• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1diff --git a/jni/Android.mk b/jni/Android.mk
2index 8b816270..d48e0d8e 100755
3--- a/jni/Android.mk
4+++ b/jni/Android.mk
5@@ -1,50 +1,53 @@
6+local_target_dir := $(TARGET_OUT_DATA)/local/tmp
7+
8 LOCAL_PATH:= $(call my-dir)
9
10 include $(CLEAR_VARS)
11
12 LOCAL_C_INCLUDES := \
13-        $(LOCAL_PATH)/feature_stab/db_vlvm \
14-        $(LOCAL_PATH)/feature_stab/src \
15-        $(LOCAL_PATH)/feature_stab/src/dbreg \
16-        $(LOCAL_PATH)/feature_mos/src \
17-        $(LOCAL_PATH)/feature_mos/src/mosaic
18-
19-LOCAL_CFLAGS := -O3 -DNDEBUG
20-LOCAL_CPPFLAGS := -std=gnu++98
21-
22-LOCAL_SRC_FILES := \
23-        feature_mos_jni.cpp \
24-        mosaic_renderer_jni.cpp \
25-        feature_mos/src/mosaic/trsMatrix.cpp \
26-        feature_mos/src/mosaic/AlignFeatures.cpp \
27-        feature_mos/src/mosaic/Blend.cpp \
28-        feature_mos/src/mosaic/Delaunay.cpp \
29-        feature_mos/src/mosaic/ImageUtils.cpp \
30-        feature_mos/src/mosaic/Mosaic.cpp \
31-        feature_mos/src/mosaic/Pyramid.cpp \
32-        feature_mos/src/mosaic_renderer/Renderer.cpp \
33-        feature_mos/src/mosaic_renderer/WarpRenderer.cpp \
34-        feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp \
35-        feature_mos/src/mosaic_renderer/YVURenderer.cpp \
36-        feature_mos/src/mosaic_renderer/FrameBuffer.cpp \
37-        feature_stab/db_vlvm/db_feature_detection.cpp \
38-        feature_stab/db_vlvm/db_feature_matching.cpp \
39-        feature_stab/db_vlvm/db_framestitching.cpp \
40-        feature_stab/db_vlvm/db_image_homography.cpp \
41-        feature_stab/db_vlvm/db_rob_image_homography.cpp \
42-        feature_stab/db_vlvm/db_utilities.cpp \
43-        feature_stab/db_vlvm/db_utilities_camera.cpp \
44-        feature_stab/db_vlvm/db_utilities_indexing.cpp \
45-        feature_stab/db_vlvm/db_utilities_linalg.cpp \
46-        feature_stab/db_vlvm/db_utilities_poly.cpp \
47-        feature_stab/src/dbreg/dbreg.cpp \
48-        feature_stab/src/dbreg/dbstabsmooth.cpp \
49-        feature_stab/src/dbreg/vp_motionmodel.c
50+    $(LOCAL_PATH)/feature_mos/src \
51+    $(LOCAL_PATH)/feature_stab/src \
52+    $(LOCAL_PATH)/feature_stab/db_vlvm
53
54-LOCAL_SHARED_LIBRARIES := liblog libnativehelper libGLESv2
55-#LOCAL_LDLIBS := -L$(SYSROOT)/usr/lib -ldl -llog -lGLESv2 -L$(TARGET_OUT)
56+LOCAL_SRC_FILES := benchmark.cpp \
57+	feature_mos/src/mosaic/ImageUtils.cpp \
58+    feature_mos/src/mosaic/Mosaic.cpp \
59+    feature_mos/src/mosaic/AlignFeatures.cpp \
60+    feature_mos/src/mosaic/Blend.cpp \
61+    feature_mos/src/mosaic/Pyramid.cpp \
62+    feature_mos/src/mosaic/trsMatrix.cpp \
63+    feature_mos/src/mosaic/Delaunay.cpp \
64+    feature_mos/src/mosaic_renderer/Renderer.cpp \
65+    feature_mos/src/mosaic_renderer/WarpRenderer.cpp \
66+    feature_mos/src/mosaic_renderer/SurfaceTextureRenderer.cpp \
67+    feature_mos/src/mosaic_renderer/YVURenderer.cpp \
68+    feature_mos/src/mosaic_renderer/FrameBuffer.cpp \
69+    feature_stab/db_vlvm/db_rob_image_homography.cpp \
70+    feature_stab/db_vlvm/db_feature_detection.cpp \
71+    feature_stab/db_vlvm/db_image_homography.cpp \
72+    feature_stab/db_vlvm/db_framestitching.cpp \
73+    feature_stab/db_vlvm/db_feature_matching.cpp \
74+    feature_stab/db_vlvm/db_utilities.cpp \
75+    feature_stab/db_vlvm/db_utilities_camera.cpp \
76+    feature_stab/db_vlvm/db_utilities_indexing.cpp \
77+    feature_stab/db_vlvm/db_utilities_linalg.cpp \
78+    feature_stab/db_vlvm/db_utilities_poly.cpp \
79+    feature_stab/src/dbreg/dbstabsmooth.cpp \
80+    feature_stab/src/dbreg/dbreg.cpp \
81+    feature_stab/src/dbreg/vp_motionmodel.c
82
83-LOCAL_MODULE_TAGS := optional
84+LOCAL_CFLAGS := -O3 -DNDEBUG -Wno-unused-parameter -Wno-maybe-uninitialized
85+LOCAL_CFLAGS += $(CFLAGS_FOR_BENCH_SUITE)
86+LOCAL_LDFLAGS := $(LDFLAGS_FOR_BENCH_SUITE)
87+LOCAL_CPPFLAGS := -std=c++98
88+LOCAL_MODULE_TAGS := tests
89+LOCAL_MODULE := panorama_bench
90+LOCAL_MODULE_STEM_32 := panorama_bench
91+LOCAL_MODULE_STEM_64 := panorama_bench64
92+LOCAL_MULTILIB := both
93+LOCAL_MODULE_PATH := $(local_target_dir)
94+LOCAL_ADDITIONAL_DEPENDENCIES := $(LOCAL_PATH)/Android.mk
95+LOCAL_FORCE_STATIC_EXECUTABLE := true
96+LOCAL_STATIC_LIBRARIES := libc libm
97
98-LOCAL_MODULE    := libjni_legacymosaic
99-include $(BUILD_SHARED_LIBRARY)
100+include $(BUILD_EXECUTABLE)
101diff --git a/jni/benchmark.cpp b/jni/benchmark.cpp
102new file mode 100755
103index 00000000..2a6440f4
104--- /dev/null
105+++ b/jni/benchmark.cpp
106@@ -0,0 +1,131 @@
107+/*
108+ * Copyright (C) 2012 The Android Open Source Project
109+ *
110+ * Licensed under the Apache License, Version 2.0 (the "License");
111+ * you may not use this file except in compliance with the License.
112+ * You may obtain a copy of the License at
113+ *
114+ *      http://www.apache.org/licenses/LICENSE-2.0
115+ *
116+ * Unless required by applicable law or agreed to in writing, software
117+ * distributed under the License is distributed on an "AS IS" BASIS,
118+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
119+ * See the License for the specific language governing permissions and
120+ * limitations under the License.
121+ */
122+
123+#include <time.h>
124+#include <sys/types.h>
125+#include <sys/stat.h>
126+#include <unistd.h>
127+
128+#include "mosaic/Mosaic.h"
129+#include "mosaic/ImageUtils.h"
130+
131+#define MAX_FRAMES 200
132+#define KERNEL_ITERATIONS 10
133+
134+const int blendingType = Blend::BLEND_TYPE_HORZ;
135+const int stripType = Blend::STRIP_TYPE_WIDE;
136+
137+ImageType yvuFrames[MAX_FRAMES];
138+
139+int loadImages(const char* basename, int &width, int &height)
140+{
141+    char filename[512];
142+    struct stat filestat;
143+    int i;
144+
145+    for (i = 0; i < MAX_FRAMES; i++) {
146+        sprintf(filename, "%s_%03d.ppm", basename, i + 1);
147+        if (stat(filename, &filestat) != 0) break;
148+        ImageType rgbFrame = ImageUtils::readBinaryPPM(filename, width, height);
149+        yvuFrames[i] = ImageUtils::allocateImage(width, height,
150+                                ImageUtils::IMAGE_TYPE_NUM_CHANNELS);
151+        ImageUtils::rgb2yvu(yvuFrames[i], rgbFrame, width, height);
152+        ImageUtils::freeImage(rgbFrame);
153+    }
154+    return i;
155+}
156+
157+int main(int argc, char **argv)
158+{
159+    struct timespec t1, t2, t3;
160+
161+    int width, height;
162+    float totalElapsedTime = 0;
163+
164+    const char *basename;
165+    const char *filename;
166+
167+    if (argc != 3) {
168+        printf("Usage: %s input_dir output_filename\n", argv[0]);
169+        return 0;
170+    } else {
171+        basename = argv[1];
172+        filename = argv[2];
173+    }
174+
175+    // Load the images outside the computational kernel
176+    int totalFrames = loadImages(basename, width, height);
177+
178+    if (totalFrames == 0) {
179+        printf("Image files not found. Make sure %s exists.\n",
180+               basename);
181+        return 1;
182+    }
183+
184+    printf("%d frames loaded\n", totalFrames);
185+
186+
187+    // Interesting stuff is here
188+    for (int iteration = 0; iteration < KERNEL_ITERATIONS; iteration++)  {
189+        Mosaic mosaic;
190+
191+        mosaic.initialize(blendingType, stripType, width, height, -1, false, 0);
192+
193+        clock_gettime(CLOCK_MONOTONIC, &t1);
194+        for (int i = 0; i < totalFrames; i++) {
195+            mosaic.addFrame(yvuFrames[i]);
196+        }
197+        clock_gettime(CLOCK_MONOTONIC, &t2);
198+
199+        float progress = 0.0;
200+        bool cancelComputation = false;
201+
202+        mosaic.createMosaic(progress, cancelComputation);
203+
204+        int mosaicWidth, mosaicHeight;
205+        ImageType resultYVU = mosaic.getMosaic(mosaicWidth, mosaicHeight);
206+
207+        ImageType imageRGB = ImageUtils::allocateImage(
208+            mosaicWidth, mosaicHeight, ImageUtils::IMAGE_TYPE_NUM_CHANNELS);
209+
210+        clock_gettime(CLOCK_MONOTONIC, &t3);
211+
212+        float elapsedTime =
213+            (t3.tv_sec - t1.tv_sec) + (t3.tv_nsec - t1.tv_nsec)/1e9;
214+        float addImageTime =
215+            (t2.tv_sec - t1.tv_sec) + (t2.tv_nsec - t1.tv_nsec)/1e9;
216+        float stitchImageTime =
217+            (t3.tv_sec - t2.tv_sec) + (t3.tv_nsec - t2.tv_nsec)/1e9;
218+
219+        totalElapsedTime += elapsedTime;
220+
221+        printf("Iteration %d: %dx%d moasic created: "
222+               "%.2f seconds (%.2f + %.2f)\n",
223+               iteration, mosaicWidth, mosaicHeight,
224+               elapsedTime, addImageTime, stitchImageTime);
225+
226+        // Write the output only once for correctness check
227+        if (iteration == 0) {
228+            ImageUtils::yvu2rgb(imageRGB, resultYVU, mosaicWidth,
229+                                mosaicHeight);
230+            ImageUtils::writeBinaryPPM(imageRGB, filename, mosaicWidth,
231+                                       mosaicHeight);
232+        }
233+    }
234+    printf("Total elapsed time: %.2f seconds\n", totalElapsedTime);
235+
236+    return 0;
237+}
238diff --git a/jni/feature_mos/src/mosaic/AlignFeatures.cpp b/jni/feature_mos/src/mosaic/AlignFeatures.cpp
239index aeabf8f9..703a5ea5 100644
240--- a/jni/feature_mos/src/mosaic/AlignFeatures.cpp
241+++ b/jni/feature_mos/src/mosaic/AlignFeatures.cpp
242@@ -30,6 +30,8 @@
243
244 #define LOG_TAG "AlignFeatures"
245
246+const double Align::DEFAULT_MAX_DISPARITY = 0.1;
247+
248 Align::Align()
249 {
250   width = height = 0;
251diff --git a/jni/feature_mos/src/mosaic/AlignFeatures.h b/jni/feature_mos/src/mosaic/AlignFeatures.h
252index 19f39051..9999f575 100644
253--- a/jni/feature_mos/src/mosaic/AlignFeatures.h
254+++ b/jni/feature_mos/src/mosaic/AlignFeatures.h
255@@ -44,7 +44,7 @@ public:
256   ///// Settings for feature-based alignment
257   // Number of features to use from corner detection
258   static const int DEFAULT_NR_CORNERS=750;
259-  static const double DEFAULT_MAX_DISPARITY=0.1;//0.4;
260+  static const double DEFAULT_MAX_DISPARITY;//0.4;
261   // Type of homography to model
262   static const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_R_T;
263 // static const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_PROJECTIVE;
264diff --git a/jni/feature_mos/src/mosaic/Blend.cpp b/jni/feature_mos/src/mosaic/Blend.cpp
265index e37755de..b6a843a2 100644
266--- a/jni/feature_mos/src/mosaic/Blend.cpp
267+++ b/jni/feature_mos/src/mosaic/Blend.cpp
268@@ -26,8 +26,8 @@
269 #include "Geometry.h"
270 #include "trsMatrix.h"
271
272-#include "Log.h"
273-#define LOG_TAG "BLEND"
274+const float Blend::LIMIT_SIZE_MULTIPLIER = 50.f * 2.0f;
275+const float Blend::LIMIT_HEIGHT_MULTIPLIER = 2.5f;
276
277 Blend::Blend()
278 {
279@@ -67,7 +67,6 @@ int Blend::initialize(int blendingType, int stripType, int frame_width, int fram
280
281     if (!m_pFrameYPyr || !m_pFrameUPyr || !m_pFrameVPyr)
282     {
283-        LOGE("Error: Could not allocate pyramids for blending");
284         return BLEND_RET_ERROR_MEMORY;
285     }
286
287@@ -122,7 +121,6 @@ int Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes,
288
289     if (numCenters == 0)
290     {
291-        LOGE("Error: No frames to blend");
292         return BLEND_RET_ERROR;
293     }
294
295@@ -228,9 +226,6 @@ int Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes,
296
297     if (xRightMost <= xLeftMost || yBottomMost <= yTopMost)
298     {
299-        LOGE("RunBlend: aborting -consistency check failed,"
300-             "(xLeftMost, xRightMost, yTopMost, yBottomMost): (%d, %d, %d, %d)",
301-             xLeftMost, xRightMost, yTopMost, yBottomMost);
302         return BLEND_RET_ERROR;
303     }
304
305@@ -241,17 +236,12 @@ int Blend::runBlend(MosaicFrame **oframes, MosaicFrame **rframes,
306     ret = MosaicSizeCheck(LIMIT_SIZE_MULTIPLIER, LIMIT_HEIGHT_MULTIPLIER);
307     if (ret != BLEND_RET_OK)
308     {
309-       LOGE("RunBlend: aborting - mosaic size check failed, "
310-            "(frame_width, frame_height) vs (mosaic_width, mosaic_height): "
311-            "(%d, %d) vs (%d, %d)", width, height, Mwidth, Mheight);
312        return ret;
313     }
314
315-    LOGI("Allocate mosaic image for blending - size: %d x %d", Mwidth, Mheight);
316     YUVinfo *imgMos = YUVinfo::allocateImage(Mwidth, Mheight);
317     if (imgMos == NULL)
318     {
319-        LOGE("RunBlend: aborting - couldn't alloc %d x %d mosaic image", Mwidth, Mheight);
320         return BLEND_RET_ERROR_MEMORY;
321     }
322
323@@ -362,7 +352,6 @@ int Blend::FillFramePyramid(MosaicFrame *mb)
324             !PyramidShort::BorderReduce(m_pFrameUPyr, m_wb.nlevsC) || !PyramidShort::BorderExpand(m_pFrameUPyr, m_wb.nlevsC, -1) ||
325             !PyramidShort::BorderReduce(m_pFrameVPyr, m_wb.nlevsC) || !PyramidShort::BorderExpand(m_pFrameVPyr, m_wb.nlevsC, -1))
326     {
327-        LOGE("Error: Could not generate Laplacian pyramids");
328         return BLEND_RET_ERROR;
329     }
330     else
331@@ -384,7 +373,6 @@ int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite,
332     m_pMosaicVPyr = PyramidShort::allocatePyramidPacked(m_wb.nlevsC,(unsigned short)rect.Width(),(unsigned short)rect.Height(),BORDER);
333     if (!m_pMosaicYPyr || !m_pMosaicUPyr || !m_pMosaicVPyr)
334     {
335-      LOGE("Error: Could not allocate pyramids for blending");
336       return BLEND_RET_ERROR_MEMORY;
337     }
338
339@@ -579,6 +567,11 @@ int Blend::DoMergeAndBlend(MosaicFrame **frames, int nsite,
340     // Blend
341     PerformFinalBlending(imgMos, cropping_rect);
342
343+    if (cropping_rect.Width() <= 0 || cropping_rect.Height() <= 0)
344+    {
345+        return BLEND_RET_ERROR;
346+    }
347+
348     if (m_pMosaicVPyr) free(m_pMosaicVPyr);
349     if (m_pMosaicUPyr) free(m_pMosaicUPyr);
350     if (m_pMosaicYPyr) free(m_pMosaicYPyr);
351@@ -632,7 +625,6 @@ int Blend::PerformFinalBlending(YUVinfo &imgMos, MosaicRect &cropping_rect)
352     if (!PyramidShort::BorderExpand(m_pMosaicYPyr, m_wb.nlevs, 1) || !PyramidShort::BorderExpand(m_pMosaicUPyr, m_wb.nlevsC, 1) ||
353         !PyramidShort::BorderExpand(m_pMosaicVPyr, m_wb.nlevsC, 1))
354     {
355-      LOGE("Error: Could not BorderExpand!");
356       return BLEND_RET_ERROR;
357     }
358
359@@ -785,18 +777,31 @@ int Blend::PerformFinalBlending(YUVinfo &imgMos, MosaicRect &cropping_rect)
360                 break;
361             }
362         }
363+
364     }
365
366+    RoundingCroppingSizeToMultipleOf8(cropping_rect);
367+
368     for(int j=0; j<imgMos.Y.height; j++)
369     {
370         delete b[j];
371     }
372
373-    delete b;
374+    delete[] b;
375
376     return BLEND_RET_OK;
377 }
378
379+void Blend::RoundingCroppingSizeToMultipleOf8(MosaicRect &rect) {
380+    int height = rect.bottom - rect.top + 1;
381+    int residue = height & 7;
382+    rect.bottom -= residue;
383+
384+    int width = rect.right - rect.left + 1;
385+    residue = width & 7;
386+    rect.right -= residue;
387+}
388+
389 void Blend::ComputeMask(CSite *csite, BlendRect &vcrect, BlendRect &brect, MosaicRect &rect, YUVinfo &imgMos, int site_idx)
390 {
391     PyramidShort *dptr = m_pMosaicYPyr;
392diff --git a/jni/feature_mos/src/mosaic/Blend.h b/jni/feature_mos/src/mosaic/Blend.h
393index 6371fdeb..175eacd4 100644
394--- a/jni/feature_mos/src/mosaic/Blend.h
395+++ b/jni/feature_mos/src/mosaic/Blend.h
396@@ -119,9 +119,10 @@ protected:
397   void CropFinalMosaic(YUVinfo &imgMos, MosaicRect &cropping_rect);
398
399 private:
400-   static const float LIMIT_SIZE_MULTIPLIER = 5.0f * 2.0f;
401-   static const float LIMIT_HEIGHT_MULTIPLIER = 2.5f;
402+   static const float LIMIT_SIZE_MULTIPLIER;
403+   static const float LIMIT_HEIGHT_MULTIPLIER;
404    int MosaicSizeCheck(float sizeMultiplier, float heightMultiplier);
405+   void RoundingCroppingSizeToMultipleOf8(MosaicRect& rect);
406 };
407
408 #endif
409diff --git a/jni/feature_mos/src/mosaic/Delaunay.cpp b/jni/feature_mos/src/mosaic/Delaunay.cpp
410index 82f5d203..0ce09fc5 100644
411--- a/jni/feature_mos/src/mosaic/Delaunay.cpp
412+++ b/jni/feature_mos/src/mosaic/Delaunay.cpp
413@@ -24,7 +24,7 @@
414
415 #define QQ 9   // Optimal value as determined by testing
416 #define DM 38  // 2^(1+DM/2) element sort capability. DM=38 for >10^6 elements
417-#define NYL (-1)
418+#define NYL -1
419 #define valid(l) ccw(orig(basel), dest(l), dest(basel))
420
421
422diff --git a/jni/feature_mos/src/mosaic/ImageUtils.cpp b/jni/feature_mos/src/mosaic/ImageUtils.cpp
423index 6d0aac0c..daa86060 100644
424--- a/jni/feature_mos/src/mosaic/ImageUtils.cpp
425+++ b/jni/feature_mos/src/mosaic/ImageUtils.cpp
426@@ -283,7 +283,7 @@ ImageType ImageUtils::readBinaryPPM(const char *filename, int &width, int &heigh
427
428   FILE *imgin = NULL;
429   int mval=0, format=0, eret;
430-  ImageType ret = IMAGE_TYPE_NOIMAGE;
431+  ImageType ret = NULL;//IMAGE_TYPE_NOIMAGE;
432
433   imgin = fopen(filename, "r");
434   if (imgin == NULL) {
435diff --git a/jni/feature_mos/src/mosaic/ImageUtils.h b/jni/feature_mos/src/mosaic/ImageUtils.h
436index 87782383..92965ca8 100644
437--- a/jni/feature_mos/src/mosaic/ImageUtils.h
438+++ b/jni/feature_mos/src/mosaic/ImageUtils.h
439@@ -47,7 +47,7 @@ public:
440   /**
441    *  Definition of an empty image.
442    */
443-  static const int IMAGE_TYPE_NOIMAGE = NULL;
444+  static const int IMAGE_TYPE_NOIMAGE = 0;
445
446   /**
447    *  Convert image from BGR (interlaced) to YVU (non-interlaced)
448diff --git a/jni/feature_mos/src/mosaic/Log.h b/jni/feature_mos/src/mosaic/Log.h
449index cf6f14b1..2adfeda9 100644
450--- a/jni/feature_mos/src/mosaic/Log.h
451+++ b/jni/feature_mos/src/mosaic/Log.h
452@@ -14,7 +14,7 @@
453  * limitations under the License.
454  */
455 #ifndef LOG_H_
456-#define LOG_H_
457+#define LOG_H_
458
459 #include <android/log.h>
460 #define LOGV(...) __android_log_print(ANDROID_LOG_SILENT, LOG_TAG, __VA_ARGS__)
461diff --git a/jni/feature_mos/src/mosaic/Mosaic.cpp b/jni/feature_mos/src/mosaic/Mosaic.cpp
462index f17c030b..4abc6f68 100644
463--- a/jni/feature_mos/src/mosaic/Mosaic.cpp
464+++ b/jni/feature_mos/src/mosaic/Mosaic.cpp
465@@ -26,9 +26,6 @@
466 #include "Mosaic.h"
467 #include "trsMatrix.h"
468
469-#include "Log.h"
470-#define LOG_TAG "MOSAIC"
471-
472 Mosaic::Mosaic()
473 {
474     initialized = false;
475@@ -47,6 +44,10 @@ Mosaic::~Mosaic()
476     delete frames;
477     delete rframes;
478
479+    for (int j = 0; j < owned_size; j++)
480+        delete owned_frames[j];
481+    delete owned_frames;
482+
483     if (aligner != NULL)
484         delete aligner;
485     if (blender != NULL)
486@@ -88,13 +89,10 @@ int Mosaic::initialize(int blendingType, int stripType, int width, int height, i
487         {
488             frames[i] = NULL;
489         }
490-
491-
492     }
493
494-    LOGV("Initialize %d %d", width, height);
495-    LOGV("Frame width %d,%d", width, height);
496-    LOGV("Max num frames %d", max_frames);
497+    owned_frames = new ImageType[max_frames];
498+    owned_size = 0;
499
500     aligner = new Align();
501     aligner->initialize(width, height,quarter_res,thresh_still);
502@@ -107,7 +105,6 @@ int Mosaic::initialize(int blendingType, int stripType, int width, int height, i
503         blender->initialize(blendingType, stripType, width, height);
504     } else {
505         blender = NULL;
506-        LOGE("Error: Unknown blending type %d",blendingType);
507         return MOSAIC_RET_ERROR;
508     }
509
510@@ -123,7 +120,15 @@ int Mosaic::addFrameRGB(ImageType imageRGB)
511     imageYVU = ImageUtils::allocateImage(this->width, this->height, ImageUtils::IMAGE_TYPE_NUM_CHANNELS);
512     ImageUtils::rgb2yvu(imageYVU, imageRGB, width, height);
513
514-    return addFrame(imageYVU);
515+    int existing_frames_size = frames_size;
516+    int ret = addFrame(imageYVU);
517+
518+    if (frames_size > existing_frames_size)
519+        owned_frames[owned_size++] = imageYVU;
520+    else
521+        ImageUtils::freeImage(imageYVU);
522+
523+    return ret;
524 }
525
526 int Mosaic::addFrame(ImageType imageYVU)
527@@ -146,8 +151,6 @@ int Mosaic::addFrame(ImageType imageYVU)
528
529         if (frames_size >= max_frames)
530         {
531-            LOGV("WARNING: More frames than preallocated, ignoring."
532-                 "Increase maximum number of frames (-f <max_frames>) to avoid this");
533             return MOSAIC_RET_ERROR;
534         }
535
536diff --git a/jni/feature_mos/src/mosaic/Mosaic.h b/jni/feature_mos/src/mosaic/Mosaic.h
537index fc6ecd90..9dea6642 100644
538--- a/jni/feature_mos/src/mosaic/Mosaic.h
539+++ b/jni/feature_mos/src/mosaic/Mosaic.h
540@@ -181,6 +181,12 @@ protected:
541   int frames_size;
542   int max_frames;
543
544+  /**
545+    * Implicitly created frames, should be freed by Mosaic.
546+    */
547+  ImageType *owned_frames;
548+  int owned_size;
549+
550   /**
551    * Initialization state.
552    */
553diff --git a/jni/feature_mos/src/mosaic/Pyramid.cpp b/jni/feature_mos/src/mosaic/Pyramid.cpp
554index 945eafba..b022d73d 100644
555--- a/jni/feature_mos/src/mosaic/Pyramid.cpp
556+++ b/jni/feature_mos/src/mosaic/Pyramid.cpp
557@@ -154,24 +154,30 @@ void PyramidShort::BorderExpandOdd(PyramidShort *in, PyramidShort *out, PyramidS
558     // Vertical Filter
559     for (j = -off; j < in->height + off; j++) {
560         int j2 = j * 2;
561-        for (i = -scr->border; i < scr->width + scr->border; i++) {
562+        int limit = scr->width + scr->border;
563+        for (i = -scr->border; i < limit; i++) {
564+            int t1 = in->ptr[j][i];
565+            int t2 = in->ptr[j+1][i];
566             scr->ptr[j2][i] = (short)
567-                ((6 * in->ptr[j][i] + (in->ptr[j-1][i] + in->ptr[j+1][i]) + 4) >> 3);
568-            scr->ptr[j2+1][i] = (short)((in->ptr[j][i] + in->ptr[j+1][i] + 1) >> 1);
569+                ((6 * t1 + (in->ptr[j-1][i] + t2) + 4) >> 3);
570+            scr->ptr[j2+1][i] = (short)((t1 + t2 + 1) >> 1);
571         }
572     }
573
574     BorderSpread(scr, 0, 0, 3, 3);
575
576     // Horizontal Filter
577-    for (i = -off; i < scr->width + off; i++) {
578-        int i2 = i * 2;
579-        for (j = -out->border; j < out->height + out->border; j++) {
580+    int limit = out->height + out->border;
581+    for (j = -out->border; j < limit; j++) {
582+        for (i = -off; i < scr->width + off; i++) {
583+            int i2 = i * 2;
584+            int t1 = scr->ptr[j][i];
585+            int t2 = scr->ptr[j][i+1];
586             out->ptr[j][i2] = (short) (out->ptr[j][i2] +
587-                    (mode * ((6 * scr->ptr[j][i] +
588-                              scr->ptr[j][i-1] + scr->ptr[j][i+1] + 4) >> 3)));
589+                    (mode * ((6 * t1 +
590+                              scr->ptr[j][i-1] + t2 + 4) >> 3)));
591             out->ptr[j][i2+1] = (short) (out->ptr[j][i2+1] +
592-                    (mode * ((scr->ptr[j][i] + scr->ptr[j][i+1] + 1) >> 1)));
593+                    (mode * ((t1 + t2 + 1) >> 1)));
594         }
595     }
596
597diff --git a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp
598index 9a07e496..a956f23b 100755
599--- a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp
600+++ b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.cpp
601@@ -55,6 +55,8 @@ bool FrameBuffer::Init(int width, int height, GLenum format) {
602                            GL_TEXTURE_2D,
603                            mTextureName,
604                            0);
605+    checkFramebufferStatus("FrameBuffer.cpp");
606+    checkGlError("framebuffertexture2d");
607
608     if (!checkGlError("texture setup")) {
609         return false;
610@@ -94,6 +96,3 @@ int FrameBuffer::GetWidth() const {
611 int FrameBuffer::GetHeight() const {
612     return mHeight;
613 }
614-
615-
616-
617diff --git a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h
618index b6a20ad1..314b1262 100755
619--- a/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h
620+++ b/jni/feature_mos/src/mosaic_renderer/FrameBuffer.h
621@@ -4,7 +4,10 @@
622 #include <GLES2/gl2.h>
623 #include <GLES2/gl2ext.h>
624
625-extern bool checkGlError(const char* op);
626+#define checkGlError(op)  checkGLErrorDetail(__FILE__, __LINE__, (op))
627+
628+extern bool checkGLErrorDetail(const char* file, int line, const char* op);
629+extern void checkFramebufferStatus(const char* name);
630
631 class FrameBuffer {
632   public:
633diff --git a/jni/feature_mos/src/mosaic_renderer/Renderer.cpp b/jni/feature_mos/src/mosaic_renderer/Renderer.cpp
634index c5c143f9..b9938eb6 100755
635--- a/jni/feature_mos/src/mosaic_renderer/Renderer.cpp
636+++ b/jni/feature_mos/src/mosaic_renderer/Renderer.cpp
637@@ -87,7 +87,7 @@ GLuint Renderer::createProgram(const char* pVertexSource, const char* pFragmentS
638         GLint linkStatus = GL_FALSE;
639         glGetProgramiv(program, GL_LINK_STATUS, &linkStatus);
640
641-        LOGI("Program Linked!");
642+        LOGI("Program Linked (%d)!", program);
643
644         if (linkStatus != GL_TRUE)
645         {
646diff --git a/jni/feature_stab/db_vlvm/db_utilities_constants.h b/jni/feature_stab/db_vlvm/db_utilities_constants.h
647index 612fc783..07565efd 100644
648--- a/jni/feature_stab/db_vlvm/db_utilities_constants.h
649+++ b/jni/feature_stab/db_vlvm/db_utilities_constants.h
650@@ -64,7 +64,7 @@
651 #define DB_DEFAULT_ABS_CORNER_THRESHOLD 50000000.0
652 #define DB_DEFAULT_REL_CORNER_THRESHOLD 0.00005
653 #define DB_DEFAULT_MAX_DISPARITY 0.1
654-#define DB_DEFAULT_NO_DISPARITY (-1.0)
655+#define DB_DEFAULT_NO_DISPARITY -1.0
656 #define DB_DEFAULT_MAX_TRACK_LENGTH 300
657
658 #define DB_DEFAULT_MAX_NR_CAMERAS 1000
659diff --git a/jni/feature_stab/src/dbreg/dbreg.cpp b/jni/feature_stab/src/dbreg/dbreg.cpp
660index dc7d58fe..da06aa2a 100644
661--- a/jni/feature_stab/src/dbreg/dbreg.cpp
662+++ b/jni/feature_stab/src/dbreg/dbreg.cpp
663@@ -485,7 +485,8 @@ int db_FrameToReferenceRegistration::AddFrame(const unsigned char * const * im,
664   if(m_do_motion_smoothing)
665     SmoothMotion();
666
667-   db_PrintDoubleMatrix(m_H_ref_to_ins,3,3);
668+   // Disable debug printing
669+   // db_PrintDoubleMatrix(m_H_ref_to_ins,3,3);
670
671   db_Copy9(H, m_H_ref_to_ins);
672
673diff --git a/jni/feature_stab/src/dbreg/dbstabsmooth.cpp b/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
674index dffff8ab..2bb5d2e5 100644
675--- a/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
676+++ b/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
677@@ -136,7 +136,7 @@ bool db_StabilizationSmoother::smoothMotionAdaptive(/*VP_BIMG *bimg,*/int hsize,
678             smoothFactor = minSmoothFactor;
679
680         // Find the amount of motion that must be compensated so that no "border" pixels are seen in the stable video
681-        for (smoothFactor = smoothFactor; smoothFactor >= minSmoothFactor; smoothFactor -= 0.01) {
682+        for (; smoothFactor >= minSmoothFactor; smoothFactor -= 0.01) {
683             // Compute the smoothed motion
684             if(!smoothMotion(inmot, &tmpMotion, smoothFactor))
685                 break;
686diff --git a/jni/feature_stab/src/dbreg/vp_motionmodel.h b/jni/feature_stab/src/dbreg/vp_motionmodel.h
687index 71a7f7e7..a63ac001 100644
688--- a/jni/feature_stab/src/dbreg/vp_motionmodel.h
689+++ b/jni/feature_stab/src/dbreg/vp_motionmodel.h
690@@ -120,7 +120,7 @@ enum VP_MOTION_MODEL {
691   VP_VFE_AFFINE=120
692 };
693
694-#define VP_REFID (-1)   /* Default ID used for reference frame */
695+#define VP_REFID -1   /* Default ID used for reference frame */
696
697 typedef struct {
698   VP_TRS par;            /* Contains the motion paramerers.
699@@ -205,16 +205,16 @@ typedef struct {
700 /* Warp a 2d point (assuming the z component is zero) */
701 #define VP_WARP_POINT_2D(inx,iny,m,outx,outy) do {\
702   VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWW(m); \
703-  (outx) = (MXX(m)*((VP_PAR)(inx))+MXY(m)*((VP_PAR)(iny))+MXW(m))/vpTmpWarpPnt___; \
704-  (outy) = (MYX(m)*((VP_PAR)(inx))+MYY(m)*((VP_PAR)(iny))+MYW(m))/vpTmpWarpPnt___; } while (0)
705+  outx = (MXX(m)*((VP_PAR)inx)+MXY(m)*((VP_PAR)iny)+MXW(m))/vpTmpWarpPnt___; \
706+  outy = (MYX(m)*((VP_PAR)inx)+MYY(m)*((VP_PAR)iny)+MYW(m))/vpTmpWarpPnt___; } while (0)
707
708 /* Warp a 3d point */
709 #define VP_WARP_POINT_3D(inx,iny,inz,m,outx,outy,outz) do {\
710-  VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWZ(m)*((VP_PAR)(inz))+MWW(m); \
711-  (outx) = (MXX(m)*((VP_PAR)(inx))+MXY(m)*((VP_PAR)(iny))+MXZ(m)*((VP_PAR)(inz))+MXW(m))/vpTmpWarpPnt___; \
712-  (outy) = (MYX(m)*((VP_PAR)(inx))+MYY(m)*((VP_PAR)(iny))+MYZ(m)*((VP_PAR)(inz))+MYW(m))/vpTmpWarpPnt___; \
713-  (outz) = MZX(m)*((VP_PAR)(inx))+MZY(m)*((VP_PAR)(iny))+MZZ(m)*((VP_PAR)(inz))+MZW(m); \
714-  if ((m).type==VP_MOTION_PROJ_3D) (outz)/=vpTmpWarpPnt___; } while (0)
715+  VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWZ(m)*((VP_PAR)inz)+MWW(m); \
716+  outx = (MXX(m)*((VP_PAR)inx)+MXY(m)*((VP_PAR)iny)+MXZ(m)*((VP_PAR)inz)+MXW(m))/vpTmpWarpPnt___; \
717+  outy = (MYX(m)*((VP_PAR)inx)+MYY(m)*((VP_PAR)iny)+MYZ(m)*((VP_PAR)inz)+MYW(m))/vpTmpWarpPnt___; \
718+  outz = MZX(m)*((VP_PAR)inx)+MZY(m)*((VP_PAR)iny)+MZZ(m)*((VP_PAR)inz)+MZW(m); \
719+  if ((m).type==VP_MOTION_PROJ_3D) outz/=vpTmpWarpPnt___; } while (0)
720
721 /* Projections of each component */
722 #define VP_PROJW_3D(m,x,y,z,f)   ( MWX(m)*(x)+MWY(m)*(y)+MWZ(m)*(z)+MWW(m) )
723@@ -224,15 +224,15 @@ typedef struct {
724
725 /* Scale Down a matrix by Sfactor */
726 #define VP_SCALEDOWN(m,Sfactor) do { \
727-  MXW(m) /= (VP_PAR)(Sfactor); MWX(m) *= (VP_PAR)(Sfactor); \
728-  MYW(m) /= (VP_PAR)(Sfactor); MWY(m) *= (VP_PAR)(Sfactor); \
729-  MZW(m) /= (VP_PAR)(Sfactor); MWZ(m) *= (VP_PAR)(Sfactor); } while (0)
730+  MXW(m) /= (VP_PAR)Sfactor; MWX(m) *= (VP_PAR)Sfactor; \
731+  MYW(m) /= (VP_PAR)Sfactor; MWY(m) *= (VP_PAR)Sfactor; \
732+  MZW(m) /= (VP_PAR)Sfactor; MWZ(m) *= (VP_PAR)Sfactor; } while (0)
733
734 /* Scale Up a matrix by Sfactor */
735 #define VP_SCALEUP(m,Sfactor) do { \
736-  MXW(m) *= (VP_PAR)(Sfactor); MWX(m) /= (VP_PAR)(Sfactor); \
737-  MYW(m) *= (VP_PAR)(Sfactor); MWY(m) /= (VP_PAR)(Sfactor); \
738-  MZW(m) *= (VP_PAR)(Sfactor); MWZ(m) /= (VP_PAR)(Sfactor); } while (0)
739+  MXW(m) *= (VP_PAR)Sfactor; MWX(m) /= (VP_PAR)Sfactor; \
740+  MYW(m) *= (VP_PAR)Sfactor; MWY(m) /= (VP_PAR)Sfactor; \
741+  MZW(m) *= (VP_PAR)Sfactor; MWZ(m) /= (VP_PAR)Sfactor; } while (0)
742
743 /* Normalize the transformation matrix so that MWW is 1 */
744 #define VP_NORMALIZE(m) if (MWW(m)!=(VP_PAR)0.0) do { \
745@@ -253,15 +253,15 @@ typedef struct {
746
747 /* w' projection given a point x,y,0,f */
748 #define VP_PROJZ(m,x,y,f) ( \
749-    MWX(m)*((VP_PAR)(x))+MWY(m)*((VP_PAR)(y))+MWW(m)*((VP_PAR)(f)))
750+    MWX(m)*((VP_PAR)x)+MWY(m)*((VP_PAR)y)+MWW(m)*((VP_PAR)f))
751
752 /* X Projection given a point x,y,0,f and w' */
753 #define VP_PROJX(m,x,y,w,f) (\
754-   (MXX(m)*((VP_PAR)(x))+MXY(m)*((VP_PAR)(y))+MXW(m)*((VP_PAR)(f)))/((VP_PAR)(w)))
755+   (MXX(m)*((VP_PAR)x)+MXY(m)*((VP_PAR)y)+MXW(m)*((VP_PAR)f))/((VP_PAR)w))
756
757 /* Y Projection given a point x,y,0,f and the w' */
758 #define VP_PROJY(m,x,y,w,f) (\
759-  (MYX(m)*((VP_PAR)(x))+MYY(m)*((VP_PAR)(y))+MYW(m)*((VP_PAR)(f)))/((VP_PAR)(w)))
760+  (MYX(m)*((VP_PAR)x)+MYY(m)*((VP_PAR)y)+MYW(m)*((VP_PAR)f))/((VP_PAR)w))
761
762 /* Set the reference id for a motion */
763 #define VP_SET_REFID(m,id) do { (m).refid=id; } while (0)
764