summaryrefslogtreecommitdiffstats
path: root/jni/feature_stab
diff options
context:
space:
mode:
authorSascha Haeberling <haeberling@google.com>2013-08-14 11:20:34 -0700
committerSascha Haeberling <haeberling@google.com>2013-08-14 11:20:34 -0700
commit8bddf8ce4f3dcbb56edb12cee7e93f3a9daa3f96 (patch)
tree3382b4b8b52be577c3d0525df0e7da8178673d1c /jni/feature_stab
parenta34e8c7d439d17355df51e5e536bdbbd1744cc74 (diff)
downloadandroid_packages_apps_Snap-8bddf8ce4f3dcbb56edb12cee7e93f3a9daa3f96.tar.gz
android_packages_apps_Snap-8bddf8ce4f3dcbb56edb12cee7e93f3a9daa3f96.tar.bz2
android_packages_apps_Snap-8bddf8ce4f3dcbb56edb12cee7e93f3a9daa3f96.zip
Copy over libjni_mosaic from Camera. We need to support the SRI pano
mode for Carlsbad. Change-Id: Id14e64d8248236e8170c12cfca2cbf2ca952e993
Diffstat (limited to 'jni/feature_stab')
-rw-r--r--jni/feature_stab/db_vlvm/db_bundle.h68
-rw-r--r--jni/feature_stab/db_vlvm/db_feature_detection.cpp1770
-rw-r--r--jni/feature_stab/db_vlvm/db_feature_detection.h179
-rw-r--r--jni/feature_stab/db_vlvm/db_feature_matching.cpp3410
-rw-r--r--jni/feature_stab/db_vlvm/db_feature_matching.h260
-rw-r--r--jni/feature_stab/db_vlvm/db_framestitching.cpp169
-rw-r--r--jni/feature_stab/db_vlvm/db_framestitching.h94
-rw-r--r--jni/feature_stab/db_vlvm/db_image_homography.cpp332
-rw-r--r--jni/feature_stab/db_vlvm/db_image_homography.h183
-rw-r--r--jni/feature_stab/db_vlvm/db_metrics.h408
-rw-r--r--jni/feature_stab/db_vlvm/db_rob_image_homography.cpp1082
-rw-r--r--jni/feature_stab/db_vlvm/db_rob_image_homography.h148
-rw-r--r--jni/feature_stab/db_vlvm/db_robust.h61
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities.cpp176
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities.h571
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_algebra.h41
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_camera.cpp50
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_camera.h332
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_constants.h208
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_geometry.h121
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_indexing.cpp120
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_indexing.h270
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_linalg.cpp376
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_linalg.h802
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_poly.cpp235
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_poly.h383
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_random.h98
-rw-r--r--jni/feature_stab/db_vlvm/db_utilities_rotation.h59
-rw-r--r--jni/feature_stab/doc/Readme.txt3
-rwxr-xr-xjni/feature_stab/doc/dbreg_API_doxyfile1557
-rw-r--r--jni/feature_stab/src/dbreg/dbreg.cpp794
-rw-r--r--jni/feature_stab/src/dbreg/dbreg.h581
-rw-r--r--jni/feature_stab/src/dbreg/dbstabsmooth.cpp330
-rw-r--r--jni/feature_stab/src/dbreg/dbstabsmooth.h157
-rw-r--r--jni/feature_stab/src/dbreg/targetver.h40
-rw-r--r--jni/feature_stab/src/dbreg/vp_motionmodel.c377
-rw-r--r--jni/feature_stab/src/dbreg/vp_motionmodel.h282
-rw-r--r--jni/feature_stab/src/dbregtest/PgmImage.cpp260
-rw-r--r--jni/feature_stab/src/dbregtest/PgmImage.h95
-rw-r--r--jni/feature_stab/src/dbregtest/dbregtest.cpp399
-rw-r--r--jni/feature_stab/src/dbregtest/stdafx.cpp24
-rw-r--r--jni/feature_stab/src/dbregtest/stdafx.h28
-rw-r--r--jni/feature_stab/src/dbregtest/targetver.h29
43 files changed, 16962 insertions, 0 deletions
diff --git a/jni/feature_stab/db_vlvm/db_bundle.h b/jni/feature_stab/db_vlvm/db_bundle.h
new file mode 100644
index 000000000..e4fb8db2c
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_bundle.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_bundle.h,v 1.2 2011/06/17 14:03:30 mbansal Exp $ */
+
+#ifndef DB_BUNDLE_H
+#define DB_BUNDLE_H
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMBundle (LM) Bundle adjustment utilities (a.k.a. Levenberg-Marquardt algorithm)
+ */
+/*\{*/
+
+#include "db_utilities.h"
+
+/*!
+Solve for update dx such that diagmult(1+lambda,transpose(J)%J)%dx= -Jtf
+using only upper half of JtJ, destroying lower half below diagonal in the process
+dimension is n and d should point to n allocated doubles of scratch memory
+*/
+inline void db_Compute_dx(double *dx,double **JtJ,double *min_Jtf,double lambda,double *d,int n)
+{
+ int i;
+ double opl;
+
+ opl=1.0+lambda;
+ for(i=0;i<n;i++) d[i]=JtJ[i][i]*opl;
+
+ db_CholeskyDecompSeparateDiagonal(JtJ,d,n);
+ db_CholeskyBacksub(dx,JtJ,d,n,min_Jtf);
+}
+
+/*!
+Solve for update dx such that diagmult(1+lambda,transpose(J)%J)%dx= -Jtf
+using only upper half of JtJ, destroying lower half below diagonal in the process
+*/
+inline void db_Compute_dx_3x3(double dx[3],double JtJ[9],const double min_Jtf[3],double lambda)
+{
+ double d[3],opl;
+
+ opl=1.0+lambda;
+ d[0]=JtJ[0]*opl;
+ d[1]=JtJ[4]*opl;
+ d[2]=JtJ[8]*opl;
+ db_CholeskyDecomp3x3SeparateDiagonal(JtJ,d);
+ db_CholeskyBacksub3x3(dx,JtJ,d,min_Jtf);
+}
+
+/*\}*/
+
+#endif /* DB_BUNDLE_H */
diff --git a/jni/feature_stab/db_vlvm/db_feature_detection.cpp b/jni/feature_stab/db_vlvm/db_feature_detection.cpp
new file mode 100644
index 000000000..28cb4a781
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_feature_detection.cpp
@@ -0,0 +1,1770 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*$Id: db_feature_detection.cpp,v 1.4 2011/06/17 14:03:30 mbansal Exp $*/
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+#include "db_utilities.h"
+#include "db_feature_detection.h"
+#ifdef _VERBOSE_
+#include <iostream>
+#endif
+#include <float.h>
+
+#define DB_SUB_PIXEL
+
+#define BORDER 10 // 5
+
+float** db_AllocStrengthImage_f(float **im,int w,int h)
+{
+ int i,n,aw;
+ long c,size;
+ float **img,*aim,*p;
+
+ /*Determine number of 124 element chunks needed*/
+ n=(db_maxi(1,w-6)+123)/124;
+ /*Determine the total allocation width aw*/
+ aw=n*124+8;
+ /*Allocate*/
+ size=aw*h+16;
+ *im=new float [size];
+ /*Clean up*/
+ p=(*im);
+ for(c=0;c<size;c++) p[c]=0.0;
+ /*Get a 16 byte aligned pointer*/
+ aim=db_AlignPointer_f(*im,16);
+ /*Allocate pointer table*/
+ img=new float* [h];
+ /*Initialize the pointer table*/
+ for(i=0;i<h;i++)
+ {
+ img[i]=aim+aw*i+1;
+ }
+
+ return(img);
+}
+
+void db_FreeStrengthImage_f(float *im,float **img,int h)
+{
+ delete [] im;
+ delete [] img;
+}
+
+/*Compute derivatives Ix,Iy for a subrow of img with upper left (i,j) and width chunk_width
+Memory references occur one pixel outside the subrow*/
+inline void db_IxIyRow_f(float *Ix,float *Iy,const float * const *img,int i,int j,int chunk_width)
+{
+ int c;
+
+ for(c=0;c<chunk_width;c++)
+ {
+ Ix[c]=img[i][j+c-1]-img[i][j+c+1];
+ Iy[c]=img[i-1][j+c]-img[i+1][j+c];
+ }
+}
+
+/*Compute derivatives Ix,Iy for a subrow of img with upper left (i,j) and width 128
+Memory references occur one pixel outside the subrow*/
+inline void db_IxIyRow_u(int *dxx,const unsigned char * const *img,int i,int j,int nc)
+{
+#ifdef DB_USE_MMX
+ const unsigned char *r1,*r2,*r3;
+
+ r1=img[i-1]+j; r2=img[i]+j; r3=img[i+1]+j;
+
+ _asm
+ {
+ mov esi,16
+ mov eax,r1
+ mov ebx,r2
+ mov ecx,r3
+ mov edx,dxx
+
+ /*Get bitmask into mm7*/
+ mov edi,7F7F7F7Fh
+ movd mm7,edi
+ punpckldq mm7,mm7
+
+loopstart:
+ /***************dx part 1-12*********************************/
+ movq mm0,[eax] /*1 Get upper*/
+ pxor mm6,mm6 /*2 Set to zero*/
+ movq mm1,[ecx] /*3 Get lower*/
+ psrlq mm0,1 /*4 Shift*/
+ psrlq mm1,1 /*5 Shift*/
+ pand mm0,mm7 /*6 And*/
+ movq mm2,[ebx-1] /*13 Get left*/
+ pand mm1,mm7 /*7 And*/
+ psubb mm0,mm1 /*8 Subtract*/
+ pxor mm5,mm5 /*14 Set to zero*/
+ movq mm1,mm0 /*9 Copy*/
+ pcmpgtb mm6,mm0 /*10 Create unpack mask*/
+ movq mm3,[ebx+1] /*15 Get right*/
+ punpcklbw mm0,mm6 /*11 Unpack low*/
+ punpckhbw mm1,mm6 /*12 Unpack high*/
+ /***************dy part 13-24*********************************/
+ movq mm4,mm0 /*25 Copy dx*/
+ psrlq mm2,1 /*16 Shift*/
+ pmullw mm0,mm0 /*26 Multiply dx*dx*/
+ psrlq mm3,1 /*17 Shift*/
+ pand mm2,mm7 /*18 And*/
+ pand mm3,mm7 /*19 And*/
+ /*Stall*/
+ psubb mm2,mm3 /*20 Subtract*/
+ /*Stall*/
+ movq mm3,mm2 /*21 Copy*/
+ pcmpgtb mm5,mm2 /*22 Create unpack mask*/
+ punpcklbw mm2,mm5 /*23 Unpack low*/
+ /*Stall*/
+ punpckhbw mm3,mm5 /*24 Unpack high*/
+ /***************dxx dxy dyy low part 25-49*********************************/
+ pmullw mm4,mm2 /*27 Multiply dx*dy*/
+ pmullw mm2,mm2 /*28 Multiply dy*dy*/
+ pxor mm6,mm6 /*29 Set to zero*/
+ movq mm5,mm0 /*30 Copy dx*dx*/
+ pcmpgtw mm6,mm0 /*31 Create unpack mask for dx*dx*/
+ punpcklwd mm0,mm6 /*32 Unpack dx*dx lows*/
+ /*Stall*/
+ punpckhwd mm5,mm6 /*33 Unpack dx*dx highs*/
+ pxor mm6,mm6 /*36 Set to zero*/
+ movq [edx],mm0 /*34 Store dx*dx lows*/
+ movq mm0,mm4 /*37 Copy dx*dy*/
+ movq [edx+8],mm5 /*35 Store dx*dx highs*/
+ pcmpgtw mm6,mm4 /*38 Create unpack mask for dx*dy*/
+ punpcklwd mm4,mm6 /*39 Unpack dx*dy lows*/
+ /*Stall*/
+ punpckhwd mm0,mm6 /*40 Unpack dx*dy highs*/
+ pxor mm6,mm6 /*43 Set to zero*/
+ movq [edx+512],mm4 /*41 Store dx*dy lows*/
+ movq mm5,mm2 /*44 Copy dy*dy*/
+ movq [edx+520],mm0 /*42 Store dx*dy highs*/
+ pcmpgtw mm6,mm2 /*45 Create unpack mask for dy*dy*/
+ punpcklwd mm2,mm6 /*46 Unpack dy*dy lows*/
+ movq mm4,mm1 /*50 Copy dx*/
+ punpckhwd mm5,mm6 /*47 Unpack dy*dy highs*/
+ pmullw mm1,mm1 /*51 Multiply dx*dx*/
+ movq [edx+1024],mm2 /*48 Store dy*dy lows*/
+ pmullw mm4,mm3 /*52 Multiply dx*dy*/
+ movq [edx+1032],mm5 /*49 Store dy*dy highs*/
+ /***************dxx dxy dyy high part 50-79*********************************/
+ pmullw mm3,mm3 /*53 Multiply dy*dy*/
+ pxor mm6,mm6 /*54 Set to zero*/
+ movq mm5,mm1 /*55 Copy dx*dx*/
+ pcmpgtw mm6,mm1 /*56 Create unpack mask for dx*dx*/
+ pxor mm2,mm2 /*61 Set to zero*/
+ punpcklwd mm1,mm6 /*57 Unpack dx*dx lows*/
+ movq mm0,mm4 /*62 Copy dx*dy*/
+ punpckhwd mm5,mm6 /*58 Unpack dx*dx highs*/
+ pcmpgtw mm2,mm4 /*63 Create unpack mask for dx*dy*/
+ movq [edx+16],mm1 /*59 Store dx*dx lows*/
+ punpcklwd mm4,mm2 /*64 Unpack dx*dy lows*/
+ movq [edx+24],mm5 /*60 Store dx*dx highs*/
+ punpckhwd mm0,mm2 /*65 Unpack dx*dy highs*/
+ movq [edx+528],mm4 /*66 Store dx*dy lows*/
+ pxor mm6,mm6 /*68 Set to zero*/
+ movq [edx+536],mm0 /*67 Store dx*dy highs*/
+ movq mm5,mm3 /*69 Copy dy*dy*/
+ pcmpgtw mm6,mm3 /*70 Create unpack mask for dy*dy*/
+ add eax,8 /*75*/
+ punpcklwd mm3,mm6 /*71 Unpack dy*dy lows*/
+ add ebx,8 /*76*/
+ punpckhwd mm5,mm6 /*72 Unpack dy*dy highs*/
+ add ecx,8 /*77*/
+ movq [edx+1040],mm3 /*73 Store dy*dy lows*/
+ /*Stall*/
+ movq [edx+1048],mm5 /*74 Store dy*dy highs*/
+ /*Stall*/
+ add edx,32 /*78*/
+ dec esi /*79*/
+ jnz loopstart
+
+ emms
+ }
+
+#else
+ int c;
+ int Ix,Iy;
+
+ for(c=0;c<nc;c++)
+ {
+ Ix=(img[i][j+c-1]-img[i][j+c+1])>>1;
+ Iy=(img[i-1][j+c]-img[i+1][j+c])>>1;
+ dxx[c]=Ix*Ix;
+ dxx[c+128]=Ix*Iy;
+ dxx[c+256]=Iy*Iy;
+ }
+#endif /*DB_USE_MMX*/
+}
+
+/*Filter vertically five rows of derivatives of length chunk_width into gxx,gxy,gyy*/
+inline void db_gxx_gxy_gyy_row_f(float *gxx,float *gxy,float *gyy,int chunk_width,
+ float *Ix0,float *Ix1,float *Ix2,float *Ix3,float *Ix4,
+ float *Iy0,float *Iy1,float *Iy2,float *Iy3,float *Iy4)
+{
+ int c;
+ float dx,dy;
+ float Ixx0,Ixy0,Iyy0,Ixx1,Ixy1,Iyy1,Ixx2,Ixy2,Iyy2,Ixx3,Ixy3,Iyy3,Ixx4,Ixy4,Iyy4;
+
+ for(c=0;c<chunk_width;c++)
+ {
+ dx=Ix0[c];
+ dy=Iy0[c];
+ Ixx0=dx*dx;
+ Ixy0=dx*dy;
+ Iyy0=dy*dy;
+
+ dx=Ix1[c];
+ dy=Iy1[c];
+ Ixx1=dx*dx;
+ Ixy1=dx*dy;
+ Iyy1=dy*dy;
+
+ dx=Ix2[c];
+ dy=Iy2[c];
+ Ixx2=dx*dx;
+ Ixy2=dx*dy;
+ Iyy2=dy*dy;
+
+ dx=Ix3[c];
+ dy=Iy3[c];
+ Ixx3=dx*dx;
+ Ixy3=dx*dy;
+ Iyy3=dy*dy;
+
+ dx=Ix4[c];
+ dy=Iy4[c];
+ Ixx4=dx*dx;
+ Ixy4=dx*dy;
+ Iyy4=dy*dy;
+
+ /*Filter vertically*/
+ gxx[c]=Ixx0+Ixx1*4.0f+Ixx2*6.0f+Ixx3*4.0f+Ixx4;
+ gxy[c]=Ixy0+Ixy1*4.0f+Ixy2*6.0f+Ixy3*4.0f+Ixy4;
+ gyy[c]=Iyy0+Iyy1*4.0f+Iyy2*6.0f+Iyy3*4.0f+Iyy4;
+ }
+}
+
+/*Filter vertically five rows of derivatives of length 128 into gxx,gxy,gyy*/
+inline void db_gxx_gxy_gyy_row_s(int *g,int *d0,int *d1,int *d2,int *d3,int *d4,int nc)
+{
+#ifdef DB_USE_MMX
+ int c;
+
+ _asm
+ {
+ mov c,64
+ mov eax,d0
+ mov ebx,d1
+ mov ecx,d2
+ mov edx,d3
+ mov edi,d4
+ mov esi,g
+
+loopstart:
+ /***************dxx part 1-14*********************************/
+ movq mm0,[eax] /*1 Get dxx0*/
+ /*Stall*/
+ movq mm1,[ebx] /*2 Get dxx1*/
+ /*Stall*/
+ movq mm2,[ecx] /*5 Get dxx2*/
+ pslld mm1,2 /*3 Shift dxx1*/
+ movq mm3,[edx] /*10 Get dxx3*/
+ paddd mm0,mm1 /*4 Accumulate dxx1*/
+ movq mm4,[eax+512] /*15 Get dxy0*/
+ pslld mm2,1 /*6 Shift dxx2 1*/
+ paddd mm0,mm2 /*7 Accumulate dxx2 1*/
+ pslld mm2,1 /*8 Shift dxx2 2*/
+ movq mm5,[ebx+512] /*16 Get dxy1*/
+ paddd mm0,mm2 /*9 Accumulate dxx2 2*/
+ pslld mm3,2 /*11 Shift dxx3*/
+ /*Stall*/
+ paddd mm0,mm3 /*12 Accumulate dxx3*/
+ pslld mm5,2 /*17 Shift dxy1*/
+ paddd mm0,[edi] /*13 Accumulate dxx4*/
+ paddd mm4,mm5 /*18 Accumulate dxy1*/
+ movq mm6,[ecx+512] /*19 Get dxy2*/
+ /*Stall*/
+ movq [esi],mm0 /*14 Store dxx sums*/
+ /***************dxy part 15-28*********************************/
+ pslld mm6,1 /*20 Shift dxy2 1*/
+ paddd mm4,mm6 /*21 Accumulate dxy2 1*/
+ pslld mm6,1 /*22 Shift dxy2 2*/
+ movq mm0,[eax+1024] /*29 Get dyy0*/
+ paddd mm4,mm6 /*23 Accumulate dxy2 2*/
+ movq mm7,[edx+512] /*24 Get dxy3*/
+ pslld mm7,2 /*25 Shift dxy3*/
+ movq mm1,[ebx+1024] /*30 Get dyy1*/
+ paddd mm4,mm7 /*26 Accumulate dxy3*/
+ paddd mm4,[edi+512] /*27 Accumulate dxy4*/
+ pslld mm1,2 /*31 Shift dyy1*/
+ movq mm2,[ecx+1024] /*33 Get dyy2*/
+ paddd mm0,mm1 /*32 Accumulate dyy1*/
+ movq [esi+512],mm4 /*28 Store dxy sums*/
+ pslld mm2,1 /*34 Shift dyy2 1*/
+ /***************dyy part 29-49*********************************/
+
+
+ movq mm3,[edx+1024] /*38 Get dyy3*/
+ paddd mm0,mm2 /*35 Accumulate dyy2 1*/
+ paddd mm0,[edi+1024] /*41 Accumulate dyy4*/
+ pslld mm2,1 /*36 Shift dyy2 2*/
+ paddd mm0,mm2 /*37 Accumulate dyy2 2*/
+ pslld mm3,2 /*39 Shift dyy3*/
+ paddd mm0,mm3 /*40 Accumulate dyy3*/
+ add eax,8 /*43*/
+ add ebx,8 /*44*/
+ add ecx,8 /*45*/
+ movq [esi+1024],mm0 /*42 Store dyy sums*/
+ /*Stall*/
+ add edx,8 /*46*/
+ add edi,8 /*47*/
+ add esi,8 /*48*/
+ dec c /*49*/
+ jnz loopstart
+
+ emms
+ }
+
+#else
+ int c,dd;
+
+ for(c=0;c<nc;c++)
+ {
+ /*Filter vertically*/
+ dd=d2[c];
+ g[c]=d0[c]+(d1[c]<<2)+(dd<<2)+(dd<<1)+(d3[c]<<2)+d4[c];
+
+ dd=d2[c+128];
+ g[c+128]=d0[c+128]+(d1[c+128]<<2)+(dd<<2)+(dd<<1)+(d3[c+128]<<2)+d4[c+128];
+
+ dd=d2[c+256];
+ g[c+256]=d0[c+256]+(d1[c+256]<<2)+(dd<<2)+(dd<<1)+(d3[c+256]<<2)+d4[c+256];
+ }
+#endif /*DB_USE_MMX*/
+}
+
+/*Filter horizontally the three rows gxx,gxy,gyy into the strength subrow starting at i,j
+and with width chunk_width. gxx,gxy and gyy are assumed to be four pixels wider than chunk_width
+and starting at (i,j-2)*/
+inline void db_HarrisStrength_row_f(float **s,float *gxx,float *gxy,float *gyy,int i,int j,int chunk_width)
+{
+ float Gxx,Gxy,Gyy,det,trc;
+ int c;
+
+ for(c=0;c<chunk_width;c++)
+ {
+ Gxx=gxx[c]+gxx[c+1]*4.0f+gxx[c+2]*6.0f+gxx[c+3]*4.0f+gxx[c+4];
+ Gxy=gxy[c]+gxy[c+1]*4.0f+gxy[c+2]*6.0f+gxy[c+3]*4.0f+gxy[c+4];
+ Gyy=gyy[c]+gyy[c+1]*4.0f+gyy[c+2]*6.0f+gyy[c+3]*4.0f+gyy[c+4];
+
+ det=Gxx*Gyy-Gxy*Gxy;
+ trc=Gxx+Gyy;
+ s[i][j+c]=det-0.06f*trc*trc;
+ }
+}
+
+/*Filter g of length 128 in place with 14641. Output is shifted two steps
+and of length 124*/
+inline void db_Filter14641_128_i(int *g,int nc)
+{
+#ifdef DB_USE_MMX
+ int mask;
+
+ mask=0xFFFFFFFF;
+ _asm
+ {
+ mov esi,31
+ mov eax,g
+
+ /*Get bitmask 00000000FFFFFFFF into mm7*/
+ movd mm7,mask
+
+ /*Warming iteration one 1-16********************/
+ movq mm6,[eax] /*1 Load new data*/
+ paddd mm0,mm6 /*2 Add 1* behind two steps*/
+ movq mm2,mm6 /*3 Start with 1* in front two steps*/
+ pslld mm6,1 /*4*/
+ paddd mm1,mm6 /*5 Add 2* same place*/
+ pslld mm6,1 /*6*/
+ paddd mm1,mm6 /*7 Add 4* same place*/
+ pshufw mm6,mm6,4Eh /*8 Swap the two double-words using bitmask 01001110=4Eh*/
+ paddd mm1,mm6 /*9 Add 4* swapped*/
+ movq mm5,mm6 /*10 Copy*/
+ pand mm6,mm7 /*11 Get low double-word only*/
+ paddd mm2,mm6 /*12 Add 4* in front one step*/
+ pxor mm6,mm5 /*13 Get high double-word only*/
+ paddd mm0,mm6 /*14 Add 4* behind one step*/
+ movq mm0,mm1 /*15 Shift along*/
+ movq mm1,mm2 /*16 Shift along*/
+ /*Warming iteration two 17-32********************/
+ movq mm4,[eax+8] /*17 Load new data*/
+ paddd mm0,mm4 /*18 Add 1* behind two steps*/
+ movq mm2,mm4 /*19 Start with 1* in front two steps*/
+ pslld mm4,1 /*20*/
+ paddd mm1,mm4 /*21 Add 2* same place*/
+ pslld mm4,1 /*22*/
+ paddd mm1,mm4 /*23 Add 4* same place*/
+ pshufw mm4,mm4,4Eh /*24 Swap the two double-words using bitmask 01001110=4Eh*/
+ paddd mm1,mm4 /*25 Add 4* swapped*/
+ movq mm3,mm4 /*26 Copy*/
+ pand mm4,mm7 /*27 Get low double-word only*/
+ paddd mm2,mm4 /*28 Add 4* in front one step*/
+ pxor mm4,mm3 /*29 Get high double-word only*/
+ paddd mm0,mm4 /*30 Add 4* behind one step*/
+ movq mm0,mm1 /*31 Shift along*/
+ movq mm1,mm2 /*32 Shift along*/
+
+ /*Loop********************/
+loopstart:
+ /*First part of loop 33-47********/
+ movq mm6,[eax+16] /*33 Load new data*/
+ /*Stall*/
+ paddd mm0,mm6 /*34 Add 1* behind two steps*/
+ movq mm2,mm6 /*35 Start with 1* in front two steps*/
+ movq mm4,[eax+24] /*48 Load new data*/
+ pslld mm6,1 /*36*/
+ paddd mm1,mm6 /*37 Add 2* same place*/
+ pslld mm6,1 /*38*/
+ paddd mm1,mm6 /*39 Add 4* same place*/
+ pshufw mm6,mm6,4Eh /*40 Swap the two double-words using bitmask 01001110=4Eh*/
+ paddd mm1,mm4 /*49 Add 1* behind two steps*/
+ movq mm5,mm6 /*41 Copy*/
+ paddd mm1,mm6 /*42 Add 4* swapped*/
+ pand mm6,mm7 /*43 Get low double-word only*/
+ paddd mm2,mm6 /*44 Add 4* in front one step*/
+ pxor mm6,mm5 /*45 Get high double-word only*/
+ paddd mm0,mm6 /*46 Add 4* behind one step*/
+ movq mm6,mm4 /*50a Copy*/
+ pslld mm4,1 /*51*/
+ /*Stall*/
+ movq [eax],mm0 /*47 Store result two steps behind*/
+ /*Second part of loop 48-66********/
+ movq mm0,mm6 /*50b Start with 1* in front two steps*/
+ paddd mm2,mm4 /*52 Add 2* same place*/
+ pslld mm4,1 /*53*/
+ paddd mm2,mm4 /*54 Add 4* same place*/
+ pshufw mm4,mm4,4Eh /*55 Swap the two double-words using bitmask 01001110=4Eh*/
+ paddd mm2,mm4 /*56 Add 4* swapped*/
+ movq mm3,mm4 /*57 Copy*/
+ pand mm4,mm7 /*58 Get low double-word only*/
+ /*Stall*/
+ paddd mm0,mm4 /*59 Add 4* in front one step*/
+ pxor mm4,mm3 /*60 Get high double-word only*/
+ paddd mm1,mm4 /*61 Add 4* behind one step*/
+ add eax,16 /*65*/
+ dec esi /*66*/
+ /*Stall*/
+ movq [eax-8],mm1 /*62 Store result two steps behind*/
+ movq mm1,mm0 /*63 Shift along*/
+ movq mm0,mm2 /*64 Shift along*/
+ jnz loopstart
+
+ emms
+ }
+
+#else
+ int c;
+
+ for(c=0;c<nc-4;c++)
+ {
+ g[c]=g[c]+(g[c+1]<<2)+(g[c+2]<<2)+(g[c+2]<<1)+(g[c+3]<<2)+g[c+4];
+ }
+#endif /*DB_USE_MMX*/
+}
+
+/*Filter horizontally the three rows gxx,gxy,gyy of length 128 into the strength subrow s
+of length 124. gxx,gxy and gyy are assumed to be starting at (i,j-2) if s[i][j] is sought.
+s should be 16 byte aligned*/
+inline void db_HarrisStrength_row_s(float *s,int *gxx,int *gxy,int *gyy,int nc)
+{
+ float k;
+
+ k=0.06f;
+
+ db_Filter14641_128_i(gxx,nc);
+ db_Filter14641_128_i(gxy,nc);
+ db_Filter14641_128_i(gyy,nc);
+
+#ifdef DB_USE_SIMD
+
+
+ _asm
+ {
+ mov esi,15
+ mov eax,gxx
+ mov ebx,gxy
+ mov ecx,gyy
+ mov edx,s
+
+ /*broadcast k to all positions of xmm7*/
+ movss xmm7,k
+ shufps xmm7,xmm7,0
+
+ /*****Warm up 1-10**************************************/
+ cvtpi2ps xmm0,[eax+8] /*1 Convert two integers into floating point of low double-word*/
+ /*Stall*/
+ cvtpi2ps xmm1,[ebx+8] /*4 Convert two integers into floating point of low double-word*/
+ movlhps xmm0,xmm0 /*2 Move them to the high double-word*/
+ cvtpi2ps xmm2,[ecx+8] /*7 Convert two integers into floating point of low double-word*/
+ movlhps xmm1,xmm1 /*5 Move them to the high double-word*/
+ cvtpi2ps xmm0,[eax] /*3 Convert two integers into floating point of low double-word*/
+ movlhps xmm2,xmm2 /*8 Move them to the high double-word*/
+ cvtpi2ps xmm1,[ebx] /*6 Convert two integers into floating point of low double-word*/
+ movaps xmm3,xmm0 /*10 Copy Cxx*/
+ cvtpi2ps xmm2,[ecx] /*9 Convert two integers into floating point of low double-word*/
+ /*Stall*/
+loopstart:
+ /*****First part of loop 11-18***********************/
+ mulps xmm0,xmm2 /*11 Multiply to get Gxx*Gyy*/
+ addps xmm2,xmm3 /*12 Add to get Gxx+Gyy*/
+ cvtpi2ps xmm4,[eax+24] /*19 Convert two integers into floating point of low double-word*/
+ mulps xmm1,xmm1 /*13 Multiply to get Gxy*Gxy*/
+ mulps xmm2,xmm2 /*14 Multiply to get (Gxx+Gyy)*(Gxx+Gyy)*/
+ movlhps xmm4,xmm4 /*20 Move them to the high double-word*/
+ cvtpi2ps xmm4,[eax+16] /*21 Convert two integers into floating point of low double-word*/
+ /*Stall*/
+ subps xmm0,xmm1 /*15 Subtract to get Gxx*Gyy-Gxy*Gxy*/
+ mulps xmm2,xmm7 /*16 Multiply to get k*(Gxx+Gyy)*(Gxx+Gyy)*/
+ cvtpi2ps xmm5,[ebx+24] /*22 Convert two integers into floating point of low double-word*/
+ /*Stall*/
+ movlhps xmm5,xmm5 /*23 Move them to the high double-word*/
+ /*Stall*/
+ cvtpi2ps xmm5,[ebx+16] /*24 Convert two integers into floating point of low double-word*/
+ subps xmm0,xmm2 /*17 Subtract to get Gxx*Gyy-Gxy*Gxy-k*(Gxx+Gyy)*(Gxx+Gyy)*/
+ cvtpi2ps xmm6,[ecx+24] /*25 Convert two integers into floating point of low double-word*/
+ /*Stall*/
+ movaps [edx],xmm0 /*18 Store*/
+ /*****Second part of loop 26-40***********************/
+ movlhps xmm6,xmm6 /*26 Move them to the high double-word*/
+ cvtpi2ps xmm6,[ecx+16] /*27 Convert two integers into floating point of low double-word*/
+ movaps xmm3,xmm4 /*28 Copy Cxx*/
+ mulps xmm4,xmm6 /*29 Multiply to get Gxx*Gyy*/
+ addps xmm6,xmm3 /*30 Add to get Gxx+Gyy*/
+ cvtpi2ps xmm0,[eax+40] /*(1 Next) Convert two integers into floating point of low double-word*/
+ mulps xmm5,xmm5 /*31 Multiply to get Gxy*Gxy*/
+ cvtpi2ps xmm1,[ebx+40] /*(4 Next) Convert two integers into floating point of low double-word*/
+ mulps xmm6,xmm6 /*32 Multiply to get (Gxx+Gyy)*(Gxx+Gyy)*/
+ cvtpi2ps xmm2,[ecx+40] /*(7 Next) Convert two integers into floating point of low double-word*/
+ movlhps xmm0,xmm0 /*(2 Next) Move them to the high double-word*/
+ subps xmm4,xmm5 /*33 Subtract to get Gxx*Gyy-Gxy*Gxy*/
+ movlhps xmm1,xmm1 /*(5 Next) Move them to the high double-word*/
+ cvtpi2ps xmm0,[eax+32] /*(3 Next)Convert two integers into floating point of low double-word*/
+ mulps xmm6,xmm7 /*34 Multiply to get k*(Gxx+Gyy)*(Gxx+Gyy)*/
+ cvtpi2ps xmm1,[ebx+32] /*(6 Next) Convert two integers into floating point of low double-word*/
+ movlhps xmm2,xmm2 /*(8 Next) Move them to the high double-word*/
+ movaps xmm3,xmm0 /*(10 Next) Copy Cxx*/
+ add eax,32 /*37*/
+ subps xmm4,xmm6 /*35 Subtract to get Gxx*Gyy-Gxy*Gxy-k*(Gxx+Gyy)*(Gxx+Gyy)*/
+ add ebx,32 /*38*/
+ cvtpi2ps xmm2,[ecx+32] /*(9 Next) Convert two integers into floating point of low double-word*/
+ /*Stall*/
+ movaps [edx+16],xmm4 /*36 Store*/
+ /*Stall*/
+ add ecx,32 /*39*/
+ add edx,32 /*40*/
+ dec esi /*41*/
+ jnz loopstart
+
+ /****Cool down***************/
+ mulps xmm0,xmm2 /*Multiply to get Gxx*Gyy*/
+ addps xmm2,xmm3 /*Add to get Gxx+Gyy*/
+ mulps xmm1,xmm1 /*Multiply to get Gxy*Gxy*/
+ mulps xmm2,xmm2 /*Multiply to get (Gxx+Gyy)*(Gxx+Gyy)*/
+ subps xmm0,xmm1 /*Subtract to get Gxx*Gyy-Gxy*Gxy*/
+ mulps xmm2,xmm7 /*Multiply to get k*(Gxx+Gyy)*(Gxx+Gyy)*/
+ subps xmm0,xmm2 /*Subtract to get Gxx*Gyy-Gxy*Gxy-k*(Gxx+Gyy)*(Gxx+Gyy)*/
+ movaps [edx],xmm0 /*Store*/
+ }
+
+#else
+ float Gxx,Gxy,Gyy,det,trc;
+ int c;
+
+ //for(c=0;c<124;c++)
+ for(c=0;c<nc-4;c++)
+ {
+ Gxx=(float)gxx[c];
+ Gxy=(float)gxy[c];
+ Gyy=(float)gyy[c];
+
+ det=Gxx*Gyy-Gxy*Gxy;
+ trc=Gxx+Gyy;
+ s[c]=det-k*trc*trc;
+ }
+#endif /*DB_USE_SIMD*/
+}
+
+/*Compute the Harris corner strength of the chunk [left,top,right,bottom] of img and
+store it into the corresponding region of s. left and top have to be at least 3 and
+right and bottom have to be at most width-4,height-4*/
+inline void db_HarrisStrengthChunk_f(float **s,const float * const *img,int left,int top,int right,int bottom,
+ /*temp should point to at least
+ 13*(right-left+5) of allocated memory*/
+ float *temp)
+{
+ float *Ix[5],*Iy[5];
+ float *gxx,*gxy,*gyy;
+ int i,chunk_width,chunk_width_p4;
+
+ chunk_width=right-left+1;
+ chunk_width_p4=chunk_width+4;
+ gxx=temp;
+ gxy=gxx+chunk_width_p4;
+ gyy=gxy+chunk_width_p4;
+ for(i=0;i<5;i++)
+ {
+ Ix[i]=gyy+chunk_width_p4+(2*i*chunk_width_p4);
+ Iy[i]=Ix[i]+chunk_width_p4;
+ }
+
+ /*Fill four rows of the wrap-around derivative buffers*/
+ for(i=top-2;i<top+2;i++) db_IxIyRow_f(Ix[i%5],Iy[i%5],img,i,left-2,chunk_width_p4);
+
+ /*For each output row*/
+ for(i=top;i<=bottom;i++)
+ {
+ /*Step the derivative buffers*/
+ db_IxIyRow_f(Ix[(i+2)%5],Iy[(i+2)%5],img,(i+2),left-2,chunk_width_p4);
+
+ /*Filter Ix2,IxIy,Iy2 vertically into gxx,gxy,gyy*/
+ db_gxx_gxy_gyy_row_f(gxx,gxy,gyy,chunk_width_p4,
+ Ix[(i-2)%5],Ix[(i-1)%5],Ix[i%5],Ix[(i+1)%5],Ix[(i+2)%5],
+ Iy[(i-2)%5],Iy[(i-1)%5],Iy[i%5],Iy[(i+1)%5],Iy[(i+2)%5]);
+
+ /*Filter gxx,gxy,gyy horizontally and compute corner response s*/
+ db_HarrisStrength_row_f(s,gxx,gxy,gyy,i,left,chunk_width);
+ }
+}
+
+/*Compute the Harris corner strength of the chunk [left,top,left+123,bottom] of img and
+store it into the corresponding region of s. left and top have to be at least 3 and
+right and bottom have to be at most width-4,height-4. The left of the region in s should
+be 16 byte aligned*/
+inline void db_HarrisStrengthChunk_u(float **s,const unsigned char * const *img,int left,int top,int bottom,
+ /*temp should point to at least
+ 18*128 of allocated memory*/
+ int *temp, int nc)
+{
+ int *Ixx[5],*Ixy[5],*Iyy[5];
+ int *gxx,*gxy,*gyy;
+ int i;
+
+ gxx=temp;
+ gxy=gxx+128;
+ gyy=gxy+128;
+ for(i=0;i<5;i++)
+ {
+ Ixx[i]=gyy+(3*i+1)*128;
+ Ixy[i]=gyy+(3*i+2)*128;
+ Iyy[i]=gyy+(3*i+3)*128;
+ }
+
+ /*Fill four rows of the wrap-around derivative buffers*/
+ for(i=top-2;i<top+2;i++) db_IxIyRow_u(Ixx[i%5],img,i,left-2,nc);
+
+ /*For each output row*/
+ for(i=top;i<=bottom;i++)
+ {
+ /*Step the derivative buffers*/
+ db_IxIyRow_u(Ixx[(i+2)%5],img,(i+2),left-2,nc);
+
+ /*Filter Ix2,IxIy,Iy2 vertically into gxx,gxy,gyy*/
+ db_gxx_gxy_gyy_row_s(gxx,Ixx[(i-2)%5],Ixx[(i-1)%5],Ixx[i%5],Ixx[(i+1)%5],Ixx[(i+2)%5],nc);
+
+ /*Filter gxx,gxy,gyy horizontally and compute corner response s*/
+ db_HarrisStrength_row_s(s[i]+left,gxx,gxy,gyy,nc);
+ }
+
+}
+
+/*Compute Harris corner strength of img. Strength is returned for the region
+with (3,3) as upper left and (w-4,h-4) as lower right, positioned in the
+same place in s. In other words,image should be at least 7 pixels wide and 7 pixels high
+for a meaningful result*/
+void db_HarrisStrength_f(float **s,const float * const *img,int w,int h,
+ /*temp should point to at least
+ 13*(chunk_width+4) of allocated memory*/
+ float *temp,
+ int chunk_width)
+{
+ int x,next_x,last,right;
+
+ last=w-4;
+ for(x=3;x<=last;x=next_x)
+ {
+ next_x=x+chunk_width;
+ right=next_x-1;
+ if(right>last) right=last;
+ /*Compute the Harris strength of a chunk*/
+ db_HarrisStrengthChunk_f(s,img,x,3,right,h-4,temp);
+ }
+}
+
+/*Compute Harris corner strength of img. Strength is returned for the region
+with (3,3) as upper left and (w-4,h-4) as lower right, positioned in the
+same place in s. In other words,image should be at least 7 pixels wide and 7 pixels high
+for a meaningful result.Moreover, the image should be overallocated by 256 bytes.
+s[i][3] should by 16 byte aligned for any i*/
+void db_HarrisStrength_u(float **s, const unsigned char * const *img,int w,int h,
+ /*temp should point to at least
+ 18*128 of allocated memory*/
+ int *temp)
+{
+ int x,next_x,last;
+ int nc;
+
+ last=w-4;
+ for(x=3;x<=last;x=next_x)
+ {
+ next_x=x+124;
+
+ // mayban: to revert to the original full chunks state, change the line below to: nc = 128;
+ nc = db_mini(128,last-x+1);
+ //nc = 128;
+
+ /*Compute the Harris strength of a chunk*/
+ db_HarrisStrengthChunk_u(s,img,x,3,h-4,temp,nc);
+ }
+}
+
+inline float db_Max_128Aligned16_f(float *v)
+{
+#ifdef DB_USE_SIMD
+ float back;
+
+ _asm
+ {
+ mov eax,v
+
+ /*Chunk1*/
+ movaps xmm0,[eax]
+ movaps xmm1,[eax+16]
+ movaps xmm2,[eax+32]
+ movaps xmm3,[eax+48]
+ movaps xmm4,[eax+64]
+ movaps xmm5,[eax+80]
+ movaps xmm6,[eax+96]
+ movaps xmm7,[eax+112]
+
+ /*Chunk2*/
+ maxps xmm0,[eax+128]
+ maxps xmm1,[eax+144]
+ maxps xmm2,[eax+160]
+ maxps xmm3,[eax+176]
+ maxps xmm4,[eax+192]
+ maxps xmm5,[eax+208]
+ maxps xmm6,[eax+224]
+ maxps xmm7,[eax+240]
+
+ /*Chunk3*/
+ maxps xmm0,[eax+256]
+ maxps xmm1,[eax+272]
+ maxps xmm2,[eax+288]
+ maxps xmm3,[eax+304]
+ maxps xmm4,[eax+320]
+ maxps xmm5,[eax+336]
+ maxps xmm6,[eax+352]
+ maxps xmm7,[eax+368]
+
+ /*Chunk4*/
+ maxps xmm0,[eax+384]
+ maxps xmm1,[eax+400]
+ maxps xmm2,[eax+416]
+ maxps xmm3,[eax+432]
+ maxps xmm4,[eax+448]
+ maxps xmm5,[eax+464]
+ maxps xmm6,[eax+480]
+ maxps xmm7,[eax+496]
+
+ /*Collect*/
+ maxps xmm0,xmm1
+ maxps xmm2,xmm3
+ maxps xmm4,xmm5
+ maxps xmm6,xmm7
+ maxps xmm0,xmm2
+ maxps xmm4,xmm6
+ maxps xmm0,xmm4
+ movhlps xmm1,xmm0
+ maxps xmm0,xmm1
+ shufps xmm1,xmm0,1
+ maxps xmm0,xmm1
+ movss back,xmm0
+ }
+
+ return(back);
+#else
+ float val,max_val;
+ float *p,*stop_p;
+ max_val=v[0];
+ for(p=v+1,stop_p=v+128;p!=stop_p;)
+ {
+ val= *p++;
+ if(val>max_val) max_val=val;
+ }
+ return(max_val);
+#endif /*DB_USE_SIMD*/
+}
+
+inline float db_Max_64Aligned16_f(float *v)
+{
+#ifdef DB_USE_SIMD
+ float back;
+
+ _asm
+ {
+ mov eax,v
+
+ /*Chunk1*/
+ movaps xmm0,[eax]
+ movaps xmm1,[eax+16]
+ movaps xmm2,[eax+32]
+ movaps xmm3,[eax+48]
+ movaps xmm4,[eax+64]
+ movaps xmm5,[eax+80]
+ movaps xmm6,[eax+96]
+ movaps xmm7,[eax+112]
+
+ /*Chunk2*/
+ maxps xmm0,[eax+128]
+ maxps xmm1,[eax+144]
+ maxps xmm2,[eax+160]
+ maxps xmm3,[eax+176]
+ maxps xmm4,[eax+192]
+ maxps xmm5,[eax+208]
+ maxps xmm6,[eax+224]
+ maxps xmm7,[eax+240]
+
+ /*Collect*/
+ maxps xmm0,xmm1
+ maxps xmm2,xmm3
+ maxps xmm4,xmm5
+ maxps xmm6,xmm7
+ maxps xmm0,xmm2
+ maxps xmm4,xmm6
+ maxps xmm0,xmm4
+ movhlps xmm1,xmm0
+ maxps xmm0,xmm1
+ shufps xmm1,xmm0,1
+ maxps xmm0,xmm1
+ movss back,xmm0
+ }
+
+ return(back);
+#else
+ float val,max_val;
+ float *p,*stop_p;
+ max_val=v[0];
+ for(p=v+1,stop_p=v+64;p!=stop_p;)
+ {
+ val= *p++;
+ if(val>max_val) max_val=val;
+ }
+ return(max_val);
+#endif /*DB_USE_SIMD*/
+}
+
+inline float db_Max_32Aligned16_f(float *v)
+{
+#ifdef DB_USE_SIMD
+ float back;
+
+ _asm
+ {
+ mov eax,v
+
+ /*Chunk1*/
+ movaps xmm0,[eax]
+ movaps xmm1,[eax+16]
+ movaps xmm2,[eax+32]
+ movaps xmm3,[eax+48]
+ movaps xmm4,[eax+64]
+ movaps xmm5,[eax+80]
+ movaps xmm6,[eax+96]
+ movaps xmm7,[eax+112]
+
+ /*Collect*/
+ maxps xmm0,xmm1
+ maxps xmm2,xmm3
+ maxps xmm4,xmm5
+ maxps xmm6,xmm7
+ maxps xmm0,xmm2
+ maxps xmm4,xmm6
+ maxps xmm0,xmm4
+ movhlps xmm1,xmm0
+ maxps xmm0,xmm1
+ shufps xmm1,xmm0,1
+ maxps xmm0,xmm1
+ movss back,xmm0
+ }
+
+ return(back);
+#else
+ float val,max_val;
+ float *p,*stop_p;
+ max_val=v[0];
+ for(p=v+1,stop_p=v+32;p!=stop_p;)
+ {
+ val= *p++;
+ if(val>max_val) max_val=val;
+ }
+ return(max_val);
+#endif /*DB_USE_SIMD*/
+}
+
+inline float db_Max_16Aligned16_f(float *v)
+{
+#ifdef DB_USE_SIMD
+ float back;
+
+ _asm
+ {
+ mov eax,v
+
+ /*Chunk1*/
+ movaps xmm0,[eax]
+ movaps xmm1,[eax+16]
+ movaps xmm2,[eax+32]
+ movaps xmm3,[eax+48]
+
+ /*Collect*/
+ maxps xmm0,xmm1
+ maxps xmm2,xmm3
+ maxps xmm0,xmm2
+ movhlps xmm1,xmm0
+ maxps xmm0,xmm1
+ shufps xmm1,xmm0,1
+ maxps xmm0,xmm1
+ movss back,xmm0
+ }
+
+ return(back);
+#else
+ float val,max_val;
+ float *p,*stop_p;
+ max_val=v[0];
+ for(p=v+1,stop_p=v+16;p!=stop_p;)
+ {
+ val= *p++;
+ if(val>max_val) max_val=val;
+ }
+ return(max_val);
+#endif /*DB_USE_SIMD*/
+}
+
+inline float db_Max_8Aligned16_f(float *v)
+{
+#ifdef DB_USE_SIMD
+ float back;
+
+ _asm
+ {
+ mov eax,v
+
+ /*Chunk1*/
+ movaps xmm0,[eax]
+ movaps xmm1,[eax+16]
+
+ /*Collect*/
+ maxps xmm0,xmm1
+ movhlps xmm1,xmm0
+ maxps xmm0,xmm1
+ shufps xmm1,xmm0,1
+ maxps xmm0,xmm1
+ movss back,xmm0
+ }
+
+ return(back);
+#else
+ float val,max_val;
+ float *p,*stop_p;
+ max_val=v[0];
+ for(p=v+1,stop_p=v+8;p!=stop_p;)
+ {
+ val= *p++;
+ if(val>max_val) max_val=val;
+ }
+ return(max_val);
+#endif /*DB_USE_SIMD*/
+}
+
+inline float db_Max_Aligned16_f(float *v,int size)
+{
+ float val,max_val;
+ float *stop_v;
+
+ max_val=v[0];
+ for(;size>=128;size-=128)
+ {
+ val=db_Max_128Aligned16_f(v);
+ v+=128;
+ if(val>max_val) max_val=val;
+ }
+ if(size&64)
+ {
+ val=db_Max_64Aligned16_f(v);
+ v+=64;
+ if(val>max_val) max_val=val;
+ }
+ if(size&32)
+ {
+ val=db_Max_32Aligned16_f(v);
+ v+=32;
+ if(val>max_val) max_val=val;
+ }
+ if(size&16)
+ {
+ val=db_Max_16Aligned16_f(v);
+ v+=16;
+ if(val>max_val) max_val=val;
+ }
+ if(size&8)
+ {
+ val=db_Max_8Aligned16_f(v);
+ v+=8;
+ if(val>max_val) max_val=val;
+ }
+ if(size&7)
+ {
+ for(stop_v=v+(size&7);v!=stop_v;)
+ {
+ val= *v++;
+ if(val>max_val) max_val=val;
+ }
+ }
+
+ return(max_val);
+}
+
+/*Find maximum value of img in the region starting at (left,top)
+and with width w and height h. img[left] should be 16 byte aligned*/
+float db_MaxImage_Aligned16_f(float **img,int left,int top,int w,int h)
+{
+ float val,max_val;
+ int i,stop_i;
+
+ if(w && h)
+ {
+ stop_i=top+h;
+ max_val=img[top][left];
+
+ for(i=top;i<stop_i;i++)
+ {
+ val=db_Max_Aligned16_f(img[i]+left,w);
+ if(val>max_val) max_val=val;
+ }
+ return(max_val);
+ }
+ return(0.0);
+}
+
+inline void db_MaxVector_128_Aligned16_f(float *m,float *v1,float *v2)
+{
+#ifdef DB_USE_SIMD
+ _asm
+ {
+ mov eax,v1
+ mov ebx,v2
+ mov ecx,m
+
+ /*Chunk1*/
+ movaps xmm0,[eax]
+ movaps xmm1,[eax+16]
+ movaps xmm2,[eax+32]
+ movaps xmm3,[eax+48]
+ movaps xmm4,[eax+64]
+ movaps xmm5,[eax+80]
+ movaps xmm6,[eax+96]
+ movaps xmm7,[eax+112]
+ maxps xmm0,[ebx]
+ maxps xmm1,[ebx+16]
+ maxps xmm2,[ebx+32]
+ maxps xmm3,[ebx+48]
+ maxps xmm4,[ebx+64]
+ maxps xmm5,[ebx+80]
+ maxps xmm6,[ebx+96]
+ maxps xmm7,[ebx+112]
+ movaps [ecx],xmm0
+ movaps [ecx+16],xmm1
+ movaps [ecx+32],xmm2
+ movaps [ecx+48],xmm3
+ movaps [ecx+64],xmm4
+ movaps [ecx+80],xmm5
+ movaps [ecx+96],xmm6
+ movaps [ecx+112],xmm7
+
+ /*Chunk2*/
+ movaps xmm0,[eax+128]
+ movaps xmm1,[eax+144]
+ movaps xmm2,[eax+160]
+ movaps xmm3,[eax+176]
+ movaps xmm4,[eax+192]
+ movaps xmm5,[eax+208]
+ movaps xmm6,[eax+224]
+ movaps xmm7,[eax+240]
+ maxps xmm0,[ebx+128]
+ maxps xmm1,[ebx+144]
+ maxps xmm2,[ebx+160]
+ maxps xmm3,[ebx+176]
+ maxps xmm4,[ebx+192]
+ maxps xmm5,[ebx+208]
+ maxps xmm6,[ebx+224]
+ maxps xmm7,[ebx+240]
+ movaps [ecx+128],xmm0
+ movaps [ecx+144],xmm1
+ movaps [ecx+160],xmm2
+ movaps [ecx+176],xmm3
+ movaps [ecx+192],xmm4
+ movaps [ecx+208],xmm5
+ movaps [ecx+224],xmm6
+ movaps [ecx+240],xmm7
+
+ /*Chunk3*/
+ movaps xmm0,[eax+256]
+ movaps xmm1,[eax+272]
+ movaps xmm2,[eax+288]
+ movaps xmm3,[eax+304]
+ movaps xmm4,[eax+320]
+ movaps xmm5,[eax+336]
+ movaps xmm6,[eax+352]
+ movaps xmm7,[eax+368]
+ maxps xmm0,[ebx+256]
+ maxps xmm1,[ebx+272]
+ maxps xmm2,[ebx+288]
+ maxps xmm3,[ebx+304]
+ maxps xmm4,[ebx+320]
+ maxps xmm5,[ebx+336]
+ maxps xmm6,[ebx+352]
+ maxps xmm7,[ebx+368]
+ movaps [ecx+256],xmm0
+ movaps [ecx+272],xmm1
+ movaps [ecx+288],xmm2
+ movaps [ecx+304],xmm3
+ movaps [ecx+320],xmm4
+ movaps [ecx+336],xmm5
+ movaps [ecx+352],xmm6
+ movaps [ecx+368],xmm7
+
+ /*Chunk4*/
+ movaps xmm0,[eax+384]
+ movaps xmm1,[eax+400]
+ movaps xmm2,[eax+416]
+ movaps xmm3,[eax+432]
+ movaps xmm4,[eax+448]
+ movaps xmm5,[eax+464]
+ movaps xmm6,[eax+480]
+ movaps xmm7,[eax+496]
+ maxps xmm0,[ebx+384]
+ maxps xmm1,[ebx+400]
+ maxps xmm2,[ebx+416]
+ maxps xmm3,[ebx+432]
+ maxps xmm4,[ebx+448]
+ maxps xmm5,[ebx+464]
+ maxps xmm6,[ebx+480]
+ maxps xmm7,[ebx+496]
+ movaps [ecx+384],xmm0
+ movaps [ecx+400],xmm1
+ movaps [ecx+416],xmm2
+ movaps [ecx+432],xmm3
+ movaps [ecx+448],xmm4
+ movaps [ecx+464],xmm5
+ movaps [ecx+480],xmm6
+ movaps [ecx+496],xmm7
+ }
+#else
+ int i;
+ float a,b;
+ for(i=0;i<128;i++)
+ {
+ a=v1[i];
+ b=v2[i];
+ if(a>=b) m[i]=a;
+ else m[i]=b;
+ }
+#endif /*DB_USE_SIMD*/
+}
+
+inline void db_MaxVector_128_SecondSourceDestAligned16_f(float *m,float *v1,float *v2)
+{
+#ifdef DB_USE_SIMD
+ _asm
+ {
+ mov eax,v1
+ mov ebx,v2
+ mov ecx,m
+
+ /*Chunk1*/
+ movups xmm0,[eax]
+ movups xmm1,[eax+16]
+ movups xmm2,[eax+32]
+ movups xmm3,[eax+48]
+ movups xmm4,[eax+64]
+ movups xmm5,[eax+80]
+ movups xmm6,[eax+96]
+ movups xmm7,[eax+112]
+ maxps xmm0,[ebx]
+ maxps xmm1,[ebx+16]
+ maxps xmm2,[ebx+32]
+ maxps xmm3,[ebx+48]
+ maxps xmm4,[ebx+64]
+ maxps xmm5,[ebx+80]
+ maxps xmm6,[ebx+96]
+ maxps xmm7,[ebx+112]
+ movaps [ecx],xmm0
+ movaps [ecx+16],xmm1
+ movaps [ecx+32],xmm2
+ movaps [ecx+48],xmm3
+ movaps [ecx+64],xmm4
+ movaps [ecx+80],xmm5
+ movaps [ecx+96],xmm6
+ movaps [ecx+112],xmm7
+
+ /*Chunk2*/
+ movups xmm0,[eax+128]
+ movups xmm1,[eax+144]
+ movups xmm2,[eax+160]
+ movups xmm3,[eax+176]
+ movups xmm4,[eax+192]
+ movups xmm5,[eax+208]
+ movups xmm6,[eax+224]
+ movups xmm7,[eax+240]
+ maxps xmm0,[ebx+128]
+ maxps xmm1,[ebx+144]
+ maxps xmm2,[ebx+160]
+ maxps xmm3,[ebx+176]
+ maxps xmm4,[ebx+192]
+ maxps xmm5,[ebx+208]
+ maxps xmm6,[ebx+224]
+ maxps xmm7,[ebx+240]
+ movaps [ecx+128],xmm0
+ movaps [ecx+144],xmm1
+ movaps [ecx+160],xmm2
+ movaps [ecx+176],xmm3
+ movaps [ecx+192],xmm4
+ movaps [ecx+208],xmm5
+ movaps [ecx+224],xmm6
+ movaps [ecx+240],xmm7
+
+ /*Chunk3*/
+ movups xmm0,[eax+256]
+ movups xmm1,[eax+272]
+ movups xmm2,[eax+288]
+ movups xmm3,[eax+304]
+ movups xmm4,[eax+320]
+ movups xmm5,[eax+336]
+ movups xmm6,[eax+352]
+ movups xmm7,[eax+368]
+ maxps xmm0,[ebx+256]
+ maxps xmm1,[ebx+272]
+ maxps xmm2,[ebx+288]
+ maxps xmm3,[ebx+304]
+ maxps xmm4,[ebx+320]
+ maxps xmm5,[ebx+336]
+ maxps xmm6,[ebx+352]
+ maxps xmm7,[ebx+368]
+ movaps [ecx+256],xmm0
+ movaps [ecx+272],xmm1
+ movaps [ecx+288],xmm2
+ movaps [ecx+304],xmm3
+ movaps [ecx+320],xmm4
+ movaps [ecx+336],xmm5
+ movaps [ecx+352],xmm6
+ movaps [ecx+368],xmm7
+
+ /*Chunk4*/
+ movups xmm0,[eax+384]
+ movups xmm1,[eax+400]
+ movups xmm2,[eax+416]
+ movups xmm3,[eax+432]
+ movups xmm4,[eax+448]
+ movups xmm5,[eax+464]
+ movups xmm6,[eax+480]
+ movups xmm7,[eax+496]
+ maxps xmm0,[ebx+384]
+ maxps xmm1,[ebx+400]
+ maxps xmm2,[ebx+416]
+ maxps xmm3,[ebx+432]
+ maxps xmm4,[ebx+448]
+ maxps xmm5,[ebx+464]
+ maxps xmm6,[ebx+480]
+ maxps xmm7,[ebx+496]
+ movaps [ecx+384],xmm0
+ movaps [ecx+400],xmm1
+ movaps [ecx+416],xmm2
+ movaps [ecx+432],xmm3
+ movaps [ecx+448],xmm4
+ movaps [ecx+464],xmm5
+ movaps [ecx+480],xmm6
+ movaps [ecx+496],xmm7
+ }
+#else
+ int i;
+ float a,b;
+ for(i=0;i<128;i++)
+ {
+ a=v1[i];
+ b=v2[i];
+ if(a>=b) m[i]=a;
+ else m[i]=b;
+ }
+#endif /*DB_USE_SIMD*/
+}
+
+/*Compute Max-suppression-filtered image for a chunk of sf starting at (left,top), of width 124 and
+stopping at bottom. The output is shifted two steps left and overwrites 128 elements for each row.
+The input s should be of width at least 128, and exist for 2 pixels outside the specified region.
+s[i][left-2] and sf[i][left-2] should be 16 byte aligned. Top must be at least 3*/
+inline void db_MaxSuppressFilterChunk_5x5_Aligned16_f(float **sf,float **s,int left,int top,int bottom,
+ /*temp should point to at least
+ 6*132 floats of 16-byte-aligned allocated memory*/
+ float *temp)
+{
+#ifdef DB_USE_SIMD
+ int i,lm2;
+ float *two[4];
+ float *four,*five;
+
+ lm2=left-2;
+
+ /*Set pointers to pre-allocated memory*/
+ four=temp;
+ five=four+132;
+ for(i=0;i<4;i++)
+ {
+ two[i]=five+(i+1)*132;
+ }
+
+ /*Set rests of four and five to zero to avoid
+ floating point exceptions*/
+ for(i=129;i<132;i++)
+ {
+ four[i]=0.0;
+ five[i]=0.0;
+ }
+
+ /*Fill three rows of the wrap-around max buffers*/
+ for(i=top-3;i<top;i++) db_MaxVector_128_Aligned16_f(two[i&3],s[i+1]+lm2,s[i+2]+lm2);
+
+ /*For each output row*/
+ for(;i<=bottom;i++)
+ {
+ /*Compute max of the lowest pair of rows in the five row window*/
+ db_MaxVector_128_Aligned16_f(two[i&3],s[i+1]+lm2,s[i+2]+lm2);
+ /*Compute max of the lowest and highest pair of rows in the five row window*/
+ db_MaxVector_128_Aligned16_f(four,two[i&3],two[(i-3)&3]);
+ /*Compute max of all rows*/
+ db_MaxVector_128_Aligned16_f(five,four,two[(i-1)&3]);
+ /*Compute max of 2x5 chunks*/
+ db_MaxVector_128_SecondSourceDestAligned16_f(five,five+1,five);
+ /*Compute max of pairs of 2x5 chunks*/
+ db_MaxVector_128_SecondSourceDestAligned16_f(five,five+3,five);
+ /*Compute max of pairs of 5x5 except middle*/
+ db_MaxVector_128_SecondSourceDestAligned16_f(sf[i]+lm2,four+2,five);
+ }
+
+#else
+ int i,j,right;
+ float sv;
+
+ right=left+128;
+ for(i=top;i<=bottom;i++) for(j=left;j<right;j++)
+ {
+ sv=s[i][j];
+
+ if( sv>s[i-2][j-2] && sv>s[i-2][j-1] && sv>s[i-2][j] && sv>s[i-2][j+1] && sv>s[i-2][j+2] &&
+ sv>s[i-1][j-2] && sv>s[i-1][j-1] && sv>s[i-1][j] && sv>s[i-1][j+1] && sv>s[i-1][j+2] &&
+ sv>s[ i][j-2] && sv>s[ i][j-1] && sv>s[ i][j+1] && sv>s[ i][j+2] &&
+ sv>s[i+1][j-2] && sv>s[i+1][j-1] && sv>s[i+1][j] && sv>s[i+1][j+1] && sv>s[i+1][j+2] &&
+ sv>s[i+2][j-2] && sv>s[i+2][j-1] && sv>s[i+2][j] && sv>s[i+2][j+1] && sv>s[i+2][j+2])
+ {
+ sf[i][j-2]=0.0;
+ }
+ else sf[i][j-2]=sv;
+ }
+#endif /*DB_USE_SIMD*/
+}
+
+/*Compute Max-suppression-filtered image for a chunk of sf starting at (left,top) and
+stopping at bottom. The output is shifted two steps left. The input s should exist for 2 pixels
+outside the specified region. s[i][left-2] and sf[i][left-2] should be 16 byte aligned.
+Top must be at least 3. Reading and writing from and to the input and output images is done
+as if the region had a width equal to a multiple of 124. If this is not the case, the images
+should be over-allocated and the input cleared for a sufficient region*/
+void db_MaxSuppressFilter_5x5_Aligned16_f(float **sf,float **s,int left,int top,int right,int bottom,
+ /*temp should point to at least
+ 6*132 floats of 16-byte-aligned allocated memory*/
+ float *temp)
+{
+ int x,next_x;
+
+ for(x=left;x<=right;x=next_x)
+ {
+ next_x=x+124;
+ db_MaxSuppressFilterChunk_5x5_Aligned16_f(sf,s,x,top,bottom,temp);
+ }
+}
+
+/*Extract corners from the chunk (left,top) to (right,bottom). Store in x_temp,y_temp and s_temp
+which should point to space of at least as many positions as there are pixels in the chunk*/
+inline int db_CornersFromChunk(float **strength,int left,int top,int right,int bottom,float threshold,double *x_temp,double *y_temp,double *s_temp)
+{
+ int i,j,nr;
+ float s;
+
+ nr=0;
+ for(i=top;i<=bottom;i++) for(j=left;j<=right;j++)
+ {
+ s=strength[i][j];
+
+ if(s>=threshold &&
+ s>strength[i-2][j-2] && s>strength[i-2][j-1] && s>strength[i-2][j] && s>strength[i-2][j+1] && s>strength[i-2][j+2] &&
+ s>strength[i-1][j-2] && s>strength[i-1][j-1] && s>strength[i-1][j] && s>strength[i-1][j+1] && s>strength[i-1][j+2] &&
+ s>strength[ i][j-2] && s>strength[ i][j-1] && s>strength[ i][j+1] && s>strength[ i][j+2] &&
+ s>strength[i+1][j-2] && s>strength[i+1][j-1] && s>strength[i+1][j] && s>strength[i+1][j+1] && s>strength[i+1][j+2] &&
+ s>strength[i+2][j-2] && s>strength[i+2][j-1] && s>strength[i+2][j] && s>strength[i+2][j+1] && s>strength[i+2][j+2])
+ {
+ x_temp[nr]=(double) j;
+ y_temp[nr]=(double) i;
+ s_temp[nr]=(double) s;
+ nr++;
+ }
+ }
+ return(nr);
+}
+
+
+//Sub-pixel accuracy using 2D quadratic interpolation.(YCJ)
+inline void db_SubPixel(float **strength, const double xd, const double yd, double &xs, double &ys)
+{
+ int x = (int) xd;
+ int y = (int) yd;
+
+ float fxx = strength[y][x-1] - strength[y][x] - strength[y][x] + strength[y][x+1];
+ float fyy = strength[y-1][x] - strength[y][x] - strength[y][x] + strength[y+1][x];
+ float fxy = (strength[y-1][x-1] - strength[y-1][x+1] - strength[y+1][x-1] + strength[y+1][x+1])/(float)4.0;
+
+ float denom = (fxx * fyy - fxy * fxy) * (float) 2.0;
+
+ xs = xd;
+ ys = yd;
+
+ if ( db_absf(denom) <= FLT_EPSILON )
+ {
+ return;
+ }
+ else
+ {
+ float fx = strength[y][x+1] - strength[y][x-1];
+ float fy = strength[y+1][x] - strength[y-1][x];
+
+ float dx = (fyy * fx - fxy * fy) / denom;
+ float dy = (fxx * fy - fxy * fx) / denom;
+
+ if ( db_absf(dx) > 1.0 || db_absf(dy) > 1.0 )
+ {
+ return;
+ }
+ else
+ {
+ xs -= dx;
+ ys -= dy;
+ }
+ }
+
+ return;
+}
+
+/*Extract corners from the image part from (left,top) to (right,bottom).
+Store in x and y, extracting at most satnr corners in each block of size (bw,bh).
+The pointer temp_d should point to at least 5*bw*bh positions.
+area_factor holds how many corners max to extract per 10000 pixels*/
+void db_ExtractCornersSaturated(float **strength,int left,int top,int right,int bottom,
+ int bw,int bh,unsigned long area_factor,
+ float threshold,double *temp_d,
+ double *x_coord,double *y_coord,int *nr_corners)
+{
+ double *x_temp,*y_temp,*s_temp,*select_temp;
+ double loc_thresh;
+ unsigned long bwbh,area,saturation;
+ int x,next_x,last_x;
+ int y,next_y,last_y;
+ int nr,nr_points,i,stop;
+
+ bwbh=bw*bh;
+ x_temp=temp_d;
+ y_temp=x_temp+bwbh;
+ s_temp=y_temp+bwbh;
+ select_temp=s_temp+bwbh;
+
+#ifdef DB_SUB_PIXEL
+ // subpixel processing may sometimes push the corner ourside the real border
+ // increasing border size:
+ left++;
+ top++;
+ bottom--;
+ right--;
+#endif /*DB_SUB_PIXEL*/
+
+ nr_points=0;
+ for(y=top;y<=bottom;y=next_y)
+ {
+ next_y=y+bh;
+ last_y=next_y-1;
+ if(last_y>bottom) last_y=bottom;
+ for(x=left;x<=right;x=next_x)
+ {
+ next_x=x+bw;
+ last_x=next_x-1;
+ if(last_x>right) last_x=right;
+
+ area=(last_x-x+1)*(last_y-y+1);
+ saturation=(area*area_factor)/10000;
+ nr=db_CornersFromChunk(strength,x,y,last_x,last_y,threshold,x_temp,y_temp,s_temp);
+ if(nr)
+ {
+ if(((unsigned long)nr)>saturation) loc_thresh=db_LeanQuickSelect(s_temp,nr,nr-saturation,select_temp);
+ else loc_thresh=threshold;
+
+ stop=nr_points+saturation;
+ for(i=0;(i<nr)&&(nr_points<stop);i++)
+ {
+ if(s_temp[i]>=loc_thresh)
+ {
+ #ifdef DB_SUB_PIXEL
+ db_SubPixel(strength, x_temp[i], y_temp[i], x_coord[nr_points], y_coord[nr_points]);
+ #else
+ x_coord[nr_points]=x_temp[i];
+ y_coord[nr_points]=y_temp[i];
+ #endif
+
+ nr_points++;
+ }
+ }
+ }
+ }
+ }
+ *nr_corners=nr_points;
+}
+
+db_CornerDetector_f::db_CornerDetector_f()
+{
+ m_w=0; m_h=0;
+}
+
+db_CornerDetector_f::~db_CornerDetector_f()
+{
+ Clean();
+}
+
+void db_CornerDetector_f::Clean()
+{
+ if(m_w!=0)
+ {
+ delete [] m_temp_f;
+ delete [] m_temp_d;
+ db_FreeStrengthImage_f(m_strength_mem,m_strength,m_h);
+ }
+ m_w=0; m_h=0;
+}
+
+unsigned long db_CornerDetector_f::Init(int im_width,int im_height,int target_nr_corners,
+ int nr_horizontal_blocks,int nr_vertical_blocks,
+ double absolute_threshold,double relative_threshold)
+{
+ int chunkwidth=208;
+ int block_width,block_height;
+ unsigned long area_factor;
+ int active_width,active_height;
+
+ active_width=db_maxi(1,im_width-10);
+ active_height=db_maxi(1,im_height-10);
+ block_width=db_maxi(1,active_width/nr_horizontal_blocks);
+ block_height=db_maxi(1,active_height/nr_vertical_blocks);
+
+ area_factor=db_minl(1000,db_maxl(1,(long)(10000.0*((double)target_nr_corners)/
+ (((double)active_width)*((double)active_height)))));
+
+ return(Start(im_width,im_height,block_width,block_height,area_factor,
+ absolute_threshold,relative_threshold,chunkwidth));
+}
+
+unsigned long db_CornerDetector_f::Start(int im_width,int im_height,
+ int block_width,int block_height,unsigned long area_factor,
+ double absolute_threshold,double relative_threshold,int chunkwidth)
+{
+ Clean();
+
+ m_w=im_width;
+ m_h=im_height;
+ m_cw=chunkwidth;
+ m_bw=block_width;
+ m_bh=block_height;
+ m_area_factor=area_factor;
+ m_r_thresh=relative_threshold;
+ m_a_thresh=absolute_threshold;
+ m_max_nr=db_maxl(1,1+(m_w*m_h*m_area_factor)/10000);
+
+ m_temp_f=new float[13*(m_cw+4)];
+ m_temp_d=new double[5*m_bw*m_bh];
+ m_strength=db_AllocStrengthImage_f(&m_strength_mem,m_w,m_h);
+
+ return(m_max_nr);
+}
+
+void db_CornerDetector_f::DetectCorners(const float * const *img,double *x_coord,double *y_coord,int *nr_corners) const
+{
+ float max_val,threshold;
+
+ db_HarrisStrength_f(m_strength,img,m_w,m_h,m_temp_f,m_cw);
+
+ if(m_r_thresh)
+ {
+ max_val=db_MaxImage_Aligned16_f(m_strength,3,3,m_w-6,m_h-6);
+ threshold= (float) db_maxd(m_a_thresh,max_val*m_r_thresh);
+ }
+ else threshold= (float) m_a_thresh;
+
+ db_ExtractCornersSaturated(m_strength,BORDER,BORDER,m_w-BORDER-1,m_h-BORDER-1,m_bw,m_bh,m_area_factor,threshold,
+ m_temp_d,x_coord,y_coord,nr_corners);
+}
+
+db_CornerDetector_u::db_CornerDetector_u()
+{
+ m_w=0; m_h=0;
+}
+
+db_CornerDetector_u::~db_CornerDetector_u()
+{
+ Clean();
+}
+
+db_CornerDetector_u::db_CornerDetector_u(const db_CornerDetector_u& cd)
+{
+ Start(cd.m_w, cd.m_h, cd.m_bw, cd.m_bh, cd.m_area_factor,
+ cd.m_a_thresh, cd.m_r_thresh);
+}
+
+db_CornerDetector_u& db_CornerDetector_u::operator=(const db_CornerDetector_u& cd)
+{
+ if ( this == &cd ) return *this;
+
+ Clean();
+
+ Start(cd.m_w, cd.m_h, cd.m_bw, cd.m_bh, cd.m_area_factor,
+ cd.m_a_thresh, cd.m_r_thresh);
+
+ return *this;
+}
+
+void db_CornerDetector_u::Clean()
+{
+ if(m_w!=0)
+ {
+ delete [] m_temp_i;
+ delete [] m_temp_d;
+ db_FreeStrengthImage_f(m_strength_mem,m_strength,m_h);
+ }
+ m_w=0; m_h=0;
+}
+
+unsigned long db_CornerDetector_u::Init(int im_width,int im_height,int target_nr_corners,
+ int nr_horizontal_blocks,int nr_vertical_blocks,
+ double absolute_threshold,double relative_threshold)
+{
+ int block_width,block_height;
+ unsigned long area_factor;
+ int active_width,active_height;
+
+ active_width=db_maxi(1,im_width-10);
+ active_height=db_maxi(1,im_height-10);
+ block_width=db_maxi(1,active_width/nr_horizontal_blocks);
+ block_height=db_maxi(1,active_height/nr_vertical_blocks);
+
+ area_factor=db_minl(1000,db_maxl(1,(long)(10000.0*((double)target_nr_corners)/
+ (((double)active_width)*((double)active_height)))));
+
+ return(Start(im_width,im_height,block_width,block_height,area_factor,
+ 16.0*absolute_threshold,relative_threshold));
+}
+
+unsigned long db_CornerDetector_u::Start(int im_width,int im_height,
+ int block_width,int block_height,unsigned long area_factor,
+ double absolute_threshold,double relative_threshold)
+{
+ Clean();
+
+ m_w=im_width;
+ m_h=im_height;
+ m_bw=block_width;
+ m_bh=block_height;
+ m_area_factor=area_factor;
+ m_r_thresh=relative_threshold;
+ m_a_thresh=absolute_threshold;
+ m_max_nr=db_maxl(1,1+(m_w*m_h*m_area_factor)/10000);
+
+ m_temp_i=new int[18*128];
+ m_temp_d=new double[5*m_bw*m_bh];
+ m_strength=db_AllocStrengthImage_f(&m_strength_mem,m_w,m_h);
+
+ return(m_max_nr);
+}
+
+void db_CornerDetector_u::DetectCorners(const unsigned char * const *img,double *x_coord,double *y_coord,int *nr_corners,
+ const unsigned char * const *msk, unsigned char fgnd) const
+{
+ float max_val,threshold;
+
+ db_HarrisStrength_u(m_strength,img,m_w,m_h,m_temp_i);
+
+
+ if(m_r_thresh)
+ {
+ max_val=db_MaxImage_Aligned16_f(m_strength,3,3,m_w-6,m_h-6);
+ threshold= (float) db_maxd(m_a_thresh,max_val*m_r_thresh);
+ }
+ else threshold= (float) m_a_thresh;
+
+ db_ExtractCornersSaturated(m_strength,BORDER,BORDER,m_w-BORDER-1,m_h-BORDER-1,m_bw,m_bh,m_area_factor,threshold,
+ m_temp_d,x_coord,y_coord,nr_corners);
+
+
+ if ( msk )
+ {
+ int nr_corners_mask=0;
+
+ for ( int i = 0; i < *nr_corners; ++i)
+ {
+ int cor_x = db_roundi(*(x_coord+i));
+ int cor_y = db_roundi(*(y_coord+i));
+ if ( msk[cor_y][cor_x] == fgnd )
+ {
+ x_coord[nr_corners_mask] = x_coord[i];
+ y_coord[nr_corners_mask] = y_coord[i];
+ nr_corners_mask++;
+ }
+ }
+ *nr_corners = nr_corners_mask;
+ }
+}
+
+void db_CornerDetector_u::ExtractCorners(float ** strength, double *x_coord, double *y_coord, int *nr_corners) {
+ if ( m_w!=0 )
+ db_ExtractCornersSaturated(strength,BORDER,BORDER,m_w-BORDER-1,m_h-BORDER-1,m_bw,m_bh,m_area_factor,float(m_a_thresh),
+ m_temp_d,x_coord,y_coord,nr_corners);
+}
+
diff --git a/jni/feature_stab/db_vlvm/db_feature_detection.h b/jni/feature_stab/db_vlvm/db_feature_detection.h
new file mode 100644
index 000000000..68ffcc9ad
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_feature_detection.h
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*$Id: db_feature_detection.h,v 1.3 2011/06/17 14:03:30 mbansal Exp $*/
+
+#ifndef DB_FEATURE_DETECTION_H
+#define DB_FEATURE_DETECTION_H
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup FeatureDetection Feature Detection
+ */
+#include "db_utilities.h"
+#include "db_utilities_constants.h"
+#include <stdlib.h> //for NULL
+
+/*!
+ * \class db_CornerDetector_f
+ * \ingroup FeatureDetection
+ * \brief Harris corner detector for float images.
+ *
+ * This class performs Harris corner extraction on *float* images managed
+ * with functions in \ref LMImageBasicUtilities.
+ */
+class DB_API db_CornerDetector_f
+{
+public:
+ db_CornerDetector_f();
+ ~db_CornerDetector_f();
+
+ /*!
+ * Set parameters and pre-allocate memory. Return an upper bound
+ * on the number of corners detected in one frame.
+ * \param im_width width
+ * \param im_height height
+ * \param target_nr_corners
+ * \param nr_horizontal_blocks
+ * \param nr_vertical_blocks
+ * \param absolute_threshold
+ * \param relative_threshold
+ */
+ unsigned long Init(int im_width,int im_height,
+ int target_nr_corners=DB_DEFAULT_TARGET_NR_CORNERS,
+ int nr_horizontal_blocks=DB_DEFAULT_NR_FEATURE_BLOCKS,
+ int nr_vertical_blocks=DB_DEFAULT_NR_FEATURE_BLOCKS,
+ double absolute_threshold=DB_DEFAULT_ABS_CORNER_THRESHOLD,
+ double relative_threshold=DB_DEFAULT_REL_CORNER_THRESHOLD);
+
+ /*!
+ * Detect the corners.
+ * x_coord and y_coord should be pre-allocated arrays of length returned by Init().
+ * \param img row array pointer
+ * \param x_coord corner locations
+ * \param y_coord corner locations
+ * \param nr_corners actual number of corners computed
+ */
+ void DetectCorners(const float * const *img,double *x_coord,double *y_coord,int *nr_corners) const;
+ void SetAbsoluteThreshold(double a_thresh) { m_a_thresh = a_thresh; };
+ void SetRelativeThreshold(double r_thresh) { m_r_thresh = r_thresh; };
+protected:
+ void Clean();
+ unsigned long Start(int im_width,int im_height,
+ int block_width,int block_height,unsigned long area_factor,
+ double absolute_threshold,double relative_threshold,int chunkwidth);
+
+ int m_w,m_h,m_cw,m_bw,m_bh;
+ /*Area factor holds the maximum number of corners to detect
+ per 10000 pixels*/
+ unsigned long m_area_factor,m_max_nr;
+ double m_a_thresh,m_r_thresh;
+ float *m_temp_f;
+ double *m_temp_d;
+ float **m_strength,*m_strength_mem;
+};
+/*!
+ * \class db_CornerDetector_u
+ * \ingroup FeatureDetection
+ * \brief Harris corner detector for byte images.
+ *
+ * This class performs Harris corner extraction on *byte* images managed
+ * with functions in \ref LMImageBasicUtilities.
+ */
+class DB_API db_CornerDetector_u
+{
+public:
+ db_CornerDetector_u();
+ virtual ~db_CornerDetector_u();
+
+ /*!
+ Copy ctor duplicates settings.
+ Memory is not copied.
+ */
+ db_CornerDetector_u(const db_CornerDetector_u& cd);
+ /*!
+ Assignment optor duplicates settings.
+ Memory not copied.
+ */
+ db_CornerDetector_u& operator=(const db_CornerDetector_u& cd);
+
+ /*!
+ * Set parameters and pre-allocate memory. Return an upper bound
+ * on the number of corners detected in one frame
+ */
+ virtual unsigned long Init(int im_width,int im_height,
+ int target_nr_corners=DB_DEFAULT_TARGET_NR_CORNERS,
+ int nr_horizontal_blocks=DB_DEFAULT_NR_FEATURE_BLOCKS,
+ int nr_vertical_blocks=DB_DEFAULT_NR_FEATURE_BLOCKS,
+ double absolute_threshold=DB_DEFAULT_ABS_CORNER_THRESHOLD,
+ double relative_threshold=DB_DEFAULT_REL_CORNER_THRESHOLD);
+
+ /*!
+ * Detect the corners.
+ * Observe that the image should be overallocated by at least 256 bytes
+ * at the end.
+ * x_coord and y_coord should be pre-allocated arrays of length returned by Init().
+ * Specifying image mask will restrict corner output to foreground regions.
+ * Foreground value can be specified using fgnd. By default any >0 mask value
+ * is considered to be foreground
+ * \param img row array pointer
+ * \param x_coord corner locations
+ * \param y_coord corner locations
+ * \param nr_corners actual number of corners computed
+ * \param msk row array pointer to mask image
+ * \param fgnd foreground value in the mask
+ */
+ virtual void DetectCorners(const unsigned char * const *img,double *x_coord,double *y_coord,int *nr_corners,
+ const unsigned char * const * msk=NULL, unsigned char fgnd=255) const;
+
+ /*!
+ Set absolute feature threshold
+ */
+ virtual void SetAbsoluteThreshold(double a_thresh) { m_a_thresh = a_thresh; };
+ /*!
+ Set relative feature threshold
+ */
+ virtual void SetRelativeThreshold(double r_thresh) { m_r_thresh = r_thresh; };
+
+ /*!
+ Extract corners from a pre-computed strength image.
+ \param strength Harris strength image
+ \param x_coord corner locations
+ \param y_coord corner locations
+ \param nr_corners actual number of corners computed
+ */
+ virtual void ExtractCorners(float ** strength, double *x_coord, double *y_coord, int *nr_corners);
+protected:
+ virtual void Clean();
+ /*The absolute threshold to this function should be 16.0 times
+ normal*/
+ unsigned long Start(int im_width,int im_height,
+ int block_width,int block_height,unsigned long area_factor,
+ double absolute_threshold,double relative_threshold);
+
+ int m_w,m_h,m_bw,m_bh;
+ /*Area factor holds the maximum number of corners to detect
+ per 10000 pixels*/
+ unsigned long m_area_factor,m_max_nr;
+ double m_a_thresh,m_r_thresh;
+ int *m_temp_i;
+ double *m_temp_d;
+ float **m_strength,*m_strength_mem;
+};
+
+#endif /*DB_FEATURE_DETECTION_H*/
diff --git a/jni/feature_stab/db_vlvm/db_feature_matching.cpp b/jni/feature_stab/db_vlvm/db_feature_matching.cpp
new file mode 100644
index 000000000..d278d0cf6
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_feature_matching.cpp
@@ -0,0 +1,3410 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*$Id: db_feature_matching.cpp,v 1.4 2011/06/17 14:03:30 mbansal Exp $*/
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+#include "db_utilities.h"
+#include "db_feature_matching.h"
+#ifdef _VERBOSE_
+#include <iostream>
+#endif
+
+
+int AffineWarpPoint_NN_LUT_x[11][11];
+int AffineWarpPoint_NN_LUT_y[11][11];
+
+float AffineWarpPoint_BL_LUT_x[11][11];
+float AffineWarpPoint_BL_LUT_y[11][11];
+
+
+inline float db_SignedSquareNormCorr7x7_u(unsigned char **f_img,unsigned char **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ unsigned char *pf,*pg;
+ float f,g,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-3;
+ xm_g=x_g-3;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=49.0f*fgsum-fsum*gsum;
+ den=(49.0f*f2sum-fsum*fsum)*(49.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+inline float db_SignedSquareNormCorr9x9_u(unsigned char **f_img,unsigned char **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ unsigned char *pf,*pg;
+ float f,g,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-4;
+ xm_g=x_g-4;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=81.0f*fgsum-fsum*gsum;
+ den=(81.0f*f2sum-fsum*fsum)*(81.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+inline float db_SignedSquareNormCorr11x11_u(unsigned char **f_img,unsigned char **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ unsigned char *pf,*pg;
+ float f,g,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-5;
+ xm_g=x_g-5;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-5]+xm_f; pg=g_img[y_g-5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+5]+xm_f; pg=g_img[y_g+5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=121.0f*fgsum-fsum*gsum;
+ den=(121.0f*f2sum-fsum*fsum)*(121.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+inline void db_SignedSquareNormCorr11x11_Pre_u(unsigned char **f_img,int x_f,int y_f,float *sum,float *recip)
+{
+ unsigned char *pf;
+ float den;
+ int f,f2sum,fsum;
+ int xm_f;
+
+ xm_f=x_f-5;
+
+ pf=f_img[y_f-5]+xm_f;
+ f= *pf++; f2sum=f*f; fsum=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+5]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ *sum= (float) fsum;
+ den=(121.0f*f2sum-fsum*fsum);
+ *recip=(float)(((den!=0.0)?1.0/den:0.0));
+}
+
+inline void db_SignedSquareNormCorr5x5_PreAlign_u(short *patch,const unsigned char * const *f_img,int x_f,int y_f,float *sum,float *recip)
+{
+ float den;
+ int f2sum,fsum;
+ int xm_f=x_f-2;
+
+#ifndef DB_USE_SSE2
+ const unsigned char *pf;
+ short f;
+
+ pf=f_img[y_f-2]+xm_f;
+ f= *pf++; f2sum=f*f; fsum=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ //int xwi;
+ //int ywi;
+ //f2sum=0;
+ //fsum=0;
+ //for (int r=-5;r<=5;r++){
+ // ywi=y_f+r;
+ // for (int c=-5;c<=5;c++){
+ // xwi=x_f+c;
+ // f=f_img[ywi][xwi];
+ // f2sum+=f*f;
+ // fsum+=f;
+ // (*patch++)=f;
+ // }
+ //}
+ (*patch++)=0; (*patch++)=0; (*patch++)=0; (*patch++)=0; (*patch++)=0;
+ (*patch++)=0; (*patch++)=0;
+#endif /* DB_USE_SSE2 */
+
+ *sum= (float) fsum;
+ den=(25.0f*f2sum-fsum*fsum);
+ *recip= (float)((den!=0.0)?1.0/den:0.0);
+}
+
+inline void db_SignedSquareNormCorr21x21_PreAlign_u(short *patch,const unsigned char * const *f_img,int x_f,int y_f,float *sum,float *recip)
+{
+ float den;
+ int f2sum,fsum;
+ int xm_f=x_f-10;
+ short f;
+
+ int xwi;
+ int ywi;
+ f2sum=0;
+ fsum=0;
+ for (int r=-10;r<=10;r++){
+ ywi=y_f+r;
+ for (int c=-10;c<=10;c++){
+ xwi=x_f+c;
+ f=f_img[ywi][xwi];
+ f2sum+=f*f;
+ fsum+=f;
+ (*patch++)=f;
+ }
+ }
+
+ for(int i=442; i<512; i++)
+ (*patch++)=0;
+
+ *sum= (float) fsum;
+ den=(441.0f*f2sum-fsum*fsum);
+ *recip= (float)((den!=0.0)?1.0/den:0.0);
+
+
+}
+
+/* Lay out the image in the patch, computing norm and
+*/
+inline void db_SignedSquareNormCorr11x11_PreAlign_u(short *patch,const unsigned char * const *f_img,int x_f,int y_f,float *sum,float *recip)
+{
+ float den;
+ int f2sum,fsum;
+ int xm_f=x_f-5;
+
+#ifndef DB_USE_SSE2
+ const unsigned char *pf;
+ short f;
+
+ pf=f_img[y_f-5]+xm_f;
+ f= *pf++; f2sum=f*f; fsum=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+5]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ //int xwi;
+ //int ywi;
+ //f2sum=0;
+ //fsum=0;
+ //for (int r=-5;r<=5;r++){
+ // ywi=y_f+r;
+ // for (int c=-5;c<=5;c++){
+ // xwi=x_f+c;
+ // f=f_img[ywi][xwi];
+ // f2sum+=f*f;
+ // fsum+=f;
+ // (*patch++)=f;
+ // }
+ //}
+
+ (*patch++)=0; (*patch++)=0; (*patch++)=0; (*patch++)=0; (*patch++)=0;
+ (*patch++)=0; (*patch++)=0;
+#else
+ const unsigned char *pf0 =f_img[y_f-5]+xm_f;
+ const unsigned char *pf1 =f_img[y_f-4]+xm_f;
+ const unsigned char *pf2 =f_img[y_f-3]+xm_f;
+ const unsigned char *pf3 =f_img[y_f-2]+xm_f;
+ const unsigned char *pf4 =f_img[y_f-1]+xm_f;
+ const unsigned char *pf5 =f_img[y_f ]+xm_f;
+ const unsigned char *pf6 =f_img[y_f+1]+xm_f;
+ const unsigned char *pf7 =f_img[y_f+2]+xm_f;
+ const unsigned char *pf8 =f_img[y_f+3]+xm_f;
+ const unsigned char *pf9 =f_img[y_f+4]+xm_f;
+ const unsigned char *pf10=f_img[y_f+5]+xm_f;
+
+ /* pixel mask */
+ const unsigned char pm[16] = {
+ 0xFF,0xFF,
+ 0xFF,0xFF,
+ 0xFF,0xFF,
+ 0,0,0,0,0,
+ 0,0,0,0,0};
+ const unsigned char * pm_p = pm;
+
+ _asm
+ {
+ mov ecx,patch /* load patch pointer */
+ mov ebx, pm_p /* load pixel mask pointer */
+ movdqu xmm1,[ebx] /* load pixel mask */
+
+ pxor xmm5,xmm5 /* set xmm5 to 0 accumulator for sum squares */
+ pxor xmm4,xmm4 /* set xmm4 to 0 accumulator for sum */
+ pxor xmm0,xmm0 /* set xmm0 to 0 */
+
+ /* row 0 */
+ mov eax,pf0 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqa [ecx+0*22],xmm7 /* move short values to patch */
+ movdqa [ecx+0*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 1 */
+ mov eax,pf1 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+1*22],xmm7 /* move short values to patch */
+ movdqu [ecx+1*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 2 */
+ mov eax,pf2 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+2*22],xmm7 /* move short values to patch */
+ movdqu [ecx+2*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 3 */
+ mov eax,pf3 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+3*22],xmm7 /* move short values to patch */
+ movdqu [ecx+3*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 4 */
+ mov eax,pf4 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+4*22],xmm7 /* move short values to patch */
+ movdqu [ecx+4*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 5 */
+ mov eax,pf5 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+5*22],xmm7 /* move short values to patch */
+ movdqu [ecx+5*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 6 */
+ mov eax,pf6 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+6*22],xmm7 /* move short values to patch */
+ movdqu [ecx+6*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 7 */
+ mov eax,pf7 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+7*22],xmm7 /* move short values to patch */
+ movdqu [ecx+7*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 8 */
+ mov eax,pf8 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqa [ecx+8*22],xmm7 /* move short values to patch */
+ movdqa [ecx+8*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 9 */
+ mov eax,pf9 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+9*22],xmm7 /* move short values to patch */
+ movdqu [ecx+9*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit uints into 16 bit uints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* row 10 */
+ mov eax,pf10 /* load image pointer */
+ movdqu xmm7,[eax] /* load 16 pixels */
+ movdqa xmm6,xmm7
+
+ punpcklbw xmm7,xmm0 /* unpack low pixels (first 8)*/
+ punpckhbw xmm6,xmm0 /* unpack high pixels (last 8)*/
+
+ pand xmm6,xmm1 /* mask out pixels 12-16 */
+
+ movdqu [ecx+10*22],xmm7 /* move short values to patch */
+ movdqu [ecx+10*22+16],xmm6 /* move short values to patch */
+
+ paddusw xmm4,xmm7 /* accumulate sums */
+ pmaddwd xmm7,xmm7 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm7 /* accumulate sum squares */
+
+ paddw xmm4,xmm6 /* accumulate sums */
+ pmaddwd xmm6,xmm6 /* multiply 16 bit ints and add into 32 bit ints */
+ paddd xmm5,xmm6 /* accumulate sum squares */
+
+ /* add up the sum squares */
+ movhlps xmm0,xmm5 /* high half to low half */
+ paddd xmm5,xmm0 /* add high to low */
+ pshuflw xmm0,xmm5, 0xE /* reshuffle */
+ paddd xmm5,xmm0 /* add remaining */
+ movd f2sum,xmm5
+
+ /* add up the sum */
+ movhlps xmm0,xmm4
+ paddw xmm4,xmm0 /* halves added */
+ pshuflw xmm0,xmm4,0xE
+ paddw xmm4,xmm0 /* quarters added */
+ pshuflw xmm0,xmm4,0x1
+ paddw xmm4,xmm0 /* eighth added */
+ movd fsum, xmm4
+
+ emms
+ }
+
+ fsum = fsum & 0xFFFF;
+
+ patch[126] = 0;
+ patch[127] = 0;
+#endif /* DB_USE_SSE2 */
+
+ *sum= (float) fsum;
+ den=(121.0f*f2sum-fsum*fsum);
+ *recip= (float)((den!=0.0)?1.0/den:0.0);
+}
+
+void AffineWarpPointOffset(float &r_w,float &c_w,double Hinv[9],int r,int c)
+{
+ r_w=(float)(Hinv[3]*c+Hinv[4]*r);
+ c_w=(float)(Hinv[0]*c+Hinv[1]*r);
+}
+
+
+
+/*!
+Prewarp the patches with given affine transform. For a given homogeneous point "x", "H*x" is
+the warped point and for any displacement "d" in the warped image resulting in point "y", the
+corresponding point in the original image is given by "Hinv*y", which can be simplified for affine H.
+If "affine" is 1, then nearest neighbor method is used, else if it is 2, then
+bilinear method is used.
+ */
+inline void db_SignedSquareNormCorr11x11_PreAlign_AffinePatchWarp_u(short *patch,const unsigned char * const *f_img,
+ int xi,int yi,float *sum,float *recip,
+ const double Hinv[9],int affine)
+{
+ float den;
+ short f;
+ int f2sum,fsum;
+
+ f2sum=0;
+ fsum=0;
+
+ if (affine==1)
+ {
+ for (int r=0;r<11;r++){
+ for (int c=0;c<11;c++){
+ f=f_img[yi+AffineWarpPoint_NN_LUT_y[r][c]][xi+AffineWarpPoint_NN_LUT_x[r][c]];
+ f2sum+=f*f;
+ fsum+=f;
+ (*patch++)=f;
+ }
+ }
+ }
+ else if (affine==2)
+ {
+ for (int r=0;r<11;r++){
+ for (int c=0;c<11;c++){
+ f=db_BilinearInterpolation(yi+AffineWarpPoint_BL_LUT_y[r][c]
+ ,xi+AffineWarpPoint_BL_LUT_x[r][c],f_img);
+ f2sum+=f*f;
+ fsum+=f;
+ (*patch++)=f;
+ }
+ }
+ }
+
+
+
+ (*patch++)=0; (*patch++)=0; (*patch++)=0; (*patch++)=0; (*patch++)=0;
+ (*patch++)=0; (*patch++)=0;
+
+ *sum= (float) fsum;
+ den=(121.0f*f2sum-fsum*fsum);
+ *recip= (float)((den!=0.0)?1.0/den:0.0);
+}
+
+
+inline float db_SignedSquareNormCorr11x11_Post_u(unsigned char **f_img,unsigned char **g_img,int x_f,int y_f,int x_g,int y_g,
+ float fsum_gsum,float f_recip_g_recip)
+{
+ unsigned char *pf,*pg;
+ int fgsum;
+ float fg_corr;
+ int xm_f,xm_g;
+
+ xm_f=x_f-5;
+ xm_g=x_g-5;
+
+ pf=f_img[y_f-5]+xm_f; pg=g_img[y_g-5]+xm_g;
+ fgsum=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+5]+xm_f; pg=g_img[y_g+5]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ fg_corr=121.0f*fgsum-fsum_gsum;
+ if(fg_corr>=0.0) return(fg_corr*fg_corr*f_recip_g_recip);
+ return(-fg_corr*fg_corr*f_recip_g_recip);
+}
+
+float db_SignedSquareNormCorr21x21Aligned_Post_s(const short *f_patch,const short *g_patch,float fsum_gsum,float f_recip_g_recip)
+{
+ float fgsum,fg_corr;
+
+ fgsum= (float) db_ScalarProduct512_s(f_patch,g_patch);
+
+ fg_corr=441.0f*fgsum-fsum_gsum;
+ if(fg_corr>=0.0) return(fg_corr*fg_corr*f_recip_g_recip);
+ return(-fg_corr*fg_corr*f_recip_g_recip);
+}
+
+
+float db_SignedSquareNormCorr11x11Aligned_Post_s(const short *f_patch,const short *g_patch,float fsum_gsum,float f_recip_g_recip)
+{
+ float fgsum,fg_corr;
+
+ fgsum= (float) db_ScalarProduct128_s(f_patch,g_patch);
+
+ fg_corr=121.0f*fgsum-fsum_gsum;
+ if(fg_corr>=0.0) return(fg_corr*fg_corr*f_recip_g_recip);
+ return(-fg_corr*fg_corr*f_recip_g_recip);
+}
+
+float db_SignedSquareNormCorr5x5Aligned_Post_s(const short *f_patch,const short *g_patch,float fsum_gsum,float f_recip_g_recip)
+{
+ float fgsum,fg_corr;
+
+ fgsum= (float) db_ScalarProduct32_s(f_patch,g_patch);
+
+ fg_corr=25.0f*fgsum-fsum_gsum;
+ if(fg_corr>=0.0) return(fg_corr*fg_corr*f_recip_g_recip);
+ return(-fg_corr*fg_corr*f_recip_g_recip);
+}
+
+
+inline float db_SignedSquareNormCorr15x15_u(unsigned char **f_img,unsigned char **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ unsigned char *pf,*pg;
+ float f,g,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-7;
+ xm_g=x_g-7;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-7]+xm_f; pg=g_img[y_g-7]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-6]+xm_f; pg=g_img[y_g-6]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-5]+xm_f; pg=g_img[y_g-5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+5]+xm_f; pg=g_img[y_g+5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+6]+xm_f; pg=g_img[y_g+6]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+7]+xm_f; pg=g_img[y_g+7]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=225.0f*fgsum-fsum*gsum;
+ den=(225.0f*f2sum-fsum*fsum)*(225.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+inline float db_SignedSquareNormCorr7x7_f(float **f_img,float **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ float f,g,*pf,*pg,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-3;
+ xm_g=x_g-3;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=49.0f*fgsum-fsum*gsum;
+ den=(49.0f*f2sum-fsum*fsum)*(49.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+inline float db_SignedSquareNormCorr9x9_f(float **f_img,float **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ float f,g,*pf,*pg,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-4;
+ xm_g=x_g-4;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=81.0f*fgsum-fsum*gsum;
+ den=(81.0f*f2sum-fsum*fsum)*(81.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+inline float db_SignedSquareNormCorr11x11_f(float **f_img,float **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ float *pf,*pg;
+ float f,g,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-5;
+ xm_g=x_g-5;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-5]+xm_f; pg=g_img[y_g-5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+5]+xm_f; pg=g_img[y_g+5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=121.0f*fgsum-fsum*gsum;
+ den=(121.0f*f2sum-fsum*fsum)*(121.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+inline void db_SignedSquareNormCorr11x11_Pre_f(float **f_img,int x_f,int y_f,float *sum,float *recip)
+{
+ float *pf,den;
+ float f,f2sum,fsum;
+ int xm_f;
+
+ xm_f=x_f-5;
+
+ pf=f_img[y_f-5]+xm_f;
+ f= *pf++; f2sum=f*f; fsum=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f-1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ pf=f_img[y_f+5]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf++; f2sum+=f*f; fsum+=f;
+ f= *pf; f2sum+=f*f; fsum+=f;
+
+ *sum=fsum;
+ den=(121.0f*f2sum-fsum*fsum);
+ *recip= (float) ((den!=0.0)?1.0/den:0.0);
+}
+
+inline void db_SignedSquareNormCorr11x11_PreAlign_f(float *patch,const float * const *f_img,int x_f,int y_f,float *sum,float *recip)
+{
+ const float *pf;
+ float den,f,f2sum,fsum;
+ int xm_f;
+
+ xm_f=x_f-5;
+
+ pf=f_img[y_f-5]+xm_f;
+ f= *pf++; f2sum=f*f; fsum=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f-1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+1]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+2]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+3]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+4]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ pf=f_img[y_f+5]+xm_f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf++; f2sum+=f*f; fsum+=f; (*patch++)=f;
+ f= *pf; f2sum+=f*f; fsum+=f; (*patch++)=f;
+
+ (*patch++)=0.0; (*patch++)=0.0; (*patch++)=0.0; (*patch++)=0.0; (*patch++)=0.0;
+ (*patch++)=0.0; (*patch++)=0.0;
+
+ *sum=fsum;
+ den=(121.0f*f2sum-fsum*fsum);
+ *recip= (float) ((den!=0.0)?1.0/den:0.0);
+}
+
+inline float db_SignedSquareNormCorr11x11_Post_f(float **f_img,float **g_img,int x_f,int y_f,int x_g,int y_g,
+ float fsum_gsum,float f_recip_g_recip)
+{
+ float *pf,*pg;
+ float fgsum,fg_corr;
+ int xm_f,xm_g;
+
+ xm_f=x_f-5;
+ xm_g=x_g-5;
+
+ pf=f_img[y_f-5]+xm_f; pg=g_img[y_g-5]+xm_g;
+ fgsum=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ pf=f_img[y_f+5]+xm_f; pg=g_img[y_g+5]+xm_g;
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++); fgsum+=(*pf++)*(*pg++);
+ fgsum+=(*pf++)*(*pg++); fgsum+=(*pf)*(*pg);
+
+ fg_corr=121.0f*fgsum-fsum_gsum;
+ if(fg_corr>=0.0) return(fg_corr*fg_corr*f_recip_g_recip);
+ return(-fg_corr*fg_corr*f_recip_g_recip);
+}
+
+inline float db_SignedSquareNormCorr11x11Aligned_Post_f(const float *f_patch,const float *g_patch,float fsum_gsum,float f_recip_g_recip)
+{
+ float fgsum,fg_corr;
+
+ fgsum=db_ScalarProduct128Aligned16_f(f_patch,g_patch);
+
+ fg_corr=121.0f*fgsum-fsum_gsum;
+ if(fg_corr>=0.0) return(fg_corr*fg_corr*f_recip_g_recip);
+ return(-fg_corr*fg_corr*f_recip_g_recip);
+}
+
+inline float db_SignedSquareNormCorr15x15_f(float **f_img,float **g_img,int x_f,int y_f,int x_g,int y_g)
+{
+ float *pf,*pg;
+ float f,g,fgsum,f2sum,g2sum,fsum,gsum,fg_corr,den;
+ int xm_f,xm_g;
+
+ xm_f=x_f-7;
+ xm_g=x_g-7;
+ fgsum=0.0; f2sum=0.0; g2sum=0.0; fsum=0.0; gsum=0.0;
+
+ pf=f_img[y_f-7]+xm_f; pg=g_img[y_g-7]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-6]+xm_f; pg=g_img[y_g-6]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-5]+xm_f; pg=g_img[y_g-5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-4]+xm_f; pg=g_img[y_g-4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-3]+xm_f; pg=g_img[y_g-3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-2]+xm_f; pg=g_img[y_g-2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f-1]+xm_f; pg=g_img[y_g-1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f]+xm_f; pg=g_img[y_g]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+1]+xm_f; pg=g_img[y_g+1]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+2]+xm_f; pg=g_img[y_g+2]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+3]+xm_f; pg=g_img[y_g+3]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+4]+xm_f; pg=g_img[y_g+4]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+5]+xm_f; pg=g_img[y_g+5]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+6]+xm_f; pg=g_img[y_g+6]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ pf=f_img[y_f+7]+xm_f; pg=g_img[y_g+7]+xm_g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf++; g= *pg++; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+ f= *pf; g= *pg; fgsum+=f*g; f2sum+=f*f; g2sum+=g*g; fsum+=f; gsum+=g;
+
+ fg_corr=225.0f*fgsum-fsum*gsum;
+ den=(225.0f*f2sum-fsum*fsum)*(225.0f*g2sum-gsum*gsum);
+ if(den!=0.0)
+ {
+ if(fg_corr>=0.0) return(fg_corr*fg_corr/den);
+ return(-fg_corr*fg_corr/den);
+ }
+ return(0.0);
+}
+
+db_Bucket_f** db_AllocBuckets_f(int nr_h,int nr_v,int bd)
+{
+ int i,j;
+ db_Bucket_f **bp,*b;
+
+ b=new db_Bucket_f [(nr_h+2)*(nr_v+2)];
+ bp=new db_Bucket_f* [(nr_v+2)];
+ bp=bp+1;
+ for(i= -1;i<=nr_v;i++)
+ {
+ bp[i]=b+1+(nr_h+2)*(i+1);
+ for(j= -1;j<=nr_h;j++)
+ {
+ bp[i][j].ptr=new db_PointInfo_f [bd];
+ }
+ }
+
+ return(bp);
+}
+
+db_Bucket_u** db_AllocBuckets_u(int nr_h,int nr_v,int bd)
+{
+ int i,j;
+ db_Bucket_u **bp,*b;
+
+ b=new db_Bucket_u [(nr_h+2)*(nr_v+2)];
+ bp=new db_Bucket_u* [(nr_v+2)];
+ bp=bp+1;
+ for(i= -1;i<=nr_v;i++)
+ {
+ bp[i]=b+1+(nr_h+2)*(i+1);
+ for(j= -1;j<=nr_h;j++)
+ {
+ bp[i][j].ptr=new db_PointInfo_u [bd];
+ }
+ }
+
+ return(bp);
+}
+
+void db_FreeBuckets_f(db_Bucket_f **bp,int nr_h,int nr_v)
+{
+ int i,j;
+
+ for(i= -1;i<=nr_v;i++) for(j= -1;j<=nr_h;j++)
+ {
+ delete [] bp[i][j].ptr;
+ }
+ delete [] (bp[-1]-1);
+ delete [] (bp-1);
+}
+
+void db_FreeBuckets_u(db_Bucket_u **bp,int nr_h,int nr_v)
+{
+ int i,j;
+
+ for(i= -1;i<=nr_v;i++) for(j= -1;j<=nr_h;j++)
+ {
+ delete [] bp[i][j].ptr;
+ }
+ delete [] (bp[-1]-1);
+ delete [] (bp-1);
+}
+
+void db_EmptyBuckets_f(db_Bucket_f **bp,int nr_h,int nr_v)
+{
+ int i,j;
+ for(i= -1;i<=nr_v;i++) for(j= -1;j<=nr_h;j++) bp[i][j].nr=0;
+}
+
+void db_EmptyBuckets_u(db_Bucket_u **bp,int nr_h,int nr_v)
+{
+ int i,j;
+ for(i= -1;i<=nr_v;i++) for(j= -1;j<=nr_h;j++) bp[i][j].nr=0;
+}
+
+float* db_FillBuckets_f(float *patch_space,const float * const *f_img,db_Bucket_f **bp,int bw,int bh,int nr_h,int nr_v,int bd,const double *x,const double *y,int nr_corners)
+{
+ int i,xi,yi,xpos,ypos,nr;
+ db_Bucket_f *br;
+ db_PointInfo_f *pir;
+
+ db_EmptyBuckets_f(bp,nr_h,nr_v);
+ for(i=0;i<nr_corners;i++)
+ {
+ xi=(int) x[i];
+ yi=(int) y[i];
+ xpos=xi/bw;
+ ypos=yi/bh;
+ if(xpos>=0 && xpos<nr_h && ypos>=0 && ypos<nr_v)
+ {
+ br=&bp[ypos][xpos];
+ nr=br->nr;
+ if(nr<bd)
+ {
+ pir=&(br->ptr[nr]);
+ pir->x=xi;
+ pir->y=yi;
+ pir->id=i;
+ pir->pir=0;
+ pir->patch=patch_space;
+ br->nr=nr+1;
+
+ db_SignedSquareNormCorr11x11_PreAlign_f(patch_space,f_img,xi,yi,&(pir->sum),&(pir->recip));
+ patch_space+=128;
+ }
+ }
+ }
+ return(patch_space);
+}
+
+short* db_FillBuckets_u(short *patch_space,const unsigned char * const *f_img,db_Bucket_u **bp,int bw,int bh,int nr_h,int nr_v,int bd,const double *x,const double *y,int nr_corners,int use_smaller_matching_window, int use_21)
+{
+ int i,xi,yi,xpos,ypos,nr;
+ db_Bucket_u *br;
+ db_PointInfo_u *pir;
+
+ db_EmptyBuckets_u(bp,nr_h,nr_v);
+ for(i=0;i<nr_corners;i++)
+ {
+ xi=(int)db_roundi(x[i]);
+ yi=(int)db_roundi(y[i]);
+ xpos=xi/bw;
+ ypos=yi/bh;
+ if(xpos>=0 && xpos<nr_h && ypos>=0 && ypos<nr_v)
+ {
+ br=&bp[ypos][xpos];
+ nr=br->nr;
+ if(nr<bd)
+ {
+ pir=&(br->ptr[nr]);
+ pir->x=xi;
+ pir->y=yi;
+ pir->id=i;
+ pir->pir=0;
+ pir->patch=patch_space;
+ br->nr=nr+1;
+
+ if(use_21)
+ {
+ db_SignedSquareNormCorr21x21_PreAlign_u(patch_space,f_img,xi,yi,&(pir->sum),&(pir->recip));
+ patch_space+=512;
+ }
+ else
+ {
+ if(!use_smaller_matching_window)
+ {
+ db_SignedSquareNormCorr11x11_PreAlign_u(patch_space,f_img,xi,yi,&(pir->sum),&(pir->recip));
+ patch_space+=128;
+ }
+ else
+ {
+ db_SignedSquareNormCorr5x5_PreAlign_u(patch_space,f_img,xi,yi,&(pir->sum),&(pir->recip));
+ patch_space+=32;
+ }
+ }
+ }
+ }
+ }
+ return(patch_space);
+}
+
+
+
+float* db_FillBucketsPrewarped_f(float *patch_space,const float *const *f_img,db_Bucket_f **bp,int bw,int bh,int nr_h,int nr_v,int bd,const double *x,const double *y,int nr_corners,const double H[9])
+{
+ int i,xi,yi,xpos,ypos,nr,wxi,wyi;
+ db_Bucket_f *br;
+ db_PointInfo_f *pir;
+ double xd[2],wx[2];
+
+ db_EmptyBuckets_f(bp,nr_h,nr_v);
+ for(i=0;i<nr_corners;i++)
+ {
+ xd[0]=x[i];
+ xd[1]=y[i];
+ xi=(int) xd[0];
+ yi=(int) xd[1];
+ db_ImageHomographyInhomogenous(wx,H,xd);
+ wxi=(int) wx[0];
+ wyi=(int) wx[1];
+
+ xpos=((wxi+bw)/bw)-1;
+ ypos=((wyi+bh)/bh)-1;
+ if(xpos>= -1 && xpos<=nr_h && ypos>= -1 && ypos<=nr_v)
+ {
+ br=&bp[ypos][xpos];
+ nr=br->nr;
+ if(nr<bd)
+ {
+ pir=&(br->ptr[nr]);
+ pir->x=wxi;
+ pir->y=wyi;
+ pir->id=i;
+ pir->pir=0;
+ pir->patch=patch_space;
+ br->nr=nr+1;
+
+ db_SignedSquareNormCorr11x11_PreAlign_f(patch_space,f_img,xi,yi,&(pir->sum),&(pir->recip));
+ patch_space+=128;
+ }
+ }
+ }
+ return(patch_space);
+}
+
+short* db_FillBucketsPrewarped_u(short *patch_space,const unsigned char * const *f_img,db_Bucket_u **bp,
+ int bw,int bh,int nr_h,int nr_v,int bd,const double *x,const double *y,
+ int nr_corners,const double H[9])
+{
+ int i,xi,yi,xpos,ypos,nr,wxi,wyi;
+ db_Bucket_u *br;
+ db_PointInfo_u *pir;
+ double xd[2],wx[2];
+
+ db_EmptyBuckets_u(bp,nr_h,nr_v);
+ for(i=0;i<nr_corners;i++)
+ {
+ xd[0]=x[i];
+ xd[1]=y[i];
+ xi=(int) db_roundi(xd[0]);
+ yi=(int) db_roundi(xd[1]);
+ db_ImageHomographyInhomogenous(wx,H,xd);
+ wxi=(int) wx[0];
+ wyi=(int) wx[1];
+
+ xpos=((wxi+bw)/bw)-1;
+ ypos=((wyi+bh)/bh)-1;
+ if(xpos>= -1 && xpos<=nr_h && ypos>= -1 && ypos<=nr_v)
+ {
+ br=&bp[ypos][xpos];
+ nr=br->nr;
+ if(nr<bd)
+ {
+ pir=&(br->ptr[nr]);
+ pir->x=wxi;
+ pir->y=wyi;
+ pir->id=i;
+ pir->pir=0;
+ pir->patch=patch_space;
+ br->nr=nr+1;
+
+ db_SignedSquareNormCorr11x11_PreAlign_u(patch_space,f_img,xi,yi,&(pir->sum),&(pir->recip));
+ patch_space+=128;
+ }
+ }
+ }
+ return(patch_space);
+}
+
+
+
+short* db_FillBucketsPrewarpedAffine_u(short *patch_space,const unsigned char * const *f_img,db_Bucket_u **bp,
+ int bw,int bh,int nr_h,int nr_v,int bd,const double *x,const double *y,
+ int nr_corners,const double H[9],const double Hinv[9],const int warpboundsp[4],
+ int affine)
+{
+ int i,xi,yi,xpos,ypos,nr,wxi,wyi;
+ db_Bucket_u *br;
+ db_PointInfo_u *pir;
+ double xd[2],wx[2];
+
+ db_EmptyBuckets_u(bp,nr_h,nr_v);
+ for(i=0;i<nr_corners;i++)
+ {
+ xd[0]=x[i];
+ xd[1]=y[i];
+ xi=(int) db_roundi(xd[0]);
+ yi=(int) db_roundi(xd[1]);
+ db_ImageHomographyInhomogenous(wx,H,xd);
+ wxi=(int) wx[0];
+ wyi=(int) wx[1];
+
+ xpos=((wxi+bw)/bw)-1;
+ ypos=((wyi+bh)/bh)-1;
+
+
+ if (xpos>= -1 && xpos<=nr_h && ypos>= -1 && ypos<=nr_v)
+ {
+ if( xi>warpboundsp[0] && xi<warpboundsp[1] && yi>warpboundsp[2] && yi<warpboundsp[3])
+ {
+
+ br=&bp[ypos][xpos];
+ nr=br->nr;
+ if(nr<bd)
+ {
+ pir=&(br->ptr[nr]);
+ pir->x=wxi;
+ pir->y=wyi;
+ pir->id=i;
+ pir->pir=0;
+ pir->patch=patch_space;
+ br->nr=nr+1;
+
+ db_SignedSquareNormCorr11x11_PreAlign_AffinePatchWarp_u(patch_space,f_img,xi,yi,&(pir->sum),&(pir->recip),Hinv,affine);
+ patch_space+=128;
+ }
+ }
+ }
+ }
+ return(patch_space);
+}
+
+
+
+inline void db_MatchPointPair_f(db_PointInfo_f *pir_l,db_PointInfo_f *pir_r,
+ unsigned long kA,unsigned long kB)
+{
+ int x_l,y_l,x_r,y_r,xm,ym;
+ double score;
+
+ x_l=pir_l->x;
+ y_l=pir_l->y;
+ x_r=pir_r->x;
+ y_r=pir_r->y;
+ xm=x_l-x_r;
+ ym=y_l-y_r;
+ /*Check if disparity is within the maximum disparity
+ with the formula xm^2*256+ym^2*kA<kB
+ where kA=256*w^2/h^2
+ and kB=256*max_disp^2*w^2*/
+ if(((xm*xm)<<8)+ym*ym*kA<kB)
+ {
+ /*Correlate*/
+ score=db_SignedSquareNormCorr11x11Aligned_Post_f(pir_l->patch,pir_r->patch,
+ (pir_l->sum)*(pir_r->sum),
+ (pir_l->recip)*(pir_r->recip));
+
+ if((!(pir_l->pir)) || (score>pir_l->s))
+ {
+ /*Update left corner*/
+ pir_l->s=score;
+ pir_l->pir=pir_r;
+ }
+ if((!(pir_r->pir)) || (score>pir_r->s))
+ {
+ /*Update right corner*/
+ pir_r->s=score;
+ pir_r->pir=pir_l;
+ }
+ }
+}
+
+inline void db_MatchPointPair_u(db_PointInfo_u *pir_l,db_PointInfo_u *pir_r,
+ unsigned long kA,unsigned long kB, unsigned int rect_window,bool use_smaller_matching_window, int use_21)
+{
+ int xm,ym;
+ double score;
+ bool compute_score;
+
+
+ if( rect_window )
+ compute_score = ((unsigned)db_absi(pir_l->x - pir_r->x)<kA && (unsigned)db_absi(pir_l->y - pir_r->y)<kB);
+ else
+ { /*Check if disparity is within the maximum disparity
+ with the formula xm^2*256+ym^2*kA<kB
+ where kA=256*w^2/h^2
+ and kB=256*max_disp^2*w^2*/
+ xm= pir_l->x - pir_r->x;
+ ym= pir_l->y - pir_r->y;
+ compute_score = ((xm*xm)<<8)+ym*ym*kA < kB;
+ }
+
+ if ( compute_score )
+ {
+ if(use_21)
+ {
+ score=db_SignedSquareNormCorr21x21Aligned_Post_s(pir_l->patch,pir_r->patch,
+ (pir_l->sum)*(pir_r->sum),
+ (pir_l->recip)*(pir_r->recip));
+ }
+ else
+ {
+ /*Correlate*/
+ if(!use_smaller_matching_window)
+ {
+ score=db_SignedSquareNormCorr11x11Aligned_Post_s(pir_l->patch,pir_r->patch,
+ (pir_l->sum)*(pir_r->sum),
+ (pir_l->recip)*(pir_r->recip));
+ }
+ else
+ {
+ score=db_SignedSquareNormCorr5x5Aligned_Post_s(pir_l->patch,pir_r->patch,
+ (pir_l->sum)*(pir_r->sum),
+ (pir_l->recip)*(pir_r->recip));
+ }
+ }
+
+ if((!(pir_l->pir)) || (score>pir_l->s))
+ {
+ /*Update left corner*/
+ pir_l->s=score;
+ pir_l->pir=pir_r;
+ }
+ if((!(pir_r->pir)) || (score>pir_r->s))
+ {
+ /*Update right corner*/
+ pir_r->s=score;
+ pir_r->pir=pir_l;
+ }
+ }
+}
+
+inline void db_MatchPointAgainstBucket_f(db_PointInfo_f *pir_l,db_Bucket_f *b_r,
+ unsigned long kA,unsigned long kB)
+{
+ int p_r,nr;
+ db_PointInfo_f *pir_r;
+
+ nr=b_r->nr;
+ pir_r=b_r->ptr;
+ for(p_r=0;p_r<nr;p_r++) db_MatchPointPair_f(pir_l,pir_r+p_r,kA,kB);
+}
+
+inline void db_MatchPointAgainstBucket_u(db_PointInfo_u *pir_l,db_Bucket_u *b_r,
+ unsigned long kA,unsigned long kB,int rect_window, bool use_smaller_matching_window, int use_21)
+{
+ int p_r,nr;
+ db_PointInfo_u *pir_r;
+
+ nr=b_r->nr;
+ pir_r=b_r->ptr;
+
+ for(p_r=0;p_r<nr;p_r++) db_MatchPointPair_u(pir_l,pir_r+p_r,kA,kB, rect_window, use_smaller_matching_window, use_21);
+
+}
+
+void db_MatchBuckets_f(db_Bucket_f **bp_l,db_Bucket_f **bp_r,int nr_h,int nr_v,
+ unsigned long kA,unsigned long kB)
+{
+ int i,j,k,a,b,br_nr;
+ db_Bucket_f *br;
+ db_PointInfo_f *pir_l;
+
+ /*For all buckets*/
+ for(i=0;i<nr_v;i++) for(j=0;j<nr_h;j++)
+ {
+ br=&bp_l[i][j];
+ br_nr=br->nr;
+ /*For all points in bucket*/
+ for(k=0;k<br_nr;k++)
+ {
+ pir_l=br->ptr+k;
+ for(a=i-1;a<=i+1;a++)
+ {
+ for(b=j-1;b<=j+1;b++)
+ {
+ db_MatchPointAgainstBucket_f(pir_l,&bp_r[a][b],kA,kB);
+ }
+ }
+ }
+ }
+}
+
+void db_MatchBuckets_u(db_Bucket_u **bp_l,db_Bucket_u **bp_r,int nr_h,int nr_v,
+ unsigned long kA,unsigned long kB,int rect_window,bool use_smaller_matching_window, int use_21)
+{
+ int i,j,k,a,b,br_nr;
+ db_Bucket_u *br;
+ db_PointInfo_u *pir_l;
+
+ /*For all buckets*/
+ for(i=0;i<nr_v;i++) for(j=0;j<nr_h;j++)
+ {
+ br=&bp_l[i][j];
+ br_nr=br->nr;
+ /*For all points in bucket*/
+ for(k=0;k<br_nr;k++)
+ {
+ pir_l=br->ptr+k;
+ for(a=i-1;a<=i+1;a++)
+ {
+ for(b=j-1;b<=j+1;b++)
+ {
+ db_MatchPointAgainstBucket_u(pir_l,&bp_r[a][b],kA,kB,rect_window,use_smaller_matching_window, use_21);
+ }
+ }
+ }
+ }
+}
+
+void db_CollectMatches_f(db_Bucket_f **bp_l,int nr_h,int nr_v,unsigned long target,int *id_l,int *id_r,int *nr_matches)
+{
+ int i,j,k,br_nr;
+ unsigned long count;
+ db_Bucket_f *br;
+ db_PointInfo_f *pir,*pir2;
+
+ count=0;
+ /*For all buckets*/
+ for(i=0;i<nr_v;i++) for(j=0;j<nr_h;j++)
+ {
+ br=&bp_l[i][j];
+ br_nr=br->nr;
+ /*For all points in bucket*/
+ for(k=0;k<br_nr;k++)
+ {
+ pir=br->ptr+k;
+ pir2=pir->pir;
+ if(pir2)
+ {
+ /*This point has a best match*/
+ if((pir2->pir)==pir)
+ {
+ /*We have a mutually consistent match*/
+ if(count<target)
+ {
+ id_l[count]=pir->id;
+ id_r[count]=pir2->id;
+ count++;
+ }
+ }
+ }
+ }
+ }
+ *nr_matches=count;
+}
+
+void db_CollectMatches_u(db_Bucket_u **bp_l,int nr_h,int nr_v,unsigned long target,int *id_l,int *id_r,int *nr_matches)
+{
+ int i,j,k,br_nr;
+ unsigned long count;
+ db_Bucket_u *br;
+ db_PointInfo_u *pir,*pir2;
+
+ count=0;
+ /*For all buckets*/
+ for(i=0;i<nr_v;i++) for(j=0;j<nr_h;j++)
+ {
+ br=&bp_l[i][j];
+ br_nr=br->nr;
+ /*For all points in bucket*/
+ for(k=0;k<br_nr;k++)
+ {
+ pir=br->ptr+k;
+ pir2=pir->pir;
+ if(pir2)
+ {
+ /*This point has a best match*/
+ if((pir2->pir)==pir)
+ {
+ /*We have a mutually consistent match*/
+ if(count<target)
+ {
+ id_l[count]=pir->id;
+ id_r[count]=pir2->id;
+ count++;
+ }
+ }
+ }
+ }
+ }
+ *nr_matches=count;
+}
+
+db_Matcher_f::db_Matcher_f()
+{
+ m_w=0; m_h=0;
+}
+
+db_Matcher_f::~db_Matcher_f()
+{
+ Clean();
+}
+
+void db_Matcher_f::Clean()
+{
+ if(m_w)
+ {
+ /*Free buckets*/
+ db_FreeBuckets_f(m_bp_l,m_nr_h,m_nr_v);
+ db_FreeBuckets_f(m_bp_r,m_nr_h,m_nr_v);
+ /*Free space for patch layouts*/
+ delete [] m_patch_space;
+ }
+ m_w=0; m_h=0;
+}
+
+unsigned long db_Matcher_f::Init(int im_width,int im_height,double max_disparity,int target_nr_corners)
+{
+ Clean();
+ m_w=im_width;
+ m_h=im_height;
+ m_bw=db_maxi(1,(int) (max_disparity*((double)im_width)));
+ m_bh=db_maxi(1,(int) (max_disparity*((double)im_height)));
+ m_nr_h=1+(im_width-1)/m_bw;
+ m_nr_v=1+(im_height-1)/m_bh;
+ m_bd=db_maxi(1,(int)(((double)target_nr_corners)*
+ max_disparity*max_disparity));
+ m_target=target_nr_corners;
+ m_kA=(long)(256.0*((double)(m_w*m_w))/((double)(m_h*m_h)));
+ m_kB=(long)(256.0*max_disparity*max_disparity*((double)(m_w*m_w)));
+
+ /*Alloc bucket structure*/
+ m_bp_l=db_AllocBuckets_f(m_nr_h,m_nr_v,m_bd);
+ m_bp_r=db_AllocBuckets_f(m_nr_h,m_nr_v,m_bd);
+
+ /*Alloc 16byte-aligned space for patch layouts*/
+ m_patch_space=new float [2*(m_nr_h+2)*(m_nr_v+2)*m_bd*128+16];
+ m_aligned_patch_space=db_AlignPointer_f(m_patch_space,16);
+
+ return(m_target);
+}
+
+void db_Matcher_f::Match(const float * const *l_img,const float * const *r_img,
+ const double *x_l,const double *y_l,int nr_l,const double *x_r,const double *y_r,int nr_r,
+ int *id_l,int *id_r,int *nr_matches,const double H[9])
+{
+ float *ps;
+
+ /*Insert the corners into bucket structure*/
+ ps=db_FillBuckets_f(m_aligned_patch_space,l_img,m_bp_l,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,x_l,y_l,nr_l);
+ if(H==0) db_FillBuckets_f(ps,r_img,m_bp_r,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,x_r,y_r,nr_r);
+ else db_FillBucketsPrewarped_f(ps,r_img,m_bp_r,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,x_r,y_r,nr_r,H);
+
+ /*Compute all the necessary match scores*/
+ db_MatchBuckets_f(m_bp_l,m_bp_r,m_nr_h,m_nr_v,m_kA,m_kB);
+
+ /*Collect the correspondences*/
+ db_CollectMatches_f(m_bp_l,m_nr_h,m_nr_v,m_target,id_l,id_r,nr_matches);
+}
+
+db_Matcher_u::db_Matcher_u()
+{
+ m_w=0; m_h=0;
+ m_rect_window = 0;
+ m_bw=m_bh=m_nr_h=m_nr_v=m_bd=m_target=0;
+ m_bp_l=m_bp_r=0;
+ m_patch_space=m_aligned_patch_space=0;
+}
+
+db_Matcher_u::db_Matcher_u(const db_Matcher_u& cm)
+{
+ Init(cm.m_w, cm.m_h, cm.m_max_disparity, cm.m_target, cm.m_max_disparity_v);
+}
+
+db_Matcher_u& db_Matcher_u::operator= (const db_Matcher_u& cm)
+{
+ if ( this == &cm ) return *this;
+ Init(cm.m_w, cm.m_h, cm.m_max_disparity, cm.m_target, cm.m_max_disparity_v);
+ return *this;
+}
+
+
+db_Matcher_u::~db_Matcher_u()
+{
+ Clean();
+}
+
+void db_Matcher_u::Clean()
+{
+ if(m_w)
+ {
+ /*Free buckets*/
+ db_FreeBuckets_u(m_bp_l,m_nr_h,m_nr_v);
+ db_FreeBuckets_u(m_bp_r,m_nr_h,m_nr_v);
+ /*Free space for patch layouts*/
+ delete [] m_patch_space;
+ }
+ m_w=0; m_h=0;
+}
+
+
+unsigned long db_Matcher_u::Init(int im_width,int im_height,double max_disparity,int target_nr_corners,
+ double max_disparity_v, bool use_smaller_matching_window, int use_21)
+{
+ Clean();
+ m_w=im_width;
+ m_h=im_height;
+ m_max_disparity=max_disparity;
+ m_max_disparity_v=max_disparity_v;
+
+ if ( max_disparity_v != DB_DEFAULT_NO_DISPARITY )
+ {
+ m_rect_window = 1;
+
+ m_bw=db_maxi(1,(int)(max_disparity*((double)im_width)));
+ m_bh=db_maxi(1,(int)(max_disparity_v*((double)im_height)));
+
+ m_bd=db_maxi(1,(int)(((double)target_nr_corners)*max_disparity*max_disparity_v));
+
+ m_kA=(int)(max_disparity*m_w);
+ m_kB=(int)(max_disparity_v*m_h);
+
+ } else
+ {
+ m_bw=(int)db_maxi(1,(int)(max_disparity*((double)im_width)));
+ m_bh=(int)db_maxi(1,(int)(max_disparity*((double)im_height)));
+
+ m_bd=db_maxi(1,(int)(((double)target_nr_corners)*max_disparity*max_disparity));
+
+ m_kA=(long)(256.0*((double)(m_w*m_w))/((double)(m_h*m_h)));
+ m_kB=(long)(256.0*max_disparity*max_disparity*((double)(m_w*m_w)));
+ }
+
+ m_nr_h=1+(im_width-1)/m_bw;
+ m_nr_v=1+(im_height-1)/m_bh;
+
+ m_target=target_nr_corners;
+
+ /*Alloc bucket structure*/
+ m_bp_l=db_AllocBuckets_u(m_nr_h,m_nr_v,m_bd);
+ m_bp_r=db_AllocBuckets_u(m_nr_h,m_nr_v,m_bd);
+
+ m_use_smaller_matching_window = use_smaller_matching_window;
+ m_use_21 = use_21;
+
+ if(m_use_21)
+ {
+ /*Alloc 64byte-aligned space for patch layouts*/
+ m_patch_space=new short [2*(m_nr_h+2)*(m_nr_v+2)*m_bd*512+64];
+ m_aligned_patch_space=db_AlignPointer_s(m_patch_space,64);
+ }
+ else
+ {
+ if(!m_use_smaller_matching_window)
+ {
+ /*Alloc 16byte-aligned space for patch layouts*/
+ m_patch_space=new short [2*(m_nr_h+2)*(m_nr_v+2)*m_bd*128+16];
+ m_aligned_patch_space=db_AlignPointer_s(m_patch_space,16);
+ }
+ else
+ {
+ /*Alloc 4byte-aligned space for patch layouts*/
+ m_patch_space=new short [2*(m_nr_h+2)*(m_nr_v+2)*m_bd*32+4];
+ m_aligned_patch_space=db_AlignPointer_s(m_patch_space,4);
+ }
+ }
+
+ return(m_target);
+}
+
+void db_Matcher_u::Match(const unsigned char * const *l_img,const unsigned char * const *r_img,
+ const double *x_l,const double *y_l,int nr_l,const double *x_r,const double *y_r,int nr_r,
+ int *id_l,int *id_r,int *nr_matches,const double H[9],int affine)
+{
+ short *ps;
+
+ /*Insert the corners into bucket structure*/
+ ps=db_FillBuckets_u(m_aligned_patch_space,l_img,m_bp_l,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,x_l,y_l,nr_l,m_use_smaller_matching_window,m_use_21);
+ if(H==0)
+ db_FillBuckets_u(ps,r_img,m_bp_r,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,x_r,y_r,nr_r,m_use_smaller_matching_window,m_use_21);
+ else
+ {
+ if (affine)
+ {
+ double Hinv[9];
+ db_InvertAffineTransform(Hinv,H);
+ float r_w, c_w;
+ float stretch_x[2];
+ float stretch_y[2];
+ AffineWarpPointOffset(r_w,c_w,Hinv, 5,5);
+ stretch_x[0]=db_absf(c_w);stretch_y[0]=db_absf(r_w);
+ AffineWarpPointOffset(r_w,c_w,Hinv, 5,-5);
+ stretch_x[1]=db_absf(c_w);stretch_y[1]=db_absf(r_w);
+ int max_stretxh_x=(int) (db_maxd(stretch_x[0],stretch_x[1]));
+ int max_stretxh_y=(int) (db_maxd(stretch_y[0],stretch_y[1]));
+ int warpbounds[4]={max_stretxh_x,m_w-1-max_stretxh_x,max_stretxh_y,m_h-1-max_stretxh_y};
+
+ for (int r=-5;r<=5;r++){
+ for (int c=-5;c<=5;c++){
+ AffineWarpPointOffset(r_w,c_w,Hinv,r,c);
+ AffineWarpPoint_BL_LUT_y[r+5][c+5]=r_w;
+ AffineWarpPoint_BL_LUT_x[r+5][c+5]=c_w;
+
+ AffineWarpPoint_NN_LUT_y[r+5][c+5]=db_roundi(r_w);
+ AffineWarpPoint_NN_LUT_x[r+5][c+5]=db_roundi(c_w);
+
+ }
+ }
+
+ db_FillBucketsPrewarpedAffine_u(ps,r_img,m_bp_r,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,
+ x_r,y_r,nr_r,H,Hinv,warpbounds,affine);
+ }
+ else
+ db_FillBucketsPrewarped_u(ps,r_img,m_bp_r,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,x_r,y_r,nr_r,H);
+ }
+
+
+ /*Compute all the necessary match scores*/
+ db_MatchBuckets_u(m_bp_l,m_bp_r,m_nr_h,m_nr_v,m_kA,m_kB, m_rect_window,m_use_smaller_matching_window,m_use_21);
+
+ /*Collect the correspondences*/
+ db_CollectMatches_u(m_bp_l,m_nr_h,m_nr_v,m_target,id_l,id_r,nr_matches);
+}
+
+int db_Matcher_u::IsAllocated()
+{
+ return (int)(m_w != 0);
+}
diff --git a/jni/feature_stab/db_vlvm/db_feature_matching.h b/jni/feature_stab/db_vlvm/db_feature_matching.h
new file mode 100644
index 000000000..6c056b9a3
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_feature_matching.h
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*$Id: db_feature_matching.h,v 1.3 2011/06/17 14:03:30 mbansal Exp $*/
+
+#ifndef DB_FEATURE_MATCHING_H
+#define DB_FEATURE_MATCHING_H
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup FeatureMatching Feature Matching
+ */
+#include "db_utilities.h"
+#include "db_utilities_constants.h"
+
+DB_API void db_SignedSquareNormCorr21x21_PreAlign_u(short *patch,const unsigned char * const *f_img,int x_f,int y_f,float *sum,float *recip);
+DB_API void db_SignedSquareNormCorr11x11_PreAlign_u(short *patch,const unsigned char * const *f_img,int x_f,int y_f,float *sum,float *recip);
+float db_SignedSquareNormCorr21x21Aligned_Post_s(const short *f_patch,const short *g_patch,float fsum_gsum,float f_recip_g_recip);
+float db_SignedSquareNormCorr11x11Aligned_Post_s(const short *f_patch,const short *g_patch,float fsum_gsum,float f_recip_g_recip);
+
+class db_PointInfo_f
+{
+public:
+ /*Coordinates of point*/
+ int x;
+ int y;
+ /*Id nr of point*/
+ int id;
+ /*Best match score*/
+ double s;
+ /*Best match candidate*/
+ db_PointInfo_f *pir;
+ /*Precomputed coefficients
+ of image patch*/
+ float sum;
+ float recip;
+ /*Pointer to patch layout*/
+ const float *patch;
+};
+
+class db_Bucket_f
+{
+public:
+ db_PointInfo_f *ptr;
+ int nr;
+};
+
+class db_PointInfo_u
+{
+public:
+ /*Coordinates of point*/
+ int x;
+ int y;
+ /*Id nr of point*/
+ int id;
+ /*Best match score*/
+ double s;
+ /*Best match candidate*/
+ db_PointInfo_u *pir;
+ /*Precomputed coefficients
+ of image patch*/
+ float sum;
+ float recip;
+ /*Pointer to patch layout*/
+ const short *patch;
+};
+
+class db_Bucket_u
+{
+public:
+ db_PointInfo_u *ptr;
+ int nr;
+};
+/*!
+ * \class db_Matcher_f
+ * \ingroup FeatureMatching
+ * \brief Feature matcher for float images.
+ *
+ * Normalized correlation feature matcher for <b>float</b> images.
+ * Correlation window size is constant and set to 11x11.
+ * See \ref FeatureDetection to detect Harris corners.
+ * Images are managed with functions in \ref LMImageBasicUtilities.
+ */
+class DB_API db_Matcher_f
+{
+public:
+ db_Matcher_f();
+ ~db_Matcher_f();
+
+ /*!
+ * Set parameters and pre-allocate memory. Return an upper bound
+ * on the number of matches.
+ * \param im_width width
+ * \param im_height height
+ * \param max_disparity maximum distance (as fraction of image size) between matches
+ * \param target_nr_corners maximum number of matches
+ * \return maximum number of matches
+ */
+ unsigned long Init(int im_width,int im_height,
+ double max_disparity=DB_DEFAULT_MAX_DISPARITY,
+ int target_nr_corners=DB_DEFAULT_TARGET_NR_CORNERS);
+
+ /*!
+ * Match two sets of features.
+ * If the prewarp H is not NULL it will be applied to the features
+ * in the right image before matching.
+ * Parameters id_l and id_r must point to arrays of size target_nr_corners
+ * (returned by Init()).
+ * The results of matching are in id_l and id_r.
+ * Interpretaqtion of results: if id_l[i] = m and id_r[i] = n,
+ * feature at (x_l[m],y_l[m]) matched to (x_r[n],y_r[n]).
+ * \param l_img left image
+ * \param r_img right image
+ * \param x_l left x coordinates of features
+ * \param y_l left y coordinates of features
+ * \param nr_l number of features in left image
+ * \param x_r right x coordinates of features
+ * \param y_r right y coordinates of features
+ * \param nr_r number of features in right image
+ * \param id_l indices of left features that matched
+ * \param id_r indices of right features that matched
+ * \param nr_matches number of features actually matched
+ * \param H image homography (prewarp) to be applied to right image features
+ */
+ void Match(const float * const *l_img,const float * const *r_img,
+ const double *x_l,const double *y_l,int nr_l,const double *x_r,const double *y_r,int nr_r,
+ int *id_l,int *id_r,int *nr_matches,const double H[9]=0);
+
+protected:
+ void Clean();
+
+ int m_w,m_h,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,m_target;
+ unsigned long m_kA,m_kB;
+ db_Bucket_f **m_bp_l;
+ db_Bucket_f **m_bp_r;
+ float *m_patch_space,*m_aligned_patch_space;
+};
+/*!
+ * \class db_Matcher_u
+ * \ingroup FeatureMatching
+ * \brief Feature matcher for byte images.
+ *
+ * Normalized correlation feature matcher for <b>byte</b> images.
+ * Correlation window size is constant and set to 11x11.
+ * See \ref FeatureDetection to detect Harris corners.
+ * Images are managed with functions in \ref LMImageBasicUtilities.
+ *
+ * If the prewarp matrix H is supplied, the feature coordinates are warped by H before being placed in
+ * appropriate buckets. If H is an affine transform and the "affine" parameter is set to 1 or 2,
+ * then the correlation patches themselves are warped before being placed in the patch space.
+ */
+class DB_API db_Matcher_u
+{
+public:
+ db_Matcher_u();
+
+ int GetPatchSize(){return 11;};
+
+ virtual ~db_Matcher_u();
+
+ /*!
+ Copy ctor duplicates settings.
+ Memory not copied.
+ */
+ db_Matcher_u(const db_Matcher_u& cm);
+
+ /*!
+ Assignment optor duplicates settings
+ Memory not copied.
+ */
+ db_Matcher_u& operator= (const db_Matcher_u& cm);
+
+ /*!
+ * Set parameters and pre-allocate memory. Return an upper bound
+ * on the number of matches.
+ * If max_disparity_v is DB_DEFAULT_NO_DISPARITY, look for matches
+ * in a ellipse around a feature of radius max_disparity*im_width by max_disparity*im_height.
+ * If max_disparity_v is specified, use a rectangle max_disparity*im_width by max_disparity_v*im_height.
+ * \param im_width width
+ * \param im_height height
+ * \param max_disparity maximum distance (as fraction of image size) between matches
+ * \param target_nr_corners maximum number of matches
+ * \param max_disparity_v maximum vertical disparity (distance between matches)
+ * \param use_smaller_matching_window if set to true, uses a correlation window of 5x5 instead of the default 11x11
+ * \return maximum number of matches
+ */
+ virtual unsigned long Init(int im_width,int im_height,
+ double max_disparity=DB_DEFAULT_MAX_DISPARITY,
+ int target_nr_corners=DB_DEFAULT_TARGET_NR_CORNERS,
+ double max_disparity_v=DB_DEFAULT_NO_DISPARITY,
+ bool use_smaller_matching_window=false, int use_21=0);
+
+ /*!
+ * Match two sets of features.
+ * If the prewarp H is not NULL it will be applied to the features
+ * in the right image before matching.
+ * Parameters id_l and id_r must point to arrays of size target_nr_corners
+ * (returned by Init()).
+ * The results of matching are in id_l and id_r.
+ * Interpretaqtion of results: if id_l[i] = m and id_r[i] = n,
+ * feature at (x_l[m],y_l[m]) matched to (x_r[n],y_r[n]).
+ * \param l_img left image
+ * \param r_img right image
+ * \param x_l left x coordinates of features
+ * \param y_l left y coordinates of features
+ * \param nr_l number of features in left image
+ * \param x_r right x coordinates of features
+ * \param y_r right y coordinates of features
+ * \param nr_r number of features in right image
+ * \param id_l indices of left features that matched
+ * \param id_r indices of right features that matched
+ * \param nr_matches number of features actually matched
+ * \param H image homography (prewarp) to be applied to right image features
+ * \param affine prewarp the 11x11 patches by given affine transform. 0 means no warping,
+ 1 means nearest neighbor, 2 means bilinear warping.
+ */
+ virtual void Match(const unsigned char * const *l_img,const unsigned char * const *r_img,
+ const double *x_l,const double *y_l,int nr_l,const double *x_r,const double *y_r,int nr_r,
+ int *id_l,int *id_r,int *nr_matches,const double H[9]=0,int affine=0);
+
+ /*!
+ * Checks if Init() was called.
+ * \return 1 if Init() was called, 0 otherwise.
+ */
+ int IsAllocated();
+
+protected:
+ virtual void Clean();
+
+
+ int m_w,m_h,m_bw,m_bh,m_nr_h,m_nr_v,m_bd,m_target;
+ unsigned long m_kA,m_kB;
+ db_Bucket_u **m_bp_l;
+ db_Bucket_u **m_bp_r;
+ short *m_patch_space,*m_aligned_patch_space;
+
+ double m_max_disparity, m_max_disparity_v;
+ int m_rect_window;
+ bool m_use_smaller_matching_window;
+ int m_use_21;
+};
+
+
+
+#endif /*DB_FEATURE_MATCHING_H*/
diff --git a/jni/feature_stab/db_vlvm/db_framestitching.cpp b/jni/feature_stab/db_vlvm/db_framestitching.cpp
new file mode 100644
index 000000000..b574f7a04
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_framestitching.cpp
@@ -0,0 +1,169 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_framestitching.cpp,v 1.2 2011/06/17 14:03:30 mbansal Exp $ */
+
+#include "db_utilities.h"
+#include "db_framestitching.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+inline void db_RotationFromMOuterProductSum(double R[9],double *score,double M[9])
+{
+ double N[16],q[4],lambda[4],lambda_max;
+ double y[4];
+ int nr_roots;
+
+ N[0]= M[0]+M[4]+M[8];
+ N[5]= M[0]-M[4]-M[8];
+ N[10]= -M[0]+M[4]-M[8];
+ N[15]= -M[0]-M[4]+M[8];
+ N[1] =N[4] =M[5]-M[7];
+ N[2] =N[8] =M[6]-M[2];
+ N[3] =N[12]=M[1]-M[3];
+ N[6] =N[9] =M[1]+M[3];
+ N[7] =N[13]=M[6]+M[2];
+ N[11]=N[14]=M[5]+M[7];
+
+ /*get the quaternion representing the rotation
+ by finding the eigenvector corresponding to the most
+ positive eigenvalue. Force eigenvalue solutions, since the matrix
+ is symmetric and solutions might otherwise be lost
+ when the data is planar*/
+ db_RealEigenvalues4x4(lambda,&nr_roots,N,1);
+ if(nr_roots)
+ {
+ lambda_max=lambda[0];
+ if(nr_roots>=2)
+ {
+ if(lambda[1]>lambda_max) lambda_max=lambda[1];
+ if(nr_roots>=3)
+ {
+ if(lambda[2]>lambda_max) lambda_max=lambda[2];
+ {
+ if(nr_roots>=4) if(lambda[3]>lambda_max) lambda_max=lambda[3];
+ }
+ }
+ }
+ }
+ else lambda_max=1.0;
+ db_EigenVector4x4(q,lambda_max,N);
+
+ /*Compute the rotation matrix*/
+ db_QuaternionToRotation(R,q);
+
+ if(score)
+ {
+ /*Compute score=transpose(q)*N*q */
+ db_Multiply4x4_4x1(y,N,q);
+ *score=db_ScalarProduct4(q,y);
+ }
+}
+
+void db_StitchSimilarity3DRaw(double *scale,double R[9],double t[3],
+ double **Xp,double **X,int nr_points,int orientation_preserving,
+ int allow_scaling,int allow_rotation,int allow_translation)
+{
+ int i;
+ double c[3],cp[3],r[3],rp[3],M[9],s,sp,sc;
+ double Rr[9],score_p,score_r;
+ double *temp,*temp_p;
+
+ if(allow_translation)
+ {
+ db_PointCentroid3D(c,X,nr_points);
+ db_PointCentroid3D(cp,Xp,nr_points);
+ }
+ else
+ {
+ db_Zero3(c);
+ db_Zero3(cp);
+ }
+
+ db_Zero9(M);
+ s=sp=0;
+ for(i=0;i<nr_points;i++)
+ {
+ temp= *X++;
+ temp_p= *Xp++;
+ r[0]=(*temp++)-c[0];
+ r[1]=(*temp++)-c[1];
+ r[2]=(*temp++)-c[2];
+ rp[0]=(*temp_p++)-cp[0];
+ rp[1]=(*temp_p++)-cp[1];
+ rp[2]=(*temp_p++)-cp[2];
+
+ M[0]+=r[0]*rp[0];
+ M[1]+=r[0]*rp[1];
+ M[2]+=r[0]*rp[2];
+ M[3]+=r[1]*rp[0];
+ M[4]+=r[1]*rp[1];
+ M[5]+=r[1]*rp[2];
+ M[6]+=r[2]*rp[0];
+ M[7]+=r[2]*rp[1];
+ M[8]+=r[2]*rp[2];
+
+ s+=db_sqr(r[0])+db_sqr(r[1])+db_sqr(r[2]);
+ sp+=db_sqr(rp[0])+db_sqr(rp[1])+db_sqr(rp[2]);
+ }
+
+ /*Compute scale*/
+ if(allow_scaling) sc=sqrt(db_SafeDivision(sp,s));
+ else sc=1.0;
+ *scale=sc;
+
+ /*Compute rotation*/
+ if(allow_rotation)
+ {
+ if(orientation_preserving)
+ {
+ db_RotationFromMOuterProductSum(R,0,M);
+ }
+ else
+ {
+ /*Try preserving*/
+ db_RotationFromMOuterProductSum(R,&score_p,M);
+ /*Try reversing*/
+ M[6]= -M[6];
+ M[7]= -M[7];
+ M[8]= -M[8];
+ db_RotationFromMOuterProductSum(Rr,&score_r,M);
+ if(score_r>score_p)
+ {
+ /*Reverse is better*/
+ R[0]=Rr[0]; R[1]=Rr[1]; R[2]= -Rr[2];
+ R[3]=Rr[3]; R[4]=Rr[4]; R[5]= -Rr[5];
+ R[6]=Rr[6]; R[7]=Rr[7]; R[8]= -Rr[8];
+ }
+ }
+ }
+ else db_Identity3x3(R);
+
+ /*Compute translation*/
+ if(allow_translation)
+ {
+ t[0]=cp[0]-sc*(R[0]*c[0]+R[1]*c[1]+R[2]*c[2]);
+ t[1]=cp[1]-sc*(R[3]*c[0]+R[4]*c[1]+R[5]*c[2]);
+ t[2]=cp[2]-sc*(R[6]*c[0]+R[7]*c[1]+R[8]*c[2]);
+ }
+ else db_Zero3(t);
+}
+
+
diff --git a/jni/feature_stab/db_vlvm/db_framestitching.h b/jni/feature_stab/db_vlvm/db_framestitching.h
new file mode 100644
index 000000000..5fef5f37e
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_framestitching.h
@@ -0,0 +1,94 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_framestitching.h,v 1.2 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_FRAMESTITCHING_H
+#define DB_FRAMESTITCHING_H
+/*!
+ * \defgroup FrameStitching Frame Stitching (2D and 3D homography estimation)
+ */
+/*\{*/
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMFrameStitching (LM) Frame Stitching (2D and 3D homography estimation)
+ */
+/*\{*/
+
+/*!
+Find scale, rotation and translation of the similarity that
+takes the nr_points inhomogenous 3D points X to Xp
+(left to right according to Horn), i.e. for the homogenous equivalents
+Xp and X we would have
+\code
+ Xp~
+ [sR t]*X
+ [0 1]
+\endcode
+If orientation_preserving is true, R is restricted such that det(R)>0.
+allow_scaling, allow_rotation and allow_translation allow s,R and t
+to differ from 1,Identity and 0
+
+Full similarity takes the following on 550MHz:
+\code
+4.5 microseconds with 3 points
+4.7 microseconds with 4 points
+5.0 microseconds with 5 points
+5.2 microseconds with 6 points
+5.8 microseconds with 10 points
+20 microseconds with 100 points
+205 microseconds with 1000 points
+2.9 milliseconds with 10000 points
+50 milliseconds with 100000 points
+0.5 seconds with 1000000 points
+\endcode
+Without orientation_preserving:
+\code
+4 points is minimal for (s,R,t) (R,t)
+3 points is minimal for (s,R) (R)
+2 points is minimal for (s,t)
+1 point is minimal for (s) (t)
+\endcode
+With orientation_preserving:
+\code
+3 points is minimal for (s,R,t) (R,t)
+2 points is minimal for (s,R) (s,t) (R)
+1 point is minimal for (s) (t)
+\endcode
+
+\param scale scale
+\param R rotation
+\param t translation
+\param Xp inhomogenouse 3D points in first coordinate system
+\param X inhomogenouse 3D points in second coordinate system
+\param nr_points number of points
+\param orientation_preserving if true, R is restricted such that det(R)>0.
+\param allow_scaling estimate scale
+\param allow_rotation estimate rotation
+\param allow_translation estimate translation
+*/
+DB_API void db_StitchSimilarity3DRaw(double *scale,double R[9],double t[3],
+ double **Xp,double **X,int nr_points,int orientation_preserving=1,
+ int allow_scaling=1,int allow_rotation=1,int allow_translation=1);
+
+
+/*\}*/
+
+#endif /* DB_FRAMESTITCHING_H */
diff --git a/jni/feature_stab/db_vlvm/db_image_homography.cpp b/jni/feature_stab/db_vlvm/db_image_homography.cpp
new file mode 100644
index 000000000..aaad7f85e
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_image_homography.cpp
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_image_homography.cpp,v 1.2 2011/06/17 14:03:31 mbansal Exp $ */
+
+#include "db_utilities.h"
+#include "db_image_homography.h"
+#include "db_framestitching.h"
+#include "db_metrics.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+/*Compute the linear constraint on H obtained by requiring that the
+ratio between coordinate i_num and i_den of xp is equal to the ratio
+between coordinate i_num and i_den of Hx. i_zero should be set to
+the coordinate not equal to i_num or i_den. No normalization is used*/
+inline void db_SProjImagePointPointConstraint(double c[9],int i_num,int i_den,int i_zero,
+ double xp[3],double x[3])
+{
+ db_MultiplyScalarCopy3(c+3*i_den,x, xp[i_num]);
+ db_MultiplyScalarCopy3(c+3*i_num,x, -xp[i_den]);
+ db_Zero3(c+3*i_zero);
+}
+
+/*Compute two constraints on H generated by the correspondence (Xp,X),
+assuming that Xp ~= H*X. No normalization is used*/
+inline void db_SProjImagePointPointConstraints(double c1[9],double c2[9],double xp[3],double x[3])
+{
+ int ma_ind;
+
+ /*Find index of coordinate of Xp with largest absolute value*/
+ ma_ind=db_MaxAbsIndex3(xp);
+
+ /*Generate 2 constraints,
+ each constraint is generated by considering the ratio between a
+ coordinate and the largest absolute value coordinate*/
+ switch(ma_ind)
+ {
+ case 0:
+ db_SProjImagePointPointConstraint(c1,1,0,2,xp,x);
+ db_SProjImagePointPointConstraint(c2,2,0,1,xp,x);
+ break;
+ case 1:
+ db_SProjImagePointPointConstraint(c1,0,1,2,xp,x);
+ db_SProjImagePointPointConstraint(c2,2,1,0,xp,x);
+ break;
+ default:
+ db_SProjImagePointPointConstraint(c1,0,2,1,xp,x);
+ db_SProjImagePointPointConstraint(c2,1,2,0,xp,x);
+ }
+}
+
+inline void db_SAffineImagePointPointConstraints(double c1[7],double c2[7],double xp[3],double x[3])
+{
+ double ct1[9],ct2[9];
+
+ db_SProjImagePointPointConstraints(ct1,ct2,xp,x);
+ db_Copy6(c1,ct1); c1[6]=ct1[8];
+ db_Copy6(c2,ct2); c2[6]=ct2[8];
+}
+
+void db_StitchProjective2D_4Points(double H[9],
+ double x1[3],double x2[3],double x3[3],double x4[3],
+ double xp1[3],double xp2[3],double xp3[3],double xp4[3])
+{
+ double c[72];
+
+ /*Collect the constraints*/
+ db_SProjImagePointPointConstraints(c ,c+9 ,xp1,x1);
+ db_SProjImagePointPointConstraints(c+18,c+27,xp2,x2);
+ db_SProjImagePointPointConstraints(c+36,c+45,xp3,x3);
+ db_SProjImagePointPointConstraints(c+54,c+63,xp4,x4);
+ /*Solve for the nullvector*/
+ db_NullVector8x9Destructive(H,c);
+}
+
+void db_StitchAffine2D_3Points(double H[9],
+ double x1[3],double x2[3],double x3[3],
+ double xp1[3],double xp2[3],double xp3[3])
+{
+ double c[42];
+
+ /*Collect the constraints*/
+ db_SAffineImagePointPointConstraints(c ,c+7 ,xp1,x1);
+ db_SAffineImagePointPointConstraints(c+14,c+21,xp2,x2);
+ db_SAffineImagePointPointConstraints(c+28,c+35,xp3,x3);
+ /*Solve for the nullvector*/
+ db_NullVector6x7Destructive(H,c);
+ db_MultiplyScalar6(H,db_SafeReciprocal(H[6]));
+ H[6]=H[7]=0; H[8]=1.0;
+}
+
+/*Compute up to three solutions for the focal length given two point correspondences
+generated by a rotation with a common unknown focal length. No specific normalization
+of the input points is required. If signed_disambiguation is true, the points are
+required to be in front of the camera*/
+inline void db_CommonFocalLengthFromRotation_2Point(double fsol[3],int *nr_sols,double x1[3],double x2[3],double xp1[3],double xp2[3],int signed_disambiguation=1)
+{
+ double m,ax,ay,apx,apy,bx,by,bpx,bpy;
+ double p1[2],p2[2],p3[2],p4[2],p5[2],p6[2];
+ double p7[3],p8[4],p9[5],p10[3],p11[4];
+ double roots[3];
+ int nr_roots,i,j;
+
+ /*Solve for focal length using the equation
+ <a,b>^2*<ap,ap><bp,bp>=<ap,bp>^2*<a,a><b,b>
+ where a and ap are the homogenous vectors in the first image
+ after focal length scaling and b,bp are the vectors in the
+ second image*/
+
+ /*Normalize homogenous coordinates so that last coordinate is one*/
+ m=db_SafeReciprocal(x1[2]);
+ ax=x1[0]*m;
+ ay=x1[1]*m;
+ m=db_SafeReciprocal(xp1[2]);
+ apx=xp1[0]*m;
+ apy=xp1[1]*m;
+ m=db_SafeReciprocal(x2[2]);
+ bx=x2[0]*m;
+ by=x2[1]*m;
+ m=db_SafeReciprocal(xp2[2]);
+ bpx=xp2[0]*m;
+ bpy=xp2[1]*m;
+
+ /*Compute cubic in l=1/(f^2)
+ by dividing out the root l=0 from the equation
+ (l(ax*bx+ay*by)+1)^2*(l(apx^2+apy^2)+1)*(l(bpx^2+bpy^2)+1)=
+ (l(apx*bpx+apy*bpy)+1)^2*(l(ax^2+ay^2)+1)*(l(bx^2+by^2)+1)*/
+ p1[1]=ax*bx+ay*by;
+ p2[1]=db_sqr(apx)+db_sqr(apy);
+ p3[1]=db_sqr(bpx)+db_sqr(bpy);
+ p4[1]=apx*bpx+apy*bpy;
+ p5[1]=db_sqr(ax)+db_sqr(ay);
+ p6[1]=db_sqr(bx)+db_sqr(by);
+ p1[0]=p2[0]=p3[0]=p4[0]=p5[0]=p6[0]=1;
+
+ db_MultiplyPoly1_1(p7,p1,p1);
+ db_MultiplyPoly1_2(p8,p2,p7);
+ db_MultiplyPoly1_3(p9,p3,p8);
+
+ db_MultiplyPoly1_1(p10,p4,p4);
+ db_MultiplyPoly1_2(p11,p5,p10);
+ db_SubtractPolyProduct1_3(p9,p6,p11);
+ /*Cubic starts at p9[1]*/
+ db_SolveCubic(roots,&nr_roots,p9[4],p9[3],p9[2],p9[1]);
+
+ for(j=0,i=0;i<nr_roots;i++)
+ {
+ if(roots[i]>0)
+ {
+ if((!signed_disambiguation) || (db_PolyEval1(p1,roots[i])*db_PolyEval1(p4,roots[i])>0))
+ {
+ fsol[j++]=db_SafeSqrtReciprocal(roots[i]);
+ }
+ }
+ }
+ *nr_sols=j;
+}
+
+int db_StitchRotationCommonFocalLength_3Points(double H[9],double x1[3],double x2[3],double x3[3],double xp1[3],double xp2[3],double xp3[3],double *f,int signed_disambiguation)
+{
+ double fsol[3];
+ int nr_sols,i,best_sol,done;
+ double cost,best_cost;
+ double m,hyp[27],x1_temp[3],x2_temp[3],xp1_temp[3],xp2_temp[3];
+ double *hyp_point,ft;
+ double y[2];
+
+ db_CommonFocalLengthFromRotation_2Point(fsol,&nr_sols,x1,x2,xp1,xp2,signed_disambiguation);
+ if(nr_sols)
+ {
+ db_DeHomogenizeImagePoint(y,xp3);
+ done=0;
+ for(i=0;i<nr_sols;i++)
+ {
+ ft=fsol[i];
+ m=db_SafeReciprocal(ft);
+ x1_temp[0]=x1[0]*m;
+ x1_temp[1]=x1[1]*m;
+ x1_temp[2]=x1[2];
+ x2_temp[0]=x2[0]*m;
+ x2_temp[1]=x2[1]*m;
+ x2_temp[2]=x2[2];
+ xp1_temp[0]=xp1[0]*m;
+ xp1_temp[1]=xp1[1]*m;
+ xp1_temp[2]=xp1[2];
+ xp2_temp[0]=xp2[0]*m;
+ xp2_temp[1]=xp2[1]*m;
+ xp2_temp[2]=xp2[2];
+
+ hyp_point=hyp+9*i;
+ db_StitchCameraRotation_2Points(hyp_point,x1_temp,x2_temp,xp1_temp,xp2_temp);
+ hyp_point[2]*=ft;
+ hyp_point[5]*=ft;
+ hyp_point[6]*=m;
+ hyp_point[7]*=m;
+ cost=db_SquaredReprojectionErrorHomography(y,hyp_point,x3);
+
+ if(!done || cost<best_cost)
+ {
+ done=1;
+ best_cost=cost;
+ best_sol=i;
+ }
+ }
+
+ if(f) *f=fsol[best_sol];
+ db_Copy9(H,hyp+9*best_sol);
+ return(1);
+ }
+ else
+ {
+ db_Identity3x3(H);
+ if(f) *f=1.0;
+ return(0);
+ }
+}
+
+void db_StitchSimilarity2DRaw(double *scale,double R[4],double t[2],
+ double **Xp,double **X,int nr_points,int orientation_preserving,
+ int allow_scaling,int allow_rotation,int allow_translation)
+{
+ int i;
+ double c[2],cp[2],r[2],rp[2],M[4],s,sp,sc;
+ double *temp,*temp_p;
+ double Aacc,Bacc,Aacc2,Bacc2,divisor,divisor2,m,Am,Bm;
+
+ if(allow_translation)
+ {
+ db_PointCentroid2D(c,X,nr_points);
+ db_PointCentroid2D(cp,Xp,nr_points);
+ }
+ else
+ {
+ db_Zero2(c);
+ db_Zero2(cp);
+ }
+
+ db_Zero4(M);
+ s=sp=0;
+ for(i=0;i<nr_points;i++)
+ {
+ temp= *X++;
+ temp_p= *Xp++;
+ r[0]=(*temp++)-c[0];
+ r[1]=(*temp++)-c[1];
+ rp[0]=(*temp_p++)-cp[0];
+ rp[1]=(*temp_p++)-cp[1];
+
+ M[0]+=r[0]*rp[0];
+ M[1]+=r[0]*rp[1];
+ M[2]+=r[1]*rp[0];
+ M[3]+=r[1]*rp[1];
+
+ s+=db_sqr(r[0])+db_sqr(r[1]);
+ sp+=db_sqr(rp[0])+db_sqr(rp[1]);
+ }
+
+ /*Compute scale*/
+ if(allow_scaling) sc=sqrt(db_SafeDivision(sp,s));
+ else sc=1.0;
+ *scale=sc;
+
+ /*Compute rotation*/
+ if(allow_rotation)
+ {
+ /*orientation preserving*/
+ Aacc=M[0]+M[3];
+ Bacc=M[2]-M[1];
+ /*orientation reversing*/
+ Aacc2=M[0]-M[3];
+ Bacc2=M[2]+M[1];
+ if(Aacc!=0.0 || Bacc!=0.0)
+ {
+ divisor=sqrt(Aacc*Aacc+Bacc*Bacc);
+ m=db_SafeReciprocal(divisor);
+ Am=Aacc*m;
+ Bm=Bacc*m;
+ R[0]= Am;
+ R[1]= Bm;
+ R[2]= -Bm;
+ R[3]= Am;
+ }
+ else
+ {
+ db_Identity2x2(R);
+ divisor=0.0;
+ }
+ if(!orientation_preserving && (Aacc2!=0.0 || Bacc2!=0.0))
+ {
+ divisor2=sqrt(Aacc2*Aacc2+Bacc2*Bacc2);
+ if(divisor2>divisor)
+ {
+ m=db_SafeReciprocal(divisor2);
+ Am=Aacc2*m;
+ Bm=Bacc2*m;
+ R[0]= Am;
+ R[1]= Bm;
+ R[2]= Bm;
+ R[3]= -Am;
+ }
+ }
+ }
+ else db_Identity2x2(R);
+
+ /*Compute translation*/
+ if(allow_translation)
+ {
+ t[0]=cp[0]-sc*(R[0]*c[0]+R[1]*c[1]);
+ t[1]=cp[1]-sc*(R[2]*c[0]+R[3]*c[1]);
+ }
+ else db_Zero2(t);
+}
+
+
diff --git a/jni/feature_stab/db_vlvm/db_image_homography.h b/jni/feature_stab/db_vlvm/db_image_homography.h
new file mode 100644
index 000000000..165447dd7
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_image_homography.h
@@ -0,0 +1,183 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_image_homography.h,v 1.2 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_IMAGE_HOMOGRAPHY
+#define DB_IMAGE_HOMOGRAPHY
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+#include "db_framestitching.h"
+/*!
+ * \defgroup LMImageHomography (LM) Image Homography Estimation (feature based)
+ */
+/*\{*/
+/*!
+Solve for projective H such that xp~Hx. Prior normalization is not necessary,
+although desirable for numerical conditioning
+\param H image projective (out)
+\param x1 image 1 point 1
+\param x2 image 1 point 2
+\param x3 image 1 point 3
+\param x4 image 1 point 4
+\param xp1 image 2 point 1
+\param xp2 image 2 point 2
+\param xp3 image 2 point 3
+\param xp4 image 2 point 4
+*/
+DB_API void db_StitchProjective2D_4Points(double H[9],
+ double x1[3],double x2[3],double x3[3],double x4[3],
+ double xp1[3],double xp2[3],double xp3[3],double xp4[3]);
+
+/*!
+Solve for affine H such that xp~Hx. Prior normalization is not necessary,
+although desirable for numerical conditioning
+\param H image projective (out)
+\param x1 image 1 point 1
+\param x2 image 1 point 2
+\param x3 image 1 point 3
+\param xp1 image 2 point 1
+\param xp2 image 2 point 2
+\param xp3 image 2 point 3
+*/
+DB_API void db_StitchAffine2D_3Points(double H[9],
+ double x1[3],double x2[3],double x3[3],
+ double xp1[3],double xp2[3],double xp3[3]);
+
+/*!
+Solve for rotation R such that xp~Rx.
+Image points have to be of unit norm for the least squares to be meaningful.
+\param R image rotation (out)
+\param x1 image 1 point 1
+\param x2 image 1 point 2
+\param xp1 image 2 point 1
+\param xp2 image 2 point 2
+*/
+inline void db_StitchCameraRotation_2Points(double R[9],
+ /*Image points have to be of unit norm
+ for the least squares to be meaningful*/
+ double x1[3],double x2[3],
+ double xp1[3],double xp2[3])
+{
+ double* x[2];
+ double* xp[2];
+ double scale,t[3];
+
+ x[0]=x1;
+ x[1]=x2;
+ xp[0]=xp1;
+ xp[1]=xp2;
+ db_StitchSimilarity3DRaw(&scale,R,t,xp,x,2,1,0,1,0);
+}
+
+/*!
+Solve for a homography H generated by a rotation R with a common unknown focal length f, i.e.
+H=diag(f,f,1)*R*diag(1/f,1/f,1) such that xp~Hx.
+If signed_disambiguation is true, the points are
+required to be in front of the camera. No specific normalization of the homogenous points
+is required, although it could be desirable to keep x1,x2,xp1 and xp2 of reasonable magnitude.
+If a solution is obtained the function returns 1, otherwise 0. If the focal length is desired
+a valid pointer should be passed in f
+*/
+DB_API int db_StitchRotationCommonFocalLength_3Points(double H[9],double x1[3],double x2[3],double x3[3],
+ double xp1[3],double xp2[3],double xp3[3],double *f=0,int signed_disambiguation=1);
+
+/*!
+Find scale, rotation and translation of the similarity that
+takes the nr_points inhomogenous 2D points X to Xp,
+i.e. for the homogenous equivalents
+Xp and X we would have
+\code
+Xp~
+[sR t]*X
+[0 1]
+\endcode
+If orientation_preserving is true, R is restricted such that det(R)>0.
+allow_scaling, allow_rotation and allow_translation allow s,R and t
+to differ from 1,Identity and 0
+
+Full similarity takes the following on 550MHz:
+\code
+0.9 microseconds with 2 points
+1.0 microseconds with 3 points
+1.1 microseconds with 4 points
+1.3 microseconds with 5 points
+1.4 microseconds with 6 points
+1.7 microseconds with 10 points
+9 microseconds with 100 points
+130 microseconds with 1000 points
+1.3 milliseconds with 10000 points
+35 milliseconds with 100000 points
+350 milliseconds with 1000000 points
+\endcode
+
+Without orientation_preserving:
+\code
+3 points is minimal for (s,R,t) (R,t)
+2 points is minimal for (s,t) (s,R) (R)
+1 point is minimal for (s) (t)
+\endcode
+
+With orientation_preserving:
+\code
+2 points is minimal for (s,R,t) (R,t) (s,t)
+1 point is minimal for (s,R) (R) (s) (t)
+\endcode
+\param scale (out)
+\param R 2D rotation (out)
+\param t 2D translation (out)
+\param Xp (nr_points x 2) pointer to array of image points
+\param X (nr_points x 2 ) pointer to array of image points
+\param nr_points number of points
+\param orientation_preserving
+\param allow_scaling compute scale (if 0, scale=1)
+\param allow_rotation compute rotation (if 0, R=[I])
+\param allow_translation compute translation (if 0 t = [0,0]')
+*/
+DB_API void db_StitchSimilarity2DRaw(double *scale,double R[4],double t[2],
+ double **Xp,double **X,int nr_points,int orientation_preserving=1,
+ int allow_scaling=1,int allow_rotation=1,int allow_translation=1);
+/*!
+See db_StitchRotationCommonFocalLength_3Points().
+\param H Image similarity transformation (out)
+\param Xp (nr_points x 2) pointer to array of image points
+\param X (nr_points x 2) pointer to array of image points
+\param nr_points number of points
+\param orientation_preserving
+\param allow_scaling compute scale (if 0, scale=1)
+\param allow_rotation compute rotation (if 0, R=[I])
+\param allow_translation compute translation (if 0 t = [0,0]')
+*/
+inline void db_StitchSimilarity2D(double H[9],double **Xp,double **X,int nr_points,int orientation_preserving=1,
+ int allow_scaling=1,int allow_rotation=1,int allow_translation=1)
+{
+ double s,R[4],t[2];
+
+ db_StitchSimilarity2DRaw(&s,R,t,Xp,X,nr_points,orientation_preserving,
+ allow_scaling,allow_rotation,allow_translation);
+
+ H[0]=s*R[0]; H[1]=s*R[1]; H[2]=t[0];
+ H[3]=s*R[2]; H[4]=s*R[3]; H[5]=t[1];
+ db_Zero2(H+6);
+ H[8]=1.0;
+}
+/*\}*/
+#endif /* DB_IMAGE_HOMOGRAPHY */
diff --git a/jni/feature_stab/db_vlvm/db_metrics.h b/jni/feature_stab/db_vlvm/db_metrics.h
new file mode 100644
index 000000000..6b95458f1
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_metrics.h
@@ -0,0 +1,408 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_metrics.h,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_METRICS
+#define DB_METRICS
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+#include "db_utilities.h"
+/*!
+ * \defgroup LMMetrics (LM) Metrics
+ */
+/*\{*/
+
+
+
+
+/*!
+Compute function value fp and Jacobian J of robustifier given input value f*/
+inline void db_CauchyDerivative(double J[4],double fp[2],const double f[2],double one_over_scale2)
+{
+ double x2,y2,r,r2,r2s,one_over_r2,fu,r_fu,one_over_r_fu;
+ double one_plus_r2s,half_dfu_dx,half_dfu_dy,coeff,coeff2,coeff3;
+ int at_zero;
+
+ /*The robustifier takes the input (x,y) and makes a new
+ vector (xp,yp) where
+ xp=sqrt(log(1+(x^2+y^2)*one_over_scale2))*x/sqrt(x^2+y^2)
+ yp=sqrt(log(1+(x^2+y^2)*one_over_scale2))*y/sqrt(x^2+y^2)
+ The new vector has the property
+ xp^2+yp^2=log(1+(x^2+y^2)*one_over_scale2)
+ i.e. when it is square-summed it gives the robust
+ reprojection error
+ Define
+ r2=(x^2+y^2) and
+ r2s=r2*one_over_scale2
+ fu=log(1+r2s)/r2
+ then
+ xp=sqrt(fu)*x
+ yp=sqrt(fu)*y
+ and
+ d(r2)/dx=2x
+ d(r2)/dy=2y
+ and
+ dfu/dx=d(r2)/dx*(r2s/(1+r2s)-log(1+r2s))/(r2*r2)
+ dfu/dy=d(r2)/dy*(r2s/(1+r2s)-log(1+r2s))/(r2*r2)
+ and
+ d(xp)/dx=1/(2sqrt(fu))*(dfu/dx)*x+sqrt(fu)
+ d(xp)/dy=1/(2sqrt(fu))*(dfu/dy)*x
+ d(yp)/dx=1/(2sqrt(fu))*(dfu/dx)*y
+ d(yp)/dy=1/(2sqrt(fu))*(dfu/dy)*y+sqrt(fu)
+ */
+
+ x2=db_sqr(f[0]);
+ y2=db_sqr(f[1]);
+ r2=x2+y2;
+ r=sqrt(r2);
+
+ if(r2<=0.0) at_zero=1;
+ else
+ {
+ one_over_r2=1.0/r2;
+ r2s=r2*one_over_scale2;
+ one_plus_r2s=1.0+r2s;
+ fu=log(one_plus_r2s)*one_over_r2;
+ r_fu=sqrt(fu);
+ if(r_fu<=0.0) at_zero=1;
+ else
+ {
+ one_over_r_fu=1.0/r_fu;
+ fp[0]=r_fu*f[0];
+ fp[1]=r_fu*f[1];
+ /*r2s is always >= 0*/
+ coeff=(r2s/one_plus_r2s*one_over_r2-fu)*one_over_r2;
+ half_dfu_dx=f[0]*coeff;
+ half_dfu_dy=f[1]*coeff;
+ coeff2=one_over_r_fu*half_dfu_dx;
+ coeff3=one_over_r_fu*half_dfu_dy;
+
+ J[0]=coeff2*f[0]+r_fu;
+ J[1]=coeff3*f[0];
+ J[2]=coeff2*f[1];
+ J[3]=coeff3*f[1]+r_fu;
+ at_zero=0;
+ }
+ }
+ if(at_zero)
+ {
+ /*Close to zero the robustifying mapping
+ becomes identity*sqrt(one_over_scale2)*/
+ fp[0]=0.0;
+ fp[1]=0.0;
+ J[0]=sqrt(one_over_scale2);
+ J[1]=0.0;
+ J[2]=0.0;
+ J[3]=J[0];
+ }
+}
+
+inline double db_SquaredReprojectionErrorHomography(const double y[2],const double H[9],const double x[3])
+{
+ double x0,x1,x2,mult;
+ double sd;
+
+ x0=H[0]*x[0]+H[1]*x[1]+H[2]*x[2];
+ x1=H[3]*x[0]+H[4]*x[1]+H[5]*x[2];
+ x2=H[6]*x[0]+H[7]*x[1]+H[8]*x[2];
+ mult=1.0/((x2!=0.0)?x2:1.0);
+ sd=db_sqr((y[0]-x0*mult))+db_sqr((y[1]-x1*mult));
+
+ return(sd);
+}
+
+inline double db_SquaredInhomogenousHomographyError(const double y[2],const double H[9],const double x[2])
+{
+ double x0,x1,x2,mult;
+ double sd;
+
+ x0=H[0]*x[0]+H[1]*x[1]+H[2];
+ x1=H[3]*x[0]+H[4]*x[1]+H[5];
+ x2=H[6]*x[0]+H[7]*x[1]+H[8];
+ mult=1.0/((x2!=0.0)?x2:1.0);
+ sd=db_sqr((y[0]-x0*mult))+db_sqr((y[1]-x1*mult));
+
+ return(sd);
+}
+
+/*!
+Return a constant divided by likelihood of a Cauchy distributed
+reprojection error given the image point y, homography H, image point
+point x and the squared scale coefficient one_over_scale2=1.0/(scale*scale)
+where scale is the half width at half maximum (hWahM) of the
+Cauchy distribution*/
+inline double db_ExpCauchyInhomogenousHomographyError(const double y[2],const double H[9],const double x[2],
+ double one_over_scale2)
+{
+ double sd;
+ sd=db_SquaredInhomogenousHomographyError(y,H,x);
+ return(1.0+sd*one_over_scale2);
+}
+
+/*!
+Compute residual vector f between image point y and homography Hx of
+image point x. Also compute Jacobian of f with respect
+to an update dx of H*/
+inline void db_DerivativeInhomHomographyError(double Jf_dx[18],double f[2],const double y[2],const double H[9],
+ const double x[2])
+{
+ double xh,yh,zh,mult,mult2,xh_mult2,yh_mult2;
+ /*The Jacobian of the inhomogenous coordinates with respect to
+ the homogenous is
+ [1/zh 0 -xh/(zh*zh)]
+ [ 0 1/zh -yh/(zh*zh)]
+ The Jacobian of the homogenous coordinates with respect to dH is
+ [x0 x1 1 0 0 0 0 0 0]
+ [ 0 0 0 x0 x1 1 0 0 0]
+ [ 0 0 0 0 0 0 x0 x1 1]
+ The output Jacobian is minus their product, i.e.
+ [-x0/zh -x1/zh -1/zh 0 0 0 x0*xh/(zh*zh) x1*xh/(zh*zh) xh/(zh*zh)]
+ [ 0 0 0 -x0/zh -x1/zh -1/zh x0*yh/(zh*zh) x1*yh/(zh*zh) yh/(zh*zh)]*/
+
+ /*Compute warped point, which is the same as
+ homogenous coordinates of reprojection*/
+ xh=H[0]*x[0]+H[1]*x[1]+H[2];
+ yh=H[3]*x[0]+H[4]*x[1]+H[5];
+ zh=H[6]*x[0]+H[7]*x[1]+H[8];
+ mult=1.0/((zh!=0.0)?zh:1.0);
+ /*Compute inhomogenous residual*/
+ f[0]=y[0]-xh*mult;
+ f[1]=y[1]-yh*mult;
+ /*Compute Jacobian*/
+ mult2=mult*mult;
+ xh_mult2=xh*mult2;
+ yh_mult2=yh*mult2;
+ Jf_dx[0]= -x[0]*mult;
+ Jf_dx[1]= -x[1]*mult;
+ Jf_dx[2]= -mult;
+ Jf_dx[3]=0;
+ Jf_dx[4]=0;
+ Jf_dx[5]=0;
+ Jf_dx[6]=x[0]*xh_mult2;
+ Jf_dx[7]=x[1]*xh_mult2;
+ Jf_dx[8]=xh_mult2;
+ Jf_dx[9]=0;
+ Jf_dx[10]=0;
+ Jf_dx[11]=0;
+ Jf_dx[12]=Jf_dx[0];
+ Jf_dx[13]=Jf_dx[1];
+ Jf_dx[14]=Jf_dx[2];
+ Jf_dx[15]=x[0]*yh_mult2;
+ Jf_dx[16]=x[1]*yh_mult2;
+ Jf_dx[17]=yh_mult2;
+}
+
+/*!
+Compute robust residual vector f between image point y and homography Hx of
+image point x. Also compute Jacobian of f with respect
+to an update dH of H*/
+inline void db_DerivativeCauchyInhomHomographyReprojection(double Jf_dx[18],double f[2],const double y[2],const double H[9],
+ const double x[2],double one_over_scale2)
+{
+ double Jf_dx_loc[18],f_loc[2];
+ double J[4],J0,J1,J2,J3;
+
+ /*Compute reprojection Jacobian*/
+ db_DerivativeInhomHomographyError(Jf_dx_loc,f_loc,y,H,x);
+ /*Compute robustifier Jacobian*/
+ db_CauchyDerivative(J,f,f_loc,one_over_scale2);
+
+ /*Multiply the robustifier Jacobian with
+ the reprojection Jacobian*/
+ J0=J[0];J1=J[1];J2=J[2];J3=J[3];
+ Jf_dx[0]=J0*Jf_dx_loc[0];
+ Jf_dx[1]=J0*Jf_dx_loc[1];
+ Jf_dx[2]=J0*Jf_dx_loc[2];
+ Jf_dx[3]= J1*Jf_dx_loc[12];
+ Jf_dx[4]= J1*Jf_dx_loc[13];
+ Jf_dx[5]= J1*Jf_dx_loc[14];
+ Jf_dx[6]=J0*Jf_dx_loc[6]+J1*Jf_dx_loc[15];
+ Jf_dx[7]=J0*Jf_dx_loc[7]+J1*Jf_dx_loc[16];
+ Jf_dx[8]=J0*Jf_dx_loc[8]+J1*Jf_dx_loc[17];
+ Jf_dx[9]= J2*Jf_dx_loc[0];
+ Jf_dx[10]=J2*Jf_dx_loc[1];
+ Jf_dx[11]=J2*Jf_dx_loc[2];
+ Jf_dx[12]= J3*Jf_dx_loc[12];
+ Jf_dx[13]= J3*Jf_dx_loc[13];
+ Jf_dx[14]= J3*Jf_dx_loc[14];
+ Jf_dx[15]=J2*Jf_dx_loc[6]+J3*Jf_dx_loc[15];
+ Jf_dx[16]=J2*Jf_dx_loc[7]+J3*Jf_dx_loc[16];
+ Jf_dx[17]=J2*Jf_dx_loc[8]+J3*Jf_dx_loc[17];
+}
+/*!
+Compute residual vector f between image point y and rotation of
+image point x by R. Also compute Jacobian of f with respect
+to an update dx of R*/
+inline void db_DerivativeInhomRotationReprojection(double Jf_dx[6],double f[2],const double y[2],const double R[9],
+ const double x[2])
+{
+ double xh,yh,zh,mult,mult2,xh_mult2,yh_mult2;
+ /*The Jacobian of the inhomogenous coordinates with respect to
+ the homogenous is
+ [1/zh 0 -xh/(zh*zh)]
+ [ 0 1/zh -yh/(zh*zh)]
+ The Jacobian at zero of the homogenous coordinates with respect to
+ [sin(phi) sin(ohm) sin(kap)] is
+ [-rx2 0 rx1 ]
+ [ 0 rx2 -rx0 ]
+ [ rx0 -rx1 0 ]
+ The output Jacobian is minus their product, i.e.
+ [1+xh*xh/(zh*zh) -xh*yh/(zh*zh) -yh/zh]
+ [xh*yh/(zh*zh) -1-yh*yh/(zh*zh) xh/zh]*/
+
+ /*Compute rotated point, which is the same as
+ homogenous coordinates of reprojection*/
+ xh=R[0]*x[0]+R[1]*x[1]+R[2];
+ yh=R[3]*x[0]+R[4]*x[1]+R[5];
+ zh=R[6]*x[0]+R[7]*x[1]+R[8];
+ mult=1.0/((zh!=0.0)?zh:1.0);
+ /*Compute inhomogenous residual*/
+ f[0]=y[0]-xh*mult;
+ f[1]=y[1]-yh*mult;
+ /*Compute Jacobian*/
+ mult2=mult*mult;
+ xh_mult2=xh*mult2;
+ yh_mult2=yh*mult2;
+ Jf_dx[0]= 1.0+xh*xh_mult2;
+ Jf_dx[1]= -yh*xh_mult2;
+ Jf_dx[2]= -yh*mult;
+ Jf_dx[3]= -Jf_dx[1];
+ Jf_dx[4]= -1-yh*yh_mult2;
+ Jf_dx[5]= xh*mult;
+}
+
+/*!
+Compute robust residual vector f between image point y and rotation of
+image point x by R. Also compute Jacobian of f with respect
+to an update dx of R*/
+inline void db_DerivativeCauchyInhomRotationReprojection(double Jf_dx[6],double f[2],const double y[2],const double R[9],
+ const double x[2],double one_over_scale2)
+{
+ double Jf_dx_loc[6],f_loc[2];
+ double J[4],J0,J1,J2,J3;
+
+ /*Compute reprojection Jacobian*/
+ db_DerivativeInhomRotationReprojection(Jf_dx_loc,f_loc,y,R,x);
+ /*Compute robustifier Jacobian*/
+ db_CauchyDerivative(J,f,f_loc,one_over_scale2);
+
+ /*Multiply the robustifier Jacobian with
+ the reprojection Jacobian*/
+ J0=J[0];J1=J[1];J2=J[2];J3=J[3];
+ Jf_dx[0]=J0*Jf_dx_loc[0]+J1*Jf_dx_loc[3];
+ Jf_dx[1]=J0*Jf_dx_loc[1]+J1*Jf_dx_loc[4];
+ Jf_dx[2]=J0*Jf_dx_loc[2]+J1*Jf_dx_loc[5];
+ Jf_dx[3]=J2*Jf_dx_loc[0]+J3*Jf_dx_loc[3];
+ Jf_dx[4]=J2*Jf_dx_loc[1]+J3*Jf_dx_loc[4];
+ Jf_dx[5]=J2*Jf_dx_loc[2]+J3*Jf_dx_loc[5];
+}
+
+
+
+/*!
+// remove the outliers whose projection error is larger than pre-defined
+*/
+inline int db_RemoveOutliers_Homography(const double H[9], double *x_i,double *xp_i, double *wp,double *im, double *im_p, double *im_r, double *im_raw,double *im_raw_p,int point_count,double scale, double thresh=DB_OUTLIER_THRESHOLD)
+{
+ double temp_valueE, t2;
+ int c;
+ int k1=0;
+ int k2=0;
+ int k3=0;
+ int numinliers=0;
+ int ind1;
+ int ind2;
+ int ind3;
+ int isinlier;
+
+ // experimentally determined
+ t2=1.0/(thresh*thresh*thresh*thresh);
+
+ // count the inliers
+ for(c=0;c<point_count;c++)
+ {
+ ind1=c<<1;
+ ind2=c<<2;
+ ind3=3*c;
+
+ temp_valueE=db_SquaredInhomogenousHomographyError(im_p+ind3,H,im+ind3);
+
+ isinlier=((temp_valueE<=t2)?1:0);
+
+ // if it is inlier, then copy the 3d and 2d correspondences
+ if (isinlier)
+ {
+ numinliers++;
+
+ x_i[k1]=x_i[ind1];
+ x_i[k1+1]=x_i[ind1+1];
+
+ xp_i[k1]=xp_i[ind1];
+ xp_i[k1+1]=xp_i[ind1+1];
+
+ k1=k1+2;
+
+ // original normalized pixel coordinates
+ im[k3]=im[ind3];
+ im[k3+1]=im[ind3+1];
+ im[k3+2]=im[ind3+2];
+
+ im_r[k3]=im_r[ind3];
+ im_r[k3+1]=im_r[ind3+1];
+ im_r[k3+2]=im_r[ind3+2];
+
+ im_p[k3]=im_p[ind3];
+ im_p[k3+1]=im_p[ind3+1];
+ im_p[k3+2]=im_p[ind3+2];
+
+ // left and right raw pixel coordinates
+ im_raw[k3] = im_raw[ind3];
+ im_raw[k3+1] = im_raw[ind3+1];
+ im_raw[k3+2] = im_raw[ind3+2]; // the index
+
+ im_raw_p[k3] = im_raw_p[ind3];
+ im_raw_p[k3+1] = im_raw_p[ind3+1];
+ im_raw_p[k3+2] = im_raw_p[ind3+2]; // the index
+
+ k3=k3+3;
+
+ // 3D coordinates
+ wp[k2]=wp[ind2];
+ wp[k2+1]=wp[ind2+1];
+ wp[k2+2]=wp[ind2+2];
+ wp[k2+3]=wp[ind2+3];
+
+ k2=k2+4;
+
+ }
+ }
+
+ return numinliers;
+}
+
+
+
+
+
+/*\}*/
+
+#endif /* DB_METRICS */
diff --git a/jni/feature_stab/db_vlvm/db_rob_image_homography.cpp b/jni/feature_stab/db_vlvm/db_rob_image_homography.cpp
new file mode 100644
index 000000000..82dec0cbe
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_rob_image_homography.cpp
@@ -0,0 +1,1082 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_rob_image_homography.cpp,v 1.2 2011/06/17 14:03:31 mbansal Exp $ */
+
+#include "db_utilities.h"
+#include "db_rob_image_homography.h"
+#include "db_bundle.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+#include "db_image_homography.h"
+
+#ifdef _VERBOSE_
+#include <iostream>
+using namespace std;
+#endif /*VERBOSE*/
+
+inline double db_RobImageHomography_Cost(double H[9],int point_count,double *x_i,double *xp_i,double one_over_scale2)
+{
+ int c;
+ double back,acc,*x_i_temp,*xp_i_temp;
+
+ for(back=0.0,c=0;c<point_count;)
+ {
+ /*Take log of product of ten reprojection
+ errors to reduce nr of expensive log operations*/
+ if(c+9<point_count)
+ {
+ x_i_temp=x_i+(c<<1);
+ xp_i_temp=xp_i+(c<<1);
+
+ acc=db_ExpCauchyInhomogenousHomographyError(xp_i_temp,H,x_i_temp,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+2,H,x_i_temp+2,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+4,H,x_i_temp+4,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+6,H,x_i_temp+6,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+8,H,x_i_temp+8,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+10,H,x_i_temp+10,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+12,H,x_i_temp+12,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+14,H,x_i_temp+14,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+16,H,x_i_temp+16,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+18,H,x_i_temp+18,one_over_scale2);
+ c+=10;
+ }
+ else
+ {
+ for(acc=1.0;c<point_count;c++)
+ {
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i+(c<<1),H,x_i+(c<<1),one_over_scale2);
+ }
+ }
+ back+=log(acc);
+ }
+ return(back);
+}
+
+inline double db_RobImageHomography_Statistics(double H[9],int point_count,double *x_i,double *xp_i,double one_over_scale2,db_Statistics *stat,double thresh=DB_OUTLIER_THRESHOLD)
+{
+ int c,i;
+ double t2,frac;
+
+ t2=thresh*thresh;
+ for(i=0,c=0;c<point_count;c++)
+ {
+ i+=(db_SquaredInhomogenousHomographyError(xp_i+(c<<1),H,x_i+(c<<1))*one_over_scale2<=t2)?1:0;
+ }
+ frac=((double)i)/((double)(db_maxi(point_count,1)));
+
+#ifdef _VERBOSE_
+ std::cout << "Inlier Percentage RobImageHomography: " << frac*100.0 << "% out of " << point_count << " constraints" << std::endl;
+#endif /*_VERBOSE_*/
+
+ if(stat)
+ {
+ stat->nr_points=point_count;
+ stat->one_over_scale2=one_over_scale2;
+ stat->nr_inliers=i;
+ stat->inlier_fraction=frac;
+
+ stat->cost=db_RobImageHomography_Cost(H,point_count,x_i,xp_i,one_over_scale2);
+ stat->model_dimension=0;
+ /*stat->nr_parameters=;*/
+
+ stat->lambda1=log(4.0);
+ stat->lambda2=log(4.0*((double)db_maxi(1,stat->nr_points)));
+ stat->lambda3=10.0;
+ stat->gric=stat->cost+stat->lambda1*stat->model_dimension*((double)stat->nr_points)+stat->lambda2*((double)stat->nr_parameters);
+ stat->inlier_evidence=((double)stat->nr_inliers)-stat->lambda3*((double)stat->nr_parameters);
+ }
+
+ return(frac);
+}
+
+/*Compute min_Jtf and upper right of JtJ. Return cost.*/
+inline double db_RobImageHomography_Jacobians(double JtJ[81],double min_Jtf[9],double H[9],int point_count,double *x_i,double *xp_i,double one_over_scale2)
+{
+ double back,Jf_dx[18],f[2],temp,temp2;
+ int i;
+
+ db_Zero(JtJ,81);
+ db_Zero(min_Jtf,9);
+ for(back=0.0,i=0;i<point_count;i++)
+ {
+ /*Compute reprojection error vector and its Jacobian
+ for this point*/
+ db_DerivativeCauchyInhomHomographyReprojection(Jf_dx,f,xp_i+(i<<1),H,x_i+(i<<1),one_over_scale2);
+ /*Perform
+ min_Jtf-=Jf_dx*f[0] and
+ min_Jtf-=(Jf_dx+9)*f[1] to accumulate -Jt%f*/
+ db_RowOperation9(min_Jtf,Jf_dx,f[0]);
+ db_RowOperation9(min_Jtf,Jf_dx+9,f[1]);
+ /*Accumulate upper right of JtJ with outer product*/
+ temp=Jf_dx[0]; temp2=Jf_dx[9];
+ JtJ[0]+=temp*Jf_dx[0]+temp2*Jf_dx[9];
+ JtJ[1]+=temp*Jf_dx[1]+temp2*Jf_dx[10];
+ JtJ[2]+=temp*Jf_dx[2]+temp2*Jf_dx[11];
+ JtJ[3]+=temp*Jf_dx[3]+temp2*Jf_dx[12];
+ JtJ[4]+=temp*Jf_dx[4]+temp2*Jf_dx[13];
+ JtJ[5]+=temp*Jf_dx[5]+temp2*Jf_dx[14];
+ JtJ[6]+=temp*Jf_dx[6]+temp2*Jf_dx[15];
+ JtJ[7]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[8]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[1]; temp2=Jf_dx[10];
+ JtJ[10]+=temp*Jf_dx[1]+temp2*Jf_dx[10];
+ JtJ[11]+=temp*Jf_dx[2]+temp2*Jf_dx[11];
+ JtJ[12]+=temp*Jf_dx[3]+temp2*Jf_dx[12];
+ JtJ[13]+=temp*Jf_dx[4]+temp2*Jf_dx[13];
+ JtJ[14]+=temp*Jf_dx[5]+temp2*Jf_dx[14];
+ JtJ[15]+=temp*Jf_dx[6]+temp2*Jf_dx[15];
+ JtJ[16]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[17]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[2]; temp2=Jf_dx[11];
+ JtJ[20]+=temp*Jf_dx[2]+temp2*Jf_dx[11];
+ JtJ[21]+=temp*Jf_dx[3]+temp2*Jf_dx[12];
+ JtJ[22]+=temp*Jf_dx[4]+temp2*Jf_dx[13];
+ JtJ[23]+=temp*Jf_dx[5]+temp2*Jf_dx[14];
+ JtJ[24]+=temp*Jf_dx[6]+temp2*Jf_dx[15];
+ JtJ[25]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[26]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[3]; temp2=Jf_dx[12];
+ JtJ[30]+=temp*Jf_dx[3]+temp2*Jf_dx[12];
+ JtJ[31]+=temp*Jf_dx[4]+temp2*Jf_dx[13];
+ JtJ[32]+=temp*Jf_dx[5]+temp2*Jf_dx[14];
+ JtJ[33]+=temp*Jf_dx[6]+temp2*Jf_dx[15];
+ JtJ[34]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[35]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[4]; temp2=Jf_dx[13];
+ JtJ[40]+=temp*Jf_dx[4]+temp2*Jf_dx[13];
+ JtJ[41]+=temp*Jf_dx[5]+temp2*Jf_dx[14];
+ JtJ[42]+=temp*Jf_dx[6]+temp2*Jf_dx[15];
+ JtJ[43]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[44]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[5]; temp2=Jf_dx[14];
+ JtJ[50]+=temp*Jf_dx[5]+temp2*Jf_dx[14];
+ JtJ[51]+=temp*Jf_dx[6]+temp2*Jf_dx[15];
+ JtJ[52]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[53]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[6]; temp2=Jf_dx[15];
+ JtJ[60]+=temp*Jf_dx[6]+temp2*Jf_dx[15];
+ JtJ[61]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[62]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[7]; temp2=Jf_dx[16];
+ JtJ[70]+=temp*Jf_dx[7]+temp2*Jf_dx[16];
+ JtJ[71]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+ temp=Jf_dx[8]; temp2=Jf_dx[17];
+ JtJ[80]+=temp*Jf_dx[8]+temp2*Jf_dx[17];
+
+ /*Add square-sum to cost*/
+ back+=db_sqr(f[0])+db_sqr(f[1]);
+ }
+
+ return(back);
+}
+
+/*Compute min_Jtf and upper right of JtJ. Return cost*/
+inline double db_RobCamRotation_Jacobians(double JtJ[9],double min_Jtf[3],double H[9],int point_count,double *x_i,double *xp_i,double one_over_scale2)
+{
+ double back,Jf_dx[6],f[2];
+ int i,j;
+
+ db_Zero(JtJ,9);
+ db_Zero(min_Jtf,3);
+ for(back=0.0,i=0;i<point_count;i++)
+ {
+ /*Compute reprojection error vector and its Jacobian
+ for this point*/
+ j=(i<<1);
+ db_DerivativeCauchyInhomRotationReprojection(Jf_dx,f,xp_i+j,H,x_i+j,one_over_scale2);
+ /*Perform
+ min_Jtf-=Jf_dx*f[0] and
+ min_Jtf-=(Jf_dx+3)*f[1] to accumulate -Jt%f*/
+ db_RowOperation3(min_Jtf,Jf_dx,f[0]);
+ db_RowOperation3(min_Jtf,Jf_dx+3,f[1]);
+ /*Accumulate upper right of JtJ with outer product*/
+ JtJ[0]+=Jf_dx[0]*Jf_dx[0]+Jf_dx[3]*Jf_dx[3];
+ JtJ[1]+=Jf_dx[0]*Jf_dx[1]+Jf_dx[3]*Jf_dx[4];
+ JtJ[2]+=Jf_dx[0]*Jf_dx[2]+Jf_dx[3]*Jf_dx[5];
+ JtJ[4]+=Jf_dx[1]*Jf_dx[1]+Jf_dx[4]*Jf_dx[4];
+ JtJ[5]+=Jf_dx[1]*Jf_dx[2]+Jf_dx[4]*Jf_dx[5];
+ JtJ[8]+=Jf_dx[2]*Jf_dx[2]+Jf_dx[5]*Jf_dx[5];
+
+ /*Add square-sum to cost*/
+ back+=db_sqr(f[0])+db_sqr(f[1]);
+ }
+
+ return(back);
+}
+
+void db_RobCamRotation_Polish(double H[9],int point_count,double *x_i,double *xp_i,double one_over_scale2,
+ int max_iterations,double improvement_requirement)
+{
+ int i,update,stop;
+ double lambda,cost,current_cost;
+ double JtJ[9],min_Jtf[3],dx[3],H_p_dx[9];
+
+ lambda=0.001;
+ for(update=1,stop=0,i=0;(stop<2) && (i<max_iterations);i++)
+ {
+ /*if first time since improvement, compute Jacobian and residual*/
+ if(update)
+ {
+ current_cost=db_RobCamRotation_Jacobians(JtJ,min_Jtf,H,point_count,x_i,xp_i,one_over_scale2);
+ update=0;
+ }
+
+#ifdef _VERBOSE_
+ /*std::cout << "Cost:" << current_cost << " ";*/
+#endif /*_VERBOSE_*/
+
+ /*Come up with a hypothesis dx
+ based on the current lambda*/
+ db_Compute_dx_3x3(dx,JtJ,min_Jtf,lambda);
+
+ /*Compute Cost(x+dx)*/
+ db_UpdateRotation(H_p_dx,H,dx);
+ cost=db_RobImageHomography_Cost(H_p_dx,point_count,x_i,xp_i,one_over_scale2);
+
+ /*Is there an improvement?*/
+ if(cost<current_cost)
+ {
+ /*improvement*/
+ if(current_cost-cost<current_cost*improvement_requirement) stop++;
+ else stop=0;
+ lambda*=0.1;
+ /*Move to the hypothesised position x+dx*/
+ current_cost=cost;
+ db_Copy9(H,H_p_dx);
+ db_OrthonormalizeRotation(H);
+ update=1;
+
+#ifdef _VERBOSE_
+ std::cout << "Step" << i << "Imp,Lambda=" << lambda << "Cost:" << current_cost << std::endl;
+#endif /*_VERBOSE_*/
+ }
+ else
+ {
+ /*no improvement*/
+ lambda*=10.0;
+ stop=0;
+ }
+ }
+}
+
+inline void db_RobImageHomographyFetchJacobian(double **JtJ_ref,double *min_Jtf,double **JtJ_temp_ref,double *min_Jtf_temp,int n,int *fetch_vector)
+{
+ int i,j,t;
+ double *t1,*t2;
+
+ for(i=0;i<n;i++)
+ {
+ t=fetch_vector[i];
+ min_Jtf[i]=min_Jtf_temp[t];
+ t1=JtJ_ref[i];
+ t2=JtJ_temp_ref[t];
+ for(j=i;j<n;j++)
+ {
+ t1[j]=t2[fetch_vector[j]];
+ }
+ }
+}
+
+inline void db_RobImageHomographyMultiplyJacobian(double **JtJ_ref,double *min_Jtf,double **JtJ_temp_ref,double *min_Jtf_temp,double **JE_dx_ref,int n)
+{
+ double JtJ_JE[72],*JtJ_JE_ref[9];
+
+ db_SetupMatrixRefs(JtJ_JE_ref,9,8,JtJ_JE);
+
+ db_SymmetricExtendUpperToLower(JtJ_temp_ref,9,9);
+ db_MultiplyMatricesAB(JtJ_JE_ref,JtJ_temp_ref,JE_dx_ref,9,9,n);
+ db_UpperMultiplyMatricesAtB(JtJ_ref,JE_dx_ref,JtJ_JE_ref,n,9,n);
+ db_MultiplyMatrixVectorAtb(min_Jtf,JE_dx_ref,min_Jtf_temp,n,9);
+}
+
+inline void db_RobImageHomographyJH_Js(double **JE_dx_ref,int j,double H[9])
+{
+ /*Update of upper 2x2 is multiplication by
+ [s 0][ cos(theta) sin(theta)]
+ [0 s][-sin(theta) cos(theta)]*/
+ JE_dx_ref[0][j]=H[0];
+ JE_dx_ref[1][j]=H[1];
+ JE_dx_ref[2][j]=0;
+ JE_dx_ref[3][j]=H[2];
+ JE_dx_ref[4][j]=H[3];
+ JE_dx_ref[5][j]=0;
+ JE_dx_ref[6][j]=0;
+ JE_dx_ref[7][j]=0;
+ JE_dx_ref[8][j]=0;
+}
+
+inline void db_RobImageHomographyJH_JR(double **JE_dx_ref,int j,double H[9])
+{
+ /*Update of upper 2x2 is multiplication by
+ [s 0][ cos(theta) sin(theta)]
+ [0 s][-sin(theta) cos(theta)]*/
+ JE_dx_ref[0][j]= H[3];
+ JE_dx_ref[1][j]= H[4];
+ JE_dx_ref[2][j]=0;
+ JE_dx_ref[3][j]= -H[0];
+ JE_dx_ref[4][j]= -H[1];
+ JE_dx_ref[5][j]=0;
+ JE_dx_ref[6][j]=0;
+ JE_dx_ref[7][j]=0;
+ JE_dx_ref[8][j]=0;
+}
+
+inline void db_RobImageHomographyJH_Jt(double **JE_dx_ref,int j,int k,double H[9])
+{
+ JE_dx_ref[0][j]=0;
+ JE_dx_ref[1][j]=0;
+ JE_dx_ref[2][j]=1.0;
+ JE_dx_ref[3][j]=0;
+ JE_dx_ref[4][j]=0;
+ JE_dx_ref[5][j]=0;
+ JE_dx_ref[6][j]=0;
+ JE_dx_ref[7][j]=0;
+ JE_dx_ref[8][j]=0;
+
+ JE_dx_ref[0][k]=0;
+ JE_dx_ref[1][k]=0;
+ JE_dx_ref[2][k]=0;
+ JE_dx_ref[3][k]=0;
+ JE_dx_ref[4][k]=0;
+ JE_dx_ref[5][k]=1.0;
+ JE_dx_ref[6][k]=0;
+ JE_dx_ref[7][k]=0;
+ JE_dx_ref[8][k]=0;
+}
+
+inline void db_RobImageHomographyJH_dRotFocal(double **JE_dx_ref,int j,int k,int l,int m,double H[9])
+{
+ double f,fi,fi2;
+ double R[9],J[9];
+
+ /*Updated matrix is diag(f+df,f+df)*dR*R*diag(1/(f+df),1/(f+df),1)*/
+ f=db_FocalAndRotFromCamRotFocalHomography(R,H);
+ fi=db_SafeReciprocal(f);
+ fi2=db_sqr(fi);
+ db_JacobianOfRotatedPointStride(J,R,3);
+ JE_dx_ref[0][j]= J[0];
+ JE_dx_ref[1][j]= J[1];
+ JE_dx_ref[2][j]=f* J[2];
+ JE_dx_ref[3][j]= J[3];
+ JE_dx_ref[4][j]= J[4];
+ JE_dx_ref[5][j]=f* J[5];
+ JE_dx_ref[6][j]=fi*J[6];
+ JE_dx_ref[7][j]=fi*J[7];
+ JE_dx_ref[8][j]= J[8];
+ db_JacobianOfRotatedPointStride(J,R+1,3);
+ JE_dx_ref[0][k]= J[0];
+ JE_dx_ref[1][k]= J[1];
+ JE_dx_ref[2][k]=f* J[2];
+ JE_dx_ref[3][k]= J[3];
+ JE_dx_ref[4][k]= J[4];
+ JE_dx_ref[5][k]=f* J[5];
+ JE_dx_ref[6][k]=fi*J[6];
+ JE_dx_ref[7][k]=fi*J[7];
+ JE_dx_ref[8][k]= J[8];
+ db_JacobianOfRotatedPointStride(J,R+2,3);
+ JE_dx_ref[0][l]= J[0];
+ JE_dx_ref[1][l]= J[1];
+ JE_dx_ref[2][l]=f* J[2];
+ JE_dx_ref[3][l]= J[3];
+ JE_dx_ref[4][l]= J[4];
+ JE_dx_ref[5][l]=f* J[5];
+ JE_dx_ref[6][l]=fi*J[6];
+ JE_dx_ref[7][l]=fi*J[7];
+ JE_dx_ref[8][l]= J[8];
+
+ JE_dx_ref[0][m]=0;
+ JE_dx_ref[1][m]=0;
+ JE_dx_ref[2][m]=H[2];
+ JE_dx_ref[3][m]=0;
+ JE_dx_ref[4][m]=0;
+ JE_dx_ref[5][m]=H[5];
+ JE_dx_ref[6][m]= -fi2*H[6];
+ JE_dx_ref[7][m]= -fi2*H[7];
+ JE_dx_ref[8][m]=0;
+}
+
+inline double db_RobImageHomography_Jacobians_Generic(double *JtJ_ref[8],double min_Jtf[8],int *num_param,int *frozen_coord,double H[9],int point_count,double *x_i,double *xp_i,int homography_type,double one_over_scale2)
+{
+ double back;
+ int i,j,fetch_vector[8],n;
+ double JtJ_temp[81],min_Jtf_temp[9],JE_dx[72];
+ double *JE_dx_ref[9],*JtJ_temp_ref[9];
+
+ /*Compute cost and JtJ,min_Jtf with respect to H*/
+ back=db_RobImageHomography_Jacobians(JtJ_temp,min_Jtf_temp,H,point_count,x_i,xp_i,one_over_scale2);
+
+ /*Compute JtJ,min_Jtf with respect to the right parameters
+ The formulas are
+ JtJ=transpose(JE_dx)*JtJ*JE_dx and
+ min_Jtf=transpose(JE_dx)*min_Jtf,
+ where the 9xN matrix JE_dx is the Jacobian of H with respect
+ to the update*/
+ db_SetupMatrixRefs(JtJ_temp_ref,9,9,JtJ_temp);
+ db_SetupMatrixRefs(JE_dx_ref,9,8,JE_dx);
+ switch(homography_type)
+ {
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY:
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY_U:
+ n=4;
+ db_RobImageHomographyJH_Js(JE_dx_ref,0,H);
+ db_RobImageHomographyJH_JR(JE_dx_ref,1,H);
+ db_RobImageHomographyJH_Jt(JE_dx_ref,2,3,H);
+ db_RobImageHomographyMultiplyJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,JE_dx_ref,n);
+ break;
+ case DB_HOMOGRAPHY_TYPE_ROTATION:
+ case DB_HOMOGRAPHY_TYPE_ROTATION_U:
+ n=1;
+ db_RobImageHomographyJH_JR(JE_dx_ref,0,H);
+ db_RobImageHomographyMultiplyJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,JE_dx_ref,n);
+ break;
+ case DB_HOMOGRAPHY_TYPE_SCALING:
+ n=1;
+ db_RobImageHomographyJH_Js(JE_dx_ref,0,H);
+ db_RobImageHomographyMultiplyJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,JE_dx_ref,n);
+ break;
+ case DB_HOMOGRAPHY_TYPE_S_T:
+ n=3;
+ db_RobImageHomographyJH_Js(JE_dx_ref,0,H);
+ db_RobImageHomographyJH_Jt(JE_dx_ref,1,2,H);
+ db_RobImageHomographyMultiplyJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,JE_dx_ref,n);
+ break;
+ case DB_HOMOGRAPHY_TYPE_R_T:
+ n=3;
+ db_RobImageHomographyJH_JR(JE_dx_ref,0,H);
+ db_RobImageHomographyJH_Jt(JE_dx_ref,1,2,H);
+ db_RobImageHomographyMultiplyJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,JE_dx_ref,n);
+ break;
+ case DB_HOMOGRAPHY_TYPE_R_S:
+ n=2;
+ db_RobImageHomographyJH_Js(JE_dx_ref,0,H);
+ db_RobImageHomographyJH_JR(JE_dx_ref,1,H);
+ db_RobImageHomographyMultiplyJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,JE_dx_ref,n);
+ break;
+
+ case DB_HOMOGRAPHY_TYPE_TRANSLATION:
+ n=2;
+ fetch_vector[0]=2;
+ fetch_vector[1]=5;
+ db_RobImageHomographyFetchJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,n,fetch_vector);
+ break;
+ case DB_HOMOGRAPHY_TYPE_AFFINE:
+ n=6;
+ fetch_vector[0]=0;
+ fetch_vector[1]=1;
+ fetch_vector[2]=2;
+ fetch_vector[3]=3;
+ fetch_vector[4]=4;
+ fetch_vector[5]=5;
+ db_RobImageHomographyFetchJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,n,fetch_vector);
+ break;
+ case DB_HOMOGRAPHY_TYPE_PROJECTIVE:
+ n=8;
+ *frozen_coord=db_MaxAbsIndex9(H);
+ for(j=0,i=0;i<9;i++) if(i!=(*frozen_coord))
+ {
+ fetch_vector[j]=i;
+ j++;
+ }
+ db_RobImageHomographyFetchJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,n,fetch_vector);
+ break;
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F:
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F_UD:
+ n=4;
+ db_RobImageHomographyJH_dRotFocal(JE_dx_ref,0,1,2,3,H);
+ db_RobImageHomographyMultiplyJacobian(JtJ_ref,min_Jtf,JtJ_temp_ref,min_Jtf_temp,JE_dx_ref,n);
+ break;
+ }
+ *num_param=n;
+
+ return(back);
+}
+
+inline void db_ImageHomographyUpdateGeneric(double H_p_dx[9],double H[9],double *dx,int homography_type,int frozen_coord)
+{
+ switch(homography_type)
+ {
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY:
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY_U:
+ db_Copy9(H_p_dx,H);
+ db_MultiplyScaleOntoImageHomography(H,1.0+dx[0]);
+ db_MultiplyRotationOntoImageHomography(H,dx[1]);
+ H_p_dx[2]+=dx[2];
+ H_p_dx[5]+=dx[3];
+ break;
+ case DB_HOMOGRAPHY_TYPE_ROTATION:
+ case DB_HOMOGRAPHY_TYPE_ROTATION_U:
+ db_MultiplyRotationOntoImageHomography(H,dx[0]);
+ break;
+ case DB_HOMOGRAPHY_TYPE_SCALING:
+ db_MultiplyScaleOntoImageHomography(H,1.0+dx[0]);
+ break;
+ case DB_HOMOGRAPHY_TYPE_S_T:
+ db_Copy9(H_p_dx,H);
+ db_MultiplyScaleOntoImageHomography(H,1.0+dx[0]);
+ H_p_dx[2]+=dx[1];
+ H_p_dx[5]+=dx[2];
+ break;
+ case DB_HOMOGRAPHY_TYPE_R_T:
+ db_Copy9(H_p_dx,H);
+ db_MultiplyRotationOntoImageHomography(H,dx[0]);
+ H_p_dx[2]+=dx[1];
+ H_p_dx[5]+=dx[2];
+ break;
+ case DB_HOMOGRAPHY_TYPE_R_S:
+ db_Copy9(H_p_dx,H);
+ db_MultiplyScaleOntoImageHomography(H,1.0+dx[0]);
+ db_MultiplyRotationOntoImageHomography(H,dx[1]);
+ break;
+ case DB_HOMOGRAPHY_TYPE_TRANSLATION:
+ db_Copy9(H_p_dx,H);
+ H_p_dx[2]+=dx[0];
+ H_p_dx[5]+=dx[1];
+ break;
+ case DB_HOMOGRAPHY_TYPE_AFFINE:
+ db_UpdateImageHomographyAffine(H_p_dx,H,dx);
+ break;
+ case DB_HOMOGRAPHY_TYPE_PROJECTIVE:
+ db_UpdateImageHomographyProjective(H_p_dx,H,dx,frozen_coord);
+ break;
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F:
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F_UD:
+ db_UpdateRotFocalHomography(H_p_dx,H,dx);
+ break;
+ }
+}
+
+void db_RobCamRotation_Polish_Generic(double H[9],int point_count,int homography_type,double *x_i,double *xp_i,double one_over_scale2,
+ int max_iterations,double improvement_requirement)
+{
+ int i,update,stop,n;
+ int frozen_coord = 0;
+ double lambda,cost,current_cost;
+ double JtJ[72],min_Jtf[9],dx[8],H_p_dx[9];
+ double *JtJ_ref[9],d[8];
+
+ lambda=0.001;
+ for(update=1,stop=0,i=0;(stop<2) && (i<max_iterations);i++)
+ {
+ /*if first time since improvement, compute Jacobian and residual*/
+ if(update)
+ {
+ db_SetupMatrixRefs(JtJ_ref,9,8,JtJ);
+ current_cost=db_RobImageHomography_Jacobians_Generic(JtJ_ref,min_Jtf,&n,&frozen_coord,H,point_count,x_i,xp_i,homography_type,one_over_scale2);
+ update=0;
+ }
+
+#ifdef _VERBOSE_
+ /*std::cout << "Cost:" << current_cost << " ";*/
+#endif /*_VERBOSE_*/
+
+ /*Come up with a hypothesis dx
+ based on the current lambda*/
+ db_Compute_dx(dx,JtJ_ref,min_Jtf,lambda,d,n);
+
+ /*Compute Cost(x+dx)*/
+ db_ImageHomographyUpdateGeneric(H_p_dx,H,dx,homography_type,frozen_coord);
+ cost=db_RobImageHomography_Cost(H_p_dx,point_count,x_i,xp_i,one_over_scale2);
+
+ /*Is there an improvement?*/
+ if(cost<current_cost)
+ {
+ /*improvement*/
+ if(current_cost-cost<current_cost*improvement_requirement) stop++;
+ else stop=0;
+ lambda*=0.1;
+ /*Move to the hypothesised position x+dx*/
+ current_cost=cost;
+ db_Copy9(H,H_p_dx);
+ update=1;
+
+#ifdef _VERBOSE_
+ std::cout << "Step" << i << "Imp,Lambda=" << lambda << "Cost:" << current_cost << std::endl;
+#endif /*_VERBOSE_*/
+ }
+ else
+ {
+ /*no improvement*/
+ lambda*=10.0;
+ stop=0;
+ }
+ }
+}
+void db_RobImageHomography(
+ /*Best homography*/
+ double H[9],
+ /*2DPoint to 2DPoint constraints
+ Points are assumed to be given in
+ homogenous coordinates*/
+ double *im, double *im_p,
+ /*Nr of points in total*/
+ int nr_points,
+ /*Calibration matrices
+ used to normalize the points*/
+ double K[9],
+ double Kp[9],
+ /*Pre-allocated space temp_d
+ should point to at least
+ 12*nr_samples+10*nr_points
+ allocated positions*/
+ double *temp_d,
+ /*Pre-allocated space temp_i
+ should point to at least
+ max(nr_samples,nr_points)
+ allocated positions*/
+ int *temp_i,
+ int homography_type,
+ db_Statistics *stat,
+ int max_iterations,
+ int max_points,
+ double scale,
+ int nr_samples,
+ int chunk_size,
+ /////////////////////////////////////////////
+ // regular use: set outlierremoveflagE =0;
+ // flag for the outlier removal
+ int outlierremoveflagE,
+ // if flag is 1, then the following variables
+ // need the input
+ //////////////////////////////////////
+ // 3D coordinates
+ double *wp,
+ // its corresponding stereo pair's points
+ double *im_r,
+ // raw image coordinates
+ double *im_raw, double *im_raw_p,
+ // final matches
+ int *finalNumE)
+{
+ /*Random seed*/
+ int r_seed;
+
+ int point_count_new;
+ /*Counters*/
+ int i,j,c,point_count,hyp_count;
+ int last_hyp,new_last_hyp,last_corr;
+ int pos,point_pos,last_point;
+ /*Accumulator*/
+ double acc;
+ /*Hypothesis pointer*/
+ double *hyp_point;
+ /*Random sample*/
+ int s[4];
+ /*Pivot for hypothesis pruning*/
+ double pivot;
+ /*Best hypothesis position*/
+ int best_pos;
+ /*Best score*/
+ double lowest_cost;
+ /*One over the squared scale of
+ Cauchy distribution*/
+ double one_over_scale2;
+ /*temporary pointers*/
+ double *x_i_temp,*xp_i_temp;
+ /*Temporary space for inverse calibration matrices*/
+ double K_inv[9];
+ double Kp_inv[9];
+ /*Temporary space for homography*/
+ double H_temp[9],H_temp2[9];
+ /*Pointers to homogenous coordinates*/
+ double *x_h_point,*xp_h_point;
+ /*Array of pointers to inhomogenous coordinates*/
+ double *X[3],*Xp[3];
+ /*Similarity parameters*/
+ int orientation_preserving,allow_scaling,allow_rotation,allow_translation,sample_size;
+
+ /*Homogenous coordinates of image points in first image*/
+ double *x_h;
+ /*Homogenous coordinates of image points in second image*/
+ double *xp_h;
+ /*Inhomogenous coordinates of image points in first image*/
+ double *x_i;
+ /*Inhomogenous coordinates of image points in second image*/
+ double *xp_i;
+ /*Homography hypotheses*/
+ double *hyp_H_array;
+ /*Cost array*/
+ double *hyp_cost_array;
+ /*Permutation of the hypotheses*/
+ int *hyp_perm;
+ /*Sample of the points*/
+ int *point_perm;
+ /*Temporary space for quick-select
+ 2*nr_samples*/
+ double *temp_select;
+
+ /*Get inverse calibration matrices*/
+ db_InvertCalibrationMatrix(K_inv,K);
+ db_InvertCalibrationMatrix(Kp_inv,Kp);
+ /*Compute scale coefficient*/
+ one_over_scale2=1.0/(scale*scale);
+ /*Initialize random seed*/
+ r_seed=12345;
+ /*Set pointers to pre-allocated space*/
+ hyp_cost_array=temp_d;
+ hyp_H_array=temp_d+nr_samples;
+ temp_select=temp_d+10*nr_samples;
+ x_h=temp_d+12*nr_samples;
+ xp_h=temp_d+12*nr_samples+3*nr_points;
+ x_i=temp_d+12*nr_samples+6*nr_points;
+ xp_i=temp_d+12*nr_samples+8*nr_points;
+ hyp_perm=temp_i;
+ point_perm=temp_i;
+
+ /*Prepare a randomly permuted subset of size
+ point_count from the input points*/
+
+ point_count=db_mini(nr_points,(int)(chunk_size*log((double)nr_samples)/DB_LN2));
+
+ point_count_new = point_count;
+
+ for(i=0;i<nr_points;i++) point_perm[i]=i;
+
+ for(last_point=nr_points-1,i=0;i<point_count;i++,last_point--)
+ {
+ pos=db_RandomInt(r_seed,last_point);
+ point_pos=point_perm[pos];
+ point_perm[pos]=point_perm[last_point];
+
+ /*Normalize image points with calibration
+ matrices and move them to x_h and xp_h*/
+ c=3*point_pos;
+ j=3*i;
+ x_h_point=x_h+j;
+ xp_h_point=xp_h+j;
+ db_Multiply3x3_3x1(x_h_point,K_inv,im+c);
+ db_Multiply3x3_3x1(xp_h_point,Kp_inv,im_p+c);
+
+ db_HomogenousNormalize3(x_h_point);
+ db_HomogenousNormalize3(xp_h_point);
+
+ /*Dehomogenize image points and move them
+ to x_i and xp_i*/
+ c=(i<<1);
+ db_DeHomogenizeImagePoint(x_i+c,x_h_point); // 2-dimension
+ db_DeHomogenizeImagePoint(xp_i+c,xp_h_point); //2-dimension
+ }
+
+
+ /*Generate Hypotheses*/
+ hyp_count=0;
+ switch(homography_type)
+ {
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY:
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY_U:
+ case DB_HOMOGRAPHY_TYPE_TRANSLATION:
+ case DB_HOMOGRAPHY_TYPE_ROTATION:
+ case DB_HOMOGRAPHY_TYPE_ROTATION_U:
+ case DB_HOMOGRAPHY_TYPE_SCALING:
+ case DB_HOMOGRAPHY_TYPE_S_T:
+ case DB_HOMOGRAPHY_TYPE_R_T:
+ case DB_HOMOGRAPHY_TYPE_R_S:
+
+ switch(homography_type)
+ {
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY:
+ orientation_preserving=1;
+ allow_scaling=1;
+ allow_rotation=1;
+ allow_translation=1;
+ sample_size=2;
+ break;
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY_U:
+ orientation_preserving=0;
+ allow_scaling=1;
+ allow_rotation=1;
+ allow_translation=1;
+ sample_size=3;
+ break;
+ case DB_HOMOGRAPHY_TYPE_TRANSLATION:
+ orientation_preserving=1;
+ allow_scaling=0;
+ allow_rotation=0;
+ allow_translation=1;
+ sample_size=1;
+ break;
+ case DB_HOMOGRAPHY_TYPE_ROTATION:
+ orientation_preserving=1;
+ allow_scaling=0;
+ allow_rotation=1;
+ allow_translation=0;
+ sample_size=1;
+ break;
+ case DB_HOMOGRAPHY_TYPE_ROTATION_U:
+ orientation_preserving=0;
+ allow_scaling=0;
+ allow_rotation=1;
+ allow_translation=0;
+ sample_size=2;
+ break;
+ case DB_HOMOGRAPHY_TYPE_SCALING:
+ orientation_preserving=1;
+ allow_scaling=1;
+ allow_rotation=0;
+ allow_translation=0;
+ sample_size=1;
+ break;
+ case DB_HOMOGRAPHY_TYPE_S_T:
+ orientation_preserving=1;
+ allow_scaling=1;
+ allow_rotation=0;
+ allow_translation=1;
+ sample_size=2;
+ break;
+ case DB_HOMOGRAPHY_TYPE_R_T:
+ orientation_preserving=1;
+ allow_scaling=0;
+ allow_rotation=1;
+ allow_translation=1;
+ sample_size=2;
+ break;
+ case DB_HOMOGRAPHY_TYPE_R_S:
+ orientation_preserving=1;
+ allow_scaling=1;
+ allow_rotation=0;
+ allow_translation=0;
+ sample_size=1;
+ break;
+ }
+
+ if(point_count>=sample_size) for(i=0;i<nr_samples;i++)
+ {
+ db_RandomSample(s,3,point_count,r_seed);
+ X[0]= &x_i[s[0]<<1];
+ X[1]= &x_i[s[1]<<1];
+ X[2]= &x_i[s[2]<<1];
+ Xp[0]= &xp_i[s[0]<<1];
+ Xp[1]= &xp_i[s[1]<<1];
+ Xp[2]= &xp_i[s[2]<<1];
+ db_StitchSimilarity2D(&hyp_H_array[9*hyp_count],Xp,X,sample_size,orientation_preserving,
+ allow_scaling,allow_rotation,allow_translation);
+ hyp_count++;
+ }
+ break;
+
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION:
+ if(point_count>=2) for(i=0;i<nr_samples;i++)
+ {
+ db_RandomSample(s,2,point_count,r_seed);
+ db_StitchCameraRotation_2Points(&hyp_H_array[9*hyp_count],
+ &x_h[3*s[0]],&x_h[3*s[1]],
+ &xp_h[3*s[0]],&xp_h[3*s[1]]);
+ hyp_count++;
+ }
+ break;
+
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F:
+ if(point_count>=3) for(i=0;i<nr_samples;i++)
+ {
+ db_RandomSample(s,3,point_count,r_seed);
+ hyp_count+=db_StitchRotationCommonFocalLength_3Points(&hyp_H_array[9*hyp_count],
+ &x_h[3*s[0]],&x_h[3*s[1]],&x_h[3*s[2]],
+ &xp_h[3*s[0]],&xp_h[3*s[1]],&xp_h[3*s[2]]);
+ }
+ break;
+
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F_UD:
+ if(point_count>=3) for(i=0;i<nr_samples;i++)
+ {
+ db_RandomSample(s,3,point_count,r_seed);
+ hyp_count+=db_StitchRotationCommonFocalLength_3Points(&hyp_H_array[9*hyp_count],
+ &x_h[3*s[0]],&x_h[3*s[1]],&x_h[3*s[2]],
+ &xp_h[3*s[0]],&xp_h[3*s[1]],&xp_h[3*s[2]],NULL,0);
+ }
+ break;
+
+ case DB_HOMOGRAPHY_TYPE_AFFINE:
+ if(point_count>=3) for(i=0;i<nr_samples;i++)
+ {
+ db_RandomSample(s,3,point_count,r_seed);
+ db_StitchAffine2D_3Points(&hyp_H_array[9*hyp_count],
+ &x_h[3*s[0]],&x_h[3*s[1]],&x_h[3*s[2]],
+ &xp_h[3*s[0]],&xp_h[3*s[1]],&xp_h[3*s[2]]);
+ hyp_count++;
+ }
+ break;
+
+ case DB_HOMOGRAPHY_TYPE_PROJECTIVE:
+ default:
+ if(point_count>=4) for(i=0;i<nr_samples;i++)
+ {
+ db_RandomSample(s,4,point_count,r_seed);
+ db_StitchProjective2D_4Points(&hyp_H_array[9*hyp_count],
+ &x_h[3*s[0]],&x_h[3*s[1]],&x_h[3*s[2]],&x_h[3*s[3]],
+ &xp_h[3*s[0]],&xp_h[3*s[1]],&xp_h[3*s[2]],&xp_h[3*s[3]]);
+ hyp_count++;
+ }
+ }
+
+ if(hyp_count)
+ {
+ /*Count cost in chunks and decimate hypotheses
+ until only one remains or the correspondences are
+ exhausted*/
+ for(i=0;i<hyp_count;i++)
+ {
+ hyp_perm[i]=i;
+ hyp_cost_array[i]=0.0;
+ }
+ for(i=0,last_hyp=hyp_count-1;(last_hyp>0) && (i<point_count);i+=chunk_size)
+ {
+ /*Update cost with the next chunk*/
+ last_corr=db_mini(i+chunk_size-1,point_count-1);
+ for(j=0;j<=last_hyp;j++)
+ {
+ hyp_point=hyp_H_array+9*hyp_perm[j];
+ for(c=i;c<=last_corr;)
+ {
+ /*Take log of product of ten reprojection
+ errors to reduce nr of expensive log operations*/
+ if(c+9<=last_corr)
+ {
+ x_i_temp=x_i+(c<<1);
+ xp_i_temp=xp_i+(c<<1);
+
+ acc=db_ExpCauchyInhomogenousHomographyError(xp_i_temp,hyp_point,x_i_temp,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+2,hyp_point,x_i_temp+2,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+4,hyp_point,x_i_temp+4,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+6,hyp_point,x_i_temp+6,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+8,hyp_point,x_i_temp+8,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+10,hyp_point,x_i_temp+10,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+12,hyp_point,x_i_temp+12,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+14,hyp_point,x_i_temp+14,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+16,hyp_point,x_i_temp+16,one_over_scale2);
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i_temp+18,hyp_point,x_i_temp+18,one_over_scale2);
+ c+=10;
+ }
+ else
+ {
+ for(acc=1.0;c<=last_corr;c++)
+ {
+ acc*=db_ExpCauchyInhomogenousHomographyError(xp_i+(c<<1),hyp_point,x_i+(c<<1),one_over_scale2);
+ }
+ }
+ hyp_cost_array[j]+=log(acc);
+ }
+ }
+ if (chunk_size<point_count){
+ /*Prune out half of the hypotheses*/
+ new_last_hyp=(last_hyp+1)/2-1;
+ pivot=db_LeanQuickSelect(hyp_cost_array,last_hyp+1,new_last_hyp,temp_select);
+ for(j=0,c=0;(j<=last_hyp) && (c<=new_last_hyp);j++)
+ {
+ if(hyp_cost_array[j]<=pivot)
+ {
+ hyp_cost_array[c]=hyp_cost_array[j];
+ hyp_perm[c]=hyp_perm[j];
+ c++;
+ }
+ }
+ last_hyp=new_last_hyp;
+ }
+ }
+ /*Find the best hypothesis*/
+ lowest_cost=hyp_cost_array[0];
+ best_pos=0;
+ for(j=1;j<=last_hyp;j++)
+ {
+ if(hyp_cost_array[j]<lowest_cost)
+ {
+ lowest_cost=hyp_cost_array[j];
+ best_pos=j;
+ }
+ }
+
+ /*Move the best hypothesis*/
+ db_Copy9(H_temp,hyp_H_array+9*hyp_perm[best_pos]);
+
+ // outlier removal
+ if (outlierremoveflagE) // no polishment needed
+ {
+ point_count_new = db_RemoveOutliers_Homography(H_temp,x_i,xp_i,wp,im,im_p,im_r,im_raw,im_raw_p,point_count,one_over_scale2);
+ }
+ else
+ {
+ /*Polish*/
+ switch(homography_type)
+ {
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY:
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY_U:
+ case DB_HOMOGRAPHY_TYPE_TRANSLATION:
+ case DB_HOMOGRAPHY_TYPE_ROTATION:
+ case DB_HOMOGRAPHY_TYPE_ROTATION_U:
+ case DB_HOMOGRAPHY_TYPE_SCALING:
+ case DB_HOMOGRAPHY_TYPE_S_T:
+ case DB_HOMOGRAPHY_TYPE_R_T:
+ case DB_HOMOGRAPHY_TYPE_R_S:
+ case DB_HOMOGRAPHY_TYPE_AFFINE:
+ case DB_HOMOGRAPHY_TYPE_PROJECTIVE:
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F:
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F_UD:
+ db_RobCamRotation_Polish_Generic(H_temp,db_mini(point_count,max_points),homography_type,x_i,xp_i,one_over_scale2,max_iterations);
+ break;
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION:
+ db_RobCamRotation_Polish(H_temp,db_mini(point_count,max_points),x_i,xp_i,one_over_scale2,max_iterations);
+ break;
+ }
+
+ }
+
+ }
+ else db_Identity3x3(H_temp);
+
+ switch(homography_type)
+ {
+ case DB_HOMOGRAPHY_TYPE_PROJECTIVE:
+ if(stat) stat->nr_parameters=8;
+ break;
+ case DB_HOMOGRAPHY_TYPE_AFFINE:
+ if(stat) stat->nr_parameters=6;
+ break;
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY:
+ case DB_HOMOGRAPHY_TYPE_SIMILARITY_U:
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F:
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION_F_UD:
+ if(stat) stat->nr_parameters=4;
+ break;
+ case DB_HOMOGRAPHY_TYPE_CAMROTATION:
+ if(stat) stat->nr_parameters=3;
+ break;
+ case DB_HOMOGRAPHY_TYPE_TRANSLATION:
+ case DB_HOMOGRAPHY_TYPE_S_T:
+ case DB_HOMOGRAPHY_TYPE_R_T:
+ case DB_HOMOGRAPHY_TYPE_R_S:
+ if(stat) stat->nr_parameters=2;
+ break;
+ case DB_HOMOGRAPHY_TYPE_ROTATION:
+ case DB_HOMOGRAPHY_TYPE_ROTATION_U:
+ case DB_HOMOGRAPHY_TYPE_SCALING:
+ if(stat) stat->nr_parameters=1;
+ break;
+ }
+
+ db_RobImageHomography_Statistics(H_temp,db_mini(point_count,max_points),x_i,xp_i,one_over_scale2,stat);
+
+ /*Put on the calibration matrices*/
+ db_Multiply3x3_3x3(H_temp2,H_temp,K_inv);
+ db_Multiply3x3_3x3(H,Kp,H_temp2);
+
+ if (finalNumE)
+ *finalNumE = point_count_new;
+
+}
diff --git a/jni/feature_stab/db_vlvm/db_rob_image_homography.h b/jni/feature_stab/db_vlvm/db_rob_image_homography.h
new file mode 100644
index 000000000..59cde7daa
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_rob_image_homography.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_rob_image_homography.h,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_ROB_IMAGE_HOMOGRAPHY
+#define DB_ROB_IMAGE_HOMOGRAPHY
+
+#include "db_utilities.h"
+#include "db_robust.h"
+#include "db_metrics.h"
+
+#include <stdlib.h> // for NULL
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMRobImageHomography (LM) Robust Image Homography
+ */
+/*\{*/
+
+#define DB_HOMOGRAPHY_TYPE_DEFAULT 0
+#define DB_HOMOGRAPHY_TYPE_PROJECTIVE 0
+#define DB_HOMOGRAPHY_TYPE_AFFINE 1
+#define DB_HOMOGRAPHY_TYPE_SIMILARITY 2
+#define DB_HOMOGRAPHY_TYPE_SIMILARITY_U 3
+#define DB_HOMOGRAPHY_TYPE_TRANSLATION 4
+#define DB_HOMOGRAPHY_TYPE_ROTATION 5
+#define DB_HOMOGRAPHY_TYPE_ROTATION_U 6
+#define DB_HOMOGRAPHY_TYPE_SCALING 7
+#define DB_HOMOGRAPHY_TYPE_S_T 8
+#define DB_HOMOGRAPHY_TYPE_R_T 9
+#define DB_HOMOGRAPHY_TYPE_R_S 10
+#define DB_HOMOGRAPHY_TYPE_CAMROTATION 11
+#define DB_HOMOGRAPHY_TYPE_CAMROTATION_F 12
+#define DB_HOMOGRAPHY_TYPE_CAMROTATION_F_UD 13
+
+/*!
+Solve for homography H such that xp~Hx
+\param H best homography
+
+2D point to 2D point constraints:
+
+\param im first image points
+\param im_p second image points
+\param nr_points number of points
+
+Calibration matrices:
+
+\param K first camera
+\param Kp second camera
+
+ Temporary space:
+
+ \param temp_d pre-allocated space of size 12*nr_samples+10*nr_points doubles
+ \param temp_i pre-allocated space of size max(nr_samples,nr_points) ints
+
+ Statistics for this estimation
+
+ \param stat NULL - do not compute
+
+ \param homography_type see DB_HOMOGRAPHY_TYPE_* definitions above
+
+ Estimation parameters:
+
+ \param max_iterations max number of polishing steps
+ \param max_points only use this many points
+ \param scale Cauchy scale coefficient (see db_ExpCauchyReprojectionError() )
+ \param nr_samples number of times to compute a hypothesis
+ \param chunk_size size of cost chunks
+*/
+DB_API void db_RobImageHomography(
+ /*Best homography*/
+ double H[9],
+ /*2DPoint to 2DPoint constraints
+ Points are assumed to be given in
+ homogenous coordinates*/
+ double *im,double *im_p,
+ /*Nr of points in total*/
+ int nr_points,
+ /*Calibration matrices
+ used to normalize the points*/
+ double K[9],
+ double Kp[9],
+ /*Pre-allocated space temp_d
+ should point to at least
+ 12*nr_samples+10*nr_points
+ allocated positions*/
+ double *temp_d,
+ /*Pre-allocated space temp_i
+ should point to at least
+ max(nr_samples,nr_points)
+ allocated positions*/
+ int *temp_i,
+ int homography_type=DB_HOMOGRAPHY_TYPE_DEFAULT,
+ db_Statistics *stat=NULL,
+ int max_iterations=DB_DEFAULT_MAX_ITERATIONS,
+ int max_points=DB_DEFAULT_MAX_POINTS,
+ double scale=DB_POINT_STANDARDDEV,
+ int nr_samples=DB_DEFAULT_NR_SAMPLES,
+ int chunk_size=DB_DEFAULT_CHUNK_SIZE,
+ ///////////////////////////////////////////////////
+ // flag for the outlier removal
+ int outlierremoveflagE = 0,
+ // if flag is 1, then the following variables
+ // need to input
+ ///////////////////////////////////////////////////
+ // 3D coordinates
+ double *wp=NULL,
+ // its corresponding stereo pair's points
+ double *im_r=NULL,
+ // raw image coordinates
+ double *im_raw=NULL, double *im_raw_p=NULL,
+ // final matches
+ int *final_NumE=0);
+
+DB_API double db_RobImageHomography_Cost(double H[9],int point_count,double *x_i,
+ double *xp_i,double one_over_scale2);
+
+
+DB_API void db_RobCamRotation_Polish(double H[9],int point_count,double *x_i,
+ double *xp_i, double one_over_scale2,
+ int max_iterations=DB_DEFAULT_MAX_ITERATIONS,
+ double improvement_requirement=DB_DEFAULT_IMP_REQ);
+
+
+DB_API void db_RobCamRotation_Polish_Generic(double H[9],int point_count,int homography_type,
+ double *x_i,double *xp_i,double one_over_scale2,
+ int max_iterations=DB_DEFAULT_MAX_ITERATIONS,
+ double improvement_requirement=DB_DEFAULT_IMP_REQ);
+
+
+#endif /* DB_ROB_IMAGE_HOMOGRAPHY */
diff --git a/jni/feature_stab/db_vlvm/db_robust.h b/jni/feature_stab/db_vlvm/db_robust.h
new file mode 100644
index 000000000..be0794c6e
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_robust.h
@@ -0,0 +1,61 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_robust.h,v 1.4 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_ROBUST
+#define DB_ROBUST
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMRobust (LM) Robust Estimation
+ */
+
+/*!
+ \struct db_Statistics
+ \ingroup LMRobust
+ \brief (LnM) Sampling problem statistics
+ \date Mon Sep 10 10:28:08 EDT 2007
+ \par Copyright: 2007 Sarnoff Corporation. All Rights Reserved
+ */
+ struct db_stat_struct
+ {
+ int nr_points;
+ int nr_inliers;
+ double inlier_fraction;
+ double cost;
+ double one_over_scale2;
+ double lambda1;
+ double lambda2;
+ double lambda3;
+ int nr_parameters;
+ int model_dimension;
+ double gric;
+ double inlier_evidence;
+ double posestd[6];
+ double rotationvecCov[9];
+ double translationvecCov[9];
+ int posecov_inliercount;
+ int posecovready;
+ double median_reprojection_error;
+ };
+ typedef db_stat_struct db_Statistics;
+
+#endif /* DB_ROBUST */
diff --git a/jni/feature_stab/db_vlvm/db_utilities.cpp b/jni/feature_stab/db_vlvm/db_utilities.cpp
new file mode 100644
index 000000000..ce2093b01
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities.cpp
@@ -0,0 +1,176 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities.cpp,v 1.4 2011/06/17 14:03:31 mbansal Exp $ */
+
+#include "db_utilities.h"
+#include <string.h>
+#include <stdio.h>
+
+float** db_SetupImageReferences_f(float *im,int w,int h)
+{
+ int i;
+ float **img;
+ assert(im);
+ img=new float* [h];
+ for(i=0;i<h;i++)
+ {
+ img[i]=im+w*i;
+ }
+ return(img);
+}
+
+unsigned char** db_SetupImageReferences_u(unsigned char *im,int w,int h)
+{
+ int i;
+ unsigned char **img;
+
+ assert(im);
+
+ img=new unsigned char* [h];
+ for(i=0;i<h;i++)
+ {
+ img[i]=im+w*i;
+ }
+ return(img);
+}
+float** db_AllocImage_f(int w,int h,int over_allocation)
+{
+ float **img,*im;
+
+ im=new float [w*h+over_allocation];
+ img=db_SetupImageReferences_f(im,w,h);
+
+ return(img);
+}
+
+unsigned char** db_AllocImage_u(int w,int h,int over_allocation)
+{
+ unsigned char **img,*im;
+
+ im=new unsigned char [w*h+over_allocation];
+ img=db_SetupImageReferences_u(im,w,h);
+
+ return(img);
+}
+
+void db_FreeImage_f(float **img,int h)
+{
+ delete [] (img[0]);
+ delete [] img;
+}
+
+void db_FreeImage_u(unsigned char **img,int h)
+{
+ delete [] (img[0]);
+ delete [] img;
+}
+
+// ----------------------------------------------------------------------------------------------------------- ;
+//
+// copy image (source to destination)
+// ---> must be a 2D image array with the same image size
+// ---> the size of the input and output images must be same
+//
+// ------------------------------------------------------------------------------------------------------------ ;
+void db_CopyImage_u(unsigned char **d,const unsigned char * const *s, int w, int h, int over_allocation)
+{
+ int i;
+
+ for (i=0;i<h;i++)
+ {
+ memcpy(d[i],s[i],w*sizeof(unsigned char));
+ }
+
+ memcpy(&d[h],&d[h],over_allocation);
+
+}
+
+inline void db_WarpImageLutFast_u(const unsigned char * const * src, unsigned char ** dst, int w, int h,
+ const float * const * lut_x, const float * const * lut_y)
+{
+ assert(src && dst);
+ int xd=0, yd=0;
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ //xd = static_cast<unsigned int>(lut_x[j][i]);
+ //yd = static_cast<unsigned int>(lut_y[j][i]);
+ xd = (unsigned int)(lut_x[j][i]);
+ yd = (unsigned int)(lut_y[j][i]);
+ if ( xd >= w || yd >= h ||
+ xd < 0 || yd < 0)
+ dst[j][i] = 0;
+ else
+ dst[j][i] = src[yd][xd];
+ }
+}
+
+inline void db_WarpImageLutBilinear_u(const unsigned char * const * src, unsigned char ** dst, int w, int h,
+ const float * const * lut_x,const float * const* lut_y)
+{
+ assert(src && dst);
+ double xd=0.0, yd=0.0;
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ xd = static_cast<double>(lut_x[j][i]);
+ yd = static_cast<double>(lut_y[j][i]);
+ if ( xd > w || yd > h ||
+ xd < 0.0 || yd < 0.0)
+ dst[j][i] = 0;
+ else
+ dst[j][i] = db_BilinearInterpolation(yd, xd, src);
+ }
+}
+
+
+void db_WarpImageLut_u(const unsigned char * const * src, unsigned char ** dst, int w, int h,
+ const float * const * lut_x,const float * const * lut_y, int type)
+{
+ switch (type)
+ {
+ case DB_WARP_FAST:
+ db_WarpImageLutFast_u(src,dst,w,h,lut_x,lut_y);
+ break;
+ case DB_WARP_BILINEAR:
+ db_WarpImageLutBilinear_u(src,dst,w,h,lut_x,lut_y);
+ break;
+ default:
+ break;
+ }
+}
+
+
+void db_PrintDoubleVector(double *a,long size)
+{
+ printf("[ ");
+ for(long i=0;i<size;i++) printf("%lf ",a[i]);
+ printf("]");
+}
+
+void db_PrintDoubleMatrix(double *a,long rows,long cols)
+{
+ printf("[\n");
+ for(long i=0;i<rows;i++)
+ {
+ for(long j=0;j<cols;j++) printf("%lf ",a[i*cols+j]);
+ printf("\n");
+ }
+ printf("]");
+}
diff --git a/jni/feature_stab/db_vlvm/db_utilities.h b/jni/feature_stab/db_vlvm/db_utilities.h
new file mode 100644
index 000000000..fa9c87745
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities.h
@@ -0,0 +1,571 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities.h,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_UTILITIES_H
+#define DB_UTILITIES_H
+
+
+#ifdef _WIN32
+#pragma warning(disable: 4275)
+#pragma warning(disable: 4251)
+#pragma warning(disable: 4786)
+#pragma warning(disable: 4800)
+#pragma warning(disable: 4018) /* signed-unsigned mismatch */
+#endif /* _WIN32 */
+
+#ifdef _WIN32
+ #ifdef DBDYNAMIC_EXPORTS
+ #define DB_API __declspec(dllexport)
+ #else
+ #ifdef DBDYNAMIC_IMPORTS
+ #define DB_API __declspec(dllimport)
+ #else
+ #define DB_API
+ #endif
+ #endif
+#else
+ #define DB_API
+#endif /* _WIN32 */
+
+#ifdef _VERBOSE_
+#include <iostream>
+#endif
+
+#include <math.h>
+
+#include <assert.h>
+#include "db_utilities_constants.h"
+/*!
+ * \defgroup LMBasicUtilities (LM) Utility Functions (basic math, linear algebra and array manipulations)
+ */
+/*\{*/
+
+/*!
+ * Round double into int using fld and fistp instructions.
+ */
+inline int db_roundi (double x) {
+#ifdef WIN32_ASM
+ int n;
+ __asm
+ {
+ fld x;
+ fistp n;
+ }
+ return n;
+#else
+ return static_cast<int>(floor(x+0.5));
+#endif
+}
+
+/*!
+ * Square a double.
+ */
+inline double db_sqr(double a)
+{
+ return(a*a);
+}
+
+/*!
+ * Square a long.
+ */
+inline long db_sqr(long a)
+{
+ return(a*a);
+}
+
+/*!
+ * Square an int.
+ */
+inline long db_sqr(int a)
+{
+ return(a*a);
+}
+
+/*!
+ * Maximum of two doubles.
+ */
+inline double db_maxd(double a,double b)
+{
+ if(b>a) return(b);
+ else return(a);
+}
+/*!
+ * Minumum of two doubles.
+ */
+inline double db_mind(double a,double b)
+{
+ if(b<a) return(b);
+ else return(a);
+}
+
+
+/*!
+ * Maximum of two ints.
+ */
+inline int db_maxi(int a,int b)
+{
+ if(b>a) return(b);
+ else return(a);
+}
+
+/*!
+ * Minimum of two numbers.
+ */
+inline int db_mini(int a,int b)
+{
+ if(b<a) return(b);
+ else return(a);
+}
+/*!
+ * Maximum of two numbers.
+ */
+inline long db_maxl(long a,long b)
+{
+ if(b>a) return(b);
+ else return(a);
+}
+
+/*!
+ * Minimum of two numbers.
+ */
+inline long db_minl(long a,long b)
+{
+ if(b<a) return(b);
+ else return(a);
+}
+
+/*!
+ * Sign of a number.
+ * \return -1.0 if negative, 1.0 if positive.
+ */
+inline double db_sign(double x)
+{
+ if(x>=0.0) return(1.0);
+ else return(-1.0);
+}
+/*!
+ * Absolute value.
+ */
+inline int db_absi(int a)
+{
+ if(a<0) return(-a);
+ else return(a);
+}
+/*!
+ * Absolute value.
+ */
+inline float db_absf(float a)
+{
+ if(a<0) return(-a);
+ else return(a);
+}
+
+/*!
+ * Absolute value.
+ */
+inline double db_absd(double a)
+{
+ if(a<0) return(-a);
+ else return(a);
+}
+
+/*!
+ * Reciprocal (1/a). Prevents divide by 0.
+ * \return 1/a if a != 0. 1.0 otherwise.
+ */
+inline double db_SafeReciprocal(double a)
+{
+ return((a!=0.0)?(1.0/a):1.0);
+}
+
+/*!
+ * Division. Prevents divide by 0.
+ * \return a/b if b!=0. a otherwise.
+ */
+inline double db_SafeDivision(double a,double b)
+{
+ return((b!=0.0)?(a/b):a);
+}
+
+/*!
+ * Square root. Prevents imaginary output.
+ * \return sqrt(a) if a > 0.0. 0.0 otherewise.
+ */
+inline double db_SafeSqrt(double a)
+{
+ return((a>=0.0)?(sqrt(a)):0.0);
+}
+
+/*!
+ * Square root of a reciprocal. Prevents divide by 0 and imaginary output.
+ * \return sqrt(1/a) if a > 0.0. 1.0 otherewise.
+ */
+inline double db_SafeSqrtReciprocal(double a)
+{
+ return((a>0.0)?(sqrt(1.0/a)):1.0);
+}
+/*!
+ * Cube root.
+ */
+inline double db_CubRoot(double x)
+{
+ if(x>=0.0) return(pow(x,1.0/3.0));
+ else return(-pow(-x,1.0/3.0));
+}
+/*!
+ * Sum of squares of elements of x.
+ */
+inline double db_SquareSum3(const double x[3])
+{
+ return(db_sqr(x[0])+db_sqr(x[1])+db_sqr(x[2]));
+}
+/*!
+ * Sum of squares of elements of x.
+ */
+inline double db_SquareSum7(double x[7])
+{
+ return(db_sqr(x[0])+db_sqr(x[1])+db_sqr(x[2])+
+ db_sqr(x[3])+db_sqr(x[4])+db_sqr(x[5])+
+ db_sqr(x[6]));
+}
+/*!
+ * Sum of squares of elements of x.
+ */
+inline double db_SquareSum9(double x[9])
+{
+ return(db_sqr(x[0])+db_sqr(x[1])+db_sqr(x[2])+
+ db_sqr(x[3])+db_sqr(x[4])+db_sqr(x[5])+
+ db_sqr(x[6])+db_sqr(x[7])+db_sqr(x[8]));
+}
+/*!
+ * Copy a vector.
+ * \param xd destination
+ * \param xs source
+ */
+void inline db_Copy3(double xd[3],const double xs[3])
+{
+ xd[0]=xs[0];xd[1]=xs[1];xd[2]=xs[2];
+}
+/*!
+ * Copy a vector.
+ * \param xd destination
+ * \param xs source
+ */
+void inline db_Copy6(double xd[6],const double xs[6])
+{
+ xd[0]=xs[0];xd[1]=xs[1];xd[2]=xs[2];
+ xd[3]=xs[3];xd[4]=xs[4];xd[5]=xs[5];
+}
+/*!
+ * Copy a vector.
+ * \param xd destination
+ * \param xs source
+ */
+void inline db_Copy9(double xd[9],const double xs[9])
+{
+ xd[0]=xs[0];xd[1]=xs[1];xd[2]=xs[2];
+ xd[3]=xs[3];xd[4]=xs[4];xd[5]=xs[5];
+ xd[6]=xs[6];xd[7]=xs[7];xd[8]=xs[8];
+}
+
+/*!
+ * Scalar product: Transpose(A)*B.
+ */
+inline double db_ScalarProduct4(const double A[4],const double B[4])
+{
+ return(A[0]*B[0]+A[1]*B[1]+A[2]*B[2]+A[3]*B[3]);
+}
+/*!
+ * Scalar product: Transpose(A)*B.
+ */
+inline double db_ScalarProduct7(const double A[7],const double B[7])
+{
+ return(A[0]*B[0]+A[1]*B[1]+A[2]*B[2]+
+ A[3]*B[3]+A[4]*B[4]+A[5]*B[5]+
+ A[6]*B[6]);
+}
+/*!
+ * Scalar product: Transpose(A)*B.
+ */
+inline double db_ScalarProduct9(const double A[9],const double B[9])
+{
+ return(A[0]*B[0]+A[1]*B[1]+A[2]*B[2]+
+ A[3]*B[3]+A[4]*B[4]+A[5]*B[5]+
+ A[6]*B[6]+A[7]*B[7]+A[8]*B[8]);
+}
+/*!
+ * Vector addition: S=A+B.
+ */
+inline void db_AddVectors6(double S[6],const double A[6],const double B[6])
+{
+ S[0]=A[0]+B[0]; S[1]=A[1]+B[1]; S[2]=A[2]+B[2]; S[3]=A[3]+B[3]; S[4]=A[4]+B[4];
+ S[5]=A[5]+B[5];
+}
+/*!
+ * Multiplication: C(3x1)=A(3x3)*B(3x1).
+ */
+inline void db_Multiply3x3_3x1(double y[3],const double A[9],const double x[3])
+{
+ y[0]=A[0]*x[0]+A[1]*x[1]+A[2]*x[2];
+ y[1]=A[3]*x[0]+A[4]*x[1]+A[5]*x[2];
+ y[2]=A[6]*x[0]+A[7]*x[1]+A[8]*x[2];
+}
+inline void db_Multiply3x3_3x3(double C[9], const double A[9],const double B[9])
+{
+ C[0]=A[0]*B[0]+A[1]*B[3]+A[2]*B[6];
+ C[1]=A[0]*B[1]+A[1]*B[4]+A[2]*B[7];
+ C[2]=A[0]*B[2]+A[1]*B[5]+A[2]*B[8];
+
+ C[3]=A[3]*B[0]+A[4]*B[3]+A[5]*B[6];
+ C[4]=A[3]*B[1]+A[4]*B[4]+A[5]*B[7];
+ C[5]=A[3]*B[2]+A[4]*B[5]+A[5]*B[8];
+
+ C[6]=A[6]*B[0]+A[7]*B[3]+A[8]*B[6];
+ C[7]=A[6]*B[1]+A[7]*B[4]+A[8]*B[7];
+ C[8]=A[6]*B[2]+A[7]*B[5]+A[8]*B[8];
+}
+/*!
+ * Multiplication: C(4x1)=A(4x4)*B(4x1).
+ */
+inline void db_Multiply4x4_4x1(double y[4],const double A[16],const double x[4])
+{
+ y[0]=A[0]*x[0]+A[1]*x[1]+A[2]*x[2]+A[3]*x[3];
+ y[1]=A[4]*x[0]+A[5]*x[1]+A[6]*x[2]+A[7]*x[3];
+ y[2]=A[8]*x[0]+A[9]*x[1]+A[10]*x[2]+A[11]*x[3];
+ y[3]=A[12]*x[0]+A[13]*x[1]+A[14]*x[2]+A[15]*x[3];
+}
+/*!
+ * Scalar multiplication in place: A(3)=mult*A(3).
+ */
+inline void db_MultiplyScalar3(double *A,double mult)
+{
+ (*A++) *= mult; (*A++) *= mult; (*A++) *= mult;
+}
+
+/*!
+ * Scalar multiplication: A(3)=mult*B(3).
+ */
+inline void db_MultiplyScalarCopy3(double *A,const double *B,double mult)
+{
+ (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult;
+}
+
+/*!
+ * Scalar multiplication: A(4)=mult*B(4).
+ */
+inline void db_MultiplyScalarCopy4(double *A,const double *B,double mult)
+{
+ (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult;
+}
+/*!
+ * Scalar multiplication: A(7)=mult*B(7).
+ */
+inline void db_MultiplyScalarCopy7(double *A,const double *B,double mult)
+{
+ (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult;
+ (*A++)=(*B++)*mult; (*A++)=(*B++)*mult;
+}
+/*!
+ * Scalar multiplication: A(9)=mult*B(9).
+ */
+inline void db_MultiplyScalarCopy9(double *A,const double *B,double mult)
+{
+ (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult;
+ (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult; (*A++)=(*B++)*mult;
+}
+
+/*!
+ * \defgroup LMImageBasicUtilities (LM) Basic Image Utility Functions
+
+ Images in db are simply 2D arrays of unsigned char or float types.
+ Only the very basic operations are supported: allocation/deallocation,
+copying, simple pyramid construction and LUT warping. These images are used
+by db_CornerDetector_u and db_Matcher_u. The db_Image class is an attempt
+to wrap these images. It has not been tested well.
+
+ */
+/*\{*/
+/*!
+ * Given a float image array, allocates and returns the set of row poiners.
+ * \param im image pointer
+ * \param w image width
+ * \param h image height
+ */
+DB_API float** db_SetupImageReferences_f(float *im,int w,int h);
+/*!
+ * Allocate a float image.
+ * Note: for feature detection images must be overallocated by 256 bytes.
+ * \param w width
+ * \param h height
+ * \param over_allocation allocate this many extra bytes at the end
+ * \return row array pointer
+ */
+DB_API float** db_AllocImage_f(int w,int h,int over_allocation=256);
+/*!
+ * Free a float image
+ * \param img row array pointer
+ * \param h image height (number of rows)
+ */
+DB_API void db_FreeImage_f(float **img,int h);
+/*!
+ * Given an unsigned char image array, allocates and returns the set of row poiners.
+ * \param im image pointer
+ * \param w image width
+ * \param h image height
+ */
+DB_API unsigned char** db_SetupImageReferences_u(unsigned char *im,int w,int h);
+/*!
+ * Allocate an unsigned char image.
+ * Note: for feature detection images must be overallocated by 256 bytes.
+ * \param w width
+ * \param h height
+ * \param over_allocation allocate this many extra bytes at the end
+ * \return row array pointer
+ */
+DB_API unsigned char** db_AllocImage_u(int w,int h,int over_allocation=256);
+/*!
+ * Free an unsigned char image
+ * \param img row array pointer
+ * \param h image height (number of rows)
+ */
+DB_API void db_FreeImage_u(unsigned char **img,int h);
+
+/*!
+ Copy an image from s to d. Both s and d must be pre-allocated at of the same size.
+ Copy is done row by row.
+ \param s source
+ \param d destination
+ \param w width
+ \param h height
+ \param over_allocation copy this many bytes after the end of the last line
+ */
+DB_API void db_CopyImage_u(unsigned char **d,const unsigned char * const *s,int w,int h,int over_allocation=0);
+
+DB_API inline unsigned char db_BilinearInterpolation(double y, double x, const unsigned char * const * v)
+{
+ int floor_x=(int) x;
+ int floor_y=(int) y;
+
+ int ceil_x=floor_x+1;
+ int ceil_y=floor_y+1;
+
+ unsigned char f00 = v[floor_y][floor_x];
+ unsigned char f01 = v[floor_y][ceil_x];
+ unsigned char f10 = v[ceil_y][floor_x];
+ unsigned char f11 = v[ceil_y][ceil_x];
+
+ double xl = x-floor_x;
+ double yl = y-floor_y;
+
+ return (unsigned char)(f00*(1-yl)*(1-xl) + f10*yl*(1-xl) + f01*(1-yl)*xl + f11*yl*xl);
+}
+/*\}*/
+/*!
+ * \ingroup LMRotation
+ * Compute an incremental rotation matrix using the update dx=[sin(phi) sin(ohm) sin(kap)]
+ */
+inline void db_IncrementalRotationMatrix(double R[9],const double dx[3])
+{
+ double sp,so,sk,om_sp2,om_so2,om_sk2,cp,co,ck,sp_so,cp_so;
+
+ /*Store sines*/
+ sp=dx[0]; so=dx[1]; sk=dx[2];
+ om_sp2=1.0-sp*sp;
+ om_so2=1.0-so*so;
+ om_sk2=1.0-sk*sk;
+ /*Compute cosines*/
+ cp=(om_sp2>=0.0)?sqrt(om_sp2):1.0;
+ co=(om_so2>=0.0)?sqrt(om_so2):1.0;
+ ck=(om_sk2>=0.0)?sqrt(om_sk2):1.0;
+ /*Compute matrix*/
+ sp_so=sp*so;
+ cp_so=cp*so;
+ R[0]=sp_so*sk+cp*ck; R[1]=co*sk; R[2]=cp_so*sk-sp*ck;
+ R[3]=sp_so*ck-cp*sk; R[4]=co*ck; R[5]=cp_so*ck+sp*sk;
+ R[6]=sp*co; R[7]= -so; R[8]=cp*co;
+}
+/*!
+ * Zero out 2 vector in place.
+ */
+void inline db_Zero2(double x[2])
+{
+ x[0]=x[1]=0;
+}
+/*!
+ * Zero out 3 vector in place.
+ */
+void inline db_Zero3(double x[3])
+{
+ x[0]=x[1]=x[2]=0;
+}
+/*!
+ * Zero out 4 vector in place.
+ */
+void inline db_Zero4(double x[4])
+{
+ x[0]=x[1]=x[2]=x[3]=0;
+}
+/*!
+ * Zero out 9 vector in place.
+ */
+void inline db_Zero9(double x[9])
+{
+ x[0]=x[1]=x[2]=x[3]=x[4]=x[5]=x[6]=x[7]=x[8]=0;
+}
+
+#define DB_WARP_FAST 0
+#define DB_WARP_BILINEAR 1
+
+/*!
+ * Perform a look-up table warp.
+ * The LUTs must be float images of the same size as source image.
+ * The source value x_s is determined from destination (x_d,y_d) through lut_x
+ * and y_s is determined from lut_y:
+ \code
+ x_s = lut_x[y_d][x_d];
+ y_s = lut_y[y_d][x_d];
+ \endcode
+
+ * \param src source image
+ * \param dst destination image
+ * \param w width
+ * \param h height
+ * \param lut_x LUT for x
+ * \param lut_y LUT for y
+ * \param type warp type (DB_WARP_FAST or DB_WARP_BILINEAR)
+ */
+DB_API void db_WarpImageLut_u(const unsigned char * const * src,unsigned char ** dst, int w, int h,
+ const float * const * lut_x, const float * const * lut_y, int type=DB_WARP_BILINEAR);
+
+DB_API void db_PrintDoubleVector(double *a,long size);
+DB_API void db_PrintDoubleMatrix(double *a,long rows,long cols);
+
+#include "db_utilities_constants.h"
+#include "db_utilities_algebra.h"
+#include "db_utilities_indexing.h"
+#include "db_utilities_linalg.h"
+#include "db_utilities_poly.h"
+#include "db_utilities_geometry.h"
+#include "db_utilities_random.h"
+#include "db_utilities_rotation.h"
+#include "db_utilities_camera.h"
+
+#define DB_INVALID (-1)
+
+
+#endif /* DB_UTILITIES_H */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_algebra.h b/jni/feature_stab/db_vlvm/db_utilities_algebra.h
new file mode 100644
index 000000000..2aedd74d5
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_algebra.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_algebra.h,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_UTILITIES_ALGEBRA
+#define DB_UTILITIES_ALGEBRA
+
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMAlgebra (LM) Algebra utilities
+ */
+/*\{*/
+
+inline void db_HomogenousNormalize3(double *x)
+{
+ db_MultiplyScalar3(x,db_SafeSqrtReciprocal(db_SquareSum3(x)));
+}
+
+/*\}*/
+
+#endif /* DB_UTILITIES_ALGEBRA */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_camera.cpp b/jni/feature_stab/db_vlvm/db_utilities_camera.cpp
new file mode 100644
index 000000000..dceba9b62
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_camera.cpp
@@ -0,0 +1,50 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_camera.cpp,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#include "db_utilities_camera.h"
+#include "db_utilities.h"
+#include <assert.h>
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+void db_Approx3DCalMat(double K[9],double Kinv[9],int im_width,int im_height,double f_correction,int field)
+{
+ double iw,ih,av_size,field_fact;
+
+ if(field) field_fact=2.0;
+ else field_fact=1.0;
+
+ iw=(double)im_width;
+ ih=(double)(im_height*field_fact);
+ av_size=(iw+ih)/2.0;
+ K[0]=f_correction*av_size;
+ K[1]=0;
+ K[2]=iw/2.0;
+ K[3]=0;
+ K[4]=f_correction*av_size/field_fact;
+ K[5]=ih/2.0/field_fact;
+ K[6]=0;
+ K[7]=0;
+ K[8]=1;
+
+ db_InvertCalibrationMatrix(Kinv,K);
+}
diff --git a/jni/feature_stab/db_vlvm/db_utilities_camera.h b/jni/feature_stab/db_vlvm/db_utilities_camera.h
new file mode 100644
index 000000000..26ba4420a
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_camera.h
@@ -0,0 +1,332 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_camera.h,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_UTILITIES_CAMERA
+#define DB_UTILITIES_CAMERA
+
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMCamera (LM) Camera Utilities
+ */
+/*\{*/
+
+#include "db_utilities.h"
+
+#define DB_RADDISTMODE_BOUGEUT 4
+#define DB_RADDISTMODE_2NDORDER 5
+#define DB_RADDISTMODE_IDENTITY 6
+
+/*!
+Give reasonable guess of the calibration matrix for normalization purposes.
+Use real K matrix when doing real geometry.
+focal length = (w+h)/2.0*f_correction.
+\param K calibration matrix (out)
+\param Kinv inverse of K (out)
+\param im_width image width
+\param im_height image height
+\param f_correction focal length correction factor
+\param field set to 1 if this is a field image (fy = fx/2)
+\return K(3x3) intrinsic calibration matrix
+*/
+DB_API void db_Approx3DCalMat(double K[9],double Kinv[9],int im_width,int im_height,double f_correction=1.0,int field=0);
+
+/*!
+ Make a 2x2 identity matrix
+ */
+void inline db_Identity2x2(double A[4])
+{
+ A[0]=1;A[1]=0;
+ A[2]=0;A[3]=1;
+}
+/*!
+ Make a 3x3 identity matrix
+ */
+void inline db_Identity3x3(double A[9])
+{
+ A[0]=1;A[1]=0;A[2]=0;
+ A[3]=0;A[4]=1;A[5]=0;
+ A[6]=0;A[7]=0;A[8]=1;
+}
+/*!
+ Invert intrinsic calibration matrix K(3x3)
+ If fx or fy is 0, I is returned.
+ */
+void inline db_InvertCalibrationMatrix(double Kinv[9],const double K[9])
+{
+ double a,b,c,d,e,f,ainv,dinv,adinv;
+
+ a=K[0];b=K[1];c=K[2];d=K[4];e=K[5];f=K[8];
+ if((a==0.0)||(d==0.0)) db_Identity3x3(Kinv);
+ else
+ {
+ Kinv[3]=0.0;
+ Kinv[6]=0.0;
+ Kinv[7]=0.0;
+ Kinv[8]=1.0;
+
+ ainv=1.0/a;
+ dinv=1.0/d;
+ adinv=ainv*dinv;
+ Kinv[0]=f*ainv;
+ Kinv[1]= -b*f*adinv;
+ Kinv[2]=(b*e-c*d)*adinv;
+ Kinv[4]=f*dinv;
+ Kinv[5]= -e*dinv;
+ }
+}
+/*!
+ De-homogenize image point: xd(1:2) = xs(1:2)/xs(3).
+ If xs(3) is 0, xd will become 0
+ \param xd destination point
+ \param xs source point
+ */
+void inline db_DeHomogenizeImagePoint(double xd[2],const double xs[3])
+{
+ double temp,div;
+
+ temp=xs[2];
+ if(temp!=0)
+ {
+ div=1.0/temp;
+ xd[0]=xs[0]*div;xd[1]=xs[1]*div;
+ }
+ else
+ {
+ xd[0]=0.0;xd[1]=0.0;
+ }
+}
+
+
+/*!
+ Orthonormalize 3D rotation R
+ */
+inline void db_OrthonormalizeRotation(double R[9])
+{
+ double s,mult;
+ /*Normalize first vector*/
+ s=db_sqr(R[0])+db_sqr(R[1])+db_sqr(R[2]);
+ mult=sqrt(1.0/(s?s:1));
+ R[0]*=mult; R[1]*=mult; R[2]*=mult;
+ /*Subtract scalar product from second vector*/
+ s=R[0]*R[3]+R[1]*R[4]+R[2]*R[5];
+ R[3]-=s*R[0]; R[4]-=s*R[1]; R[5]-=s*R[2];
+ /*Normalize second vector*/
+ s=db_sqr(R[3])+db_sqr(R[4])+db_sqr(R[5]);
+ mult=sqrt(1.0/(s?s:1));
+ R[3]*=mult; R[4]*=mult; R[5]*=mult;
+ /*Get third vector by vector product*/
+ R[6]=R[1]*R[5]-R[4]*R[2];
+ R[7]=R[2]*R[3]-R[5]*R[0];
+ R[8]=R[0]*R[4]-R[3]*R[1];
+}
+/*!
+Update a rotation with the update dx=[sin(phi) sin(ohm) sin(kap)]
+*/
+inline void db_UpdateRotation(double R_p_dx[9],double R[9],const double dx[3])
+{
+ double R_temp[9];
+ /*Update rotation*/
+ db_IncrementalRotationMatrix(R_temp,dx);
+ db_Multiply3x3_3x3(R_p_dx,R_temp,R);
+}
+/*!
+ Compute xp = Hx for inhomogenous image points.
+ */
+inline void db_ImageHomographyInhomogenous(double xp[2],const double H[9],const double x[2])
+{
+ double x3,m;
+
+ x3=H[6]*x[0]+H[7]*x[1]+H[8];
+ if(x3!=0.0)
+ {
+ m=1.0/x3;
+ xp[0]=m*(H[0]*x[0]+H[1]*x[1]+H[2]);
+ xp[1]=m*(H[3]*x[0]+H[4]*x[1]+H[5]);
+ }
+ else
+ {
+ xp[0]=xp[1]=0.0;
+ }
+}
+inline double db_FocalFromCamRotFocalHomography(const double H[9])
+{
+ double k1,k2;
+
+ k1=db_sqr(H[2])+db_sqr(H[5]);
+ k2=db_sqr(H[6])+db_sqr(H[7]);
+ if(k1>=k2)
+ {
+ return(db_SafeSqrt(db_SafeDivision(k1,1.0-db_sqr(H[8]))));
+ }
+ else
+ {
+ return(db_SafeSqrt(db_SafeDivision(1.0-db_sqr(H[8]),k2)));
+ }
+}
+
+inline double db_FocalAndRotFromCamRotFocalHomography(double R[9],const double H[9])
+{
+ double back,fi;
+
+ back=db_FocalFromCamRotFocalHomography(H);
+ fi=db_SafeReciprocal(back);
+ R[0]=H[0]; R[1]=H[1]; R[2]=fi*H[2];
+ R[3]=H[3]; R[4]=H[4]; R[5]=fi*H[5];
+ R[6]=back*H[6]; R[7]=back*H[7]; R[8]=H[8];
+ return(back);
+}
+/*!
+Compute Jacobian at zero of three coordinates dR*x with
+respect to the update dR([sin(phi) sin(ohm) sin(kap)]) given x.
+
+The Jacobian at zero of the homogenous coordinates with respect to
+ [sin(phi) sin(ohm) sin(kap)] is
+\code
+ [-rx2 0 rx1 ]
+ [ 0 rx2 -rx0 ]
+ [ rx0 -rx1 0 ].
+\endcode
+
+*/
+inline void db_JacobianOfRotatedPointStride(double J[9],const double x[3],int stride)
+{
+ /*The Jacobian at zero of the homogenous coordinates with respect to
+ [sin(phi) sin(ohm) sin(kap)] is
+ [-rx2 0 rx1 ]
+ [ 0 rx2 -rx0 ]
+ [ rx0 -rx1 0 ]*/
+
+ J[0]= -x[stride<<1];
+ J[1]=0;
+ J[2]= x[stride];
+ J[3]=0;
+ J[4]= x[stride<<1];
+ J[5]= -x[0];
+ J[6]= x[0];
+ J[7]= -x[stride];
+ J[8]=0;
+}
+/*!
+ Invert an affine (if possible)
+ \param Hinv inverted matrix
+ \param H input matrix
+ \return true if success and false if matrix is ill-conditioned (det < 1e-7)
+ */
+inline bool db_InvertAffineTransform(double Hinv[9],const double H[9])
+{
+ double det=H[0]*H[4]-H[3]*H[1];
+ if (det<1e-7)
+ {
+ db_Copy9(Hinv,H);
+ return false;
+ }
+ else
+ {
+ Hinv[0]=H[4]/det;
+ Hinv[1]=-H[1]/det;
+ Hinv[3]=-H[3]/det;
+ Hinv[4]=H[0]/det;
+ Hinv[2]= -Hinv[0]*H[2]-Hinv[1]*H[5];
+ Hinv[5]= -Hinv[3]*H[2]-Hinv[4]*H[5];
+ }
+ return true;
+}
+
+/*!
+Update of upper 2x2 is multiplication by
+\code
+[s 0][ cos(theta) sin(theta)]
+[0 s][-sin(theta) cos(theta)]
+\endcode
+*/
+inline void db_MultiplyScaleOntoImageHomography(double H[9],double s)
+{
+
+ H[0]*=s;
+ H[1]*=s;
+ H[3]*=s;
+ H[4]*=s;
+}
+/*!
+Update of upper 2x2 is multiplication by
+\code
+[s 0][ cos(theta) sin(theta)]
+[0 s][-sin(theta) cos(theta)]
+\endcode
+*/
+inline void db_MultiplyRotationOntoImageHomography(double H[9],double theta)
+{
+ double c,s,H0,H1;
+
+
+ c=cos(theta);
+ s=db_SafeSqrt(1.0-db_sqr(c));
+ H0= c*H[0]+s*H[3];
+ H[3]= -s*H[0]+c*H[3];
+ H[0]=H0;
+ H1=c*H[1]+s*H[4];
+ H[4]= -s*H[1]+c*H[4];
+ H[1]=H1;
+}
+
+inline void db_UpdateImageHomographyAffine(double H_p_dx[9],const double H[9],const double dx[6])
+{
+ db_AddVectors6(H_p_dx,H,dx);
+ db_Copy3(H_p_dx+6,H+6);
+}
+
+inline void db_UpdateImageHomographyProjective(double H_p_dx[9],const double H[9],const double dx[8],int frozen_coord)
+{
+ int i,j;
+
+ for(j=0,i=0;i<9;i++)
+ {
+ if(i!=frozen_coord)
+ {
+ H_p_dx[i]=H[i]+dx[j];
+ j++;
+ }
+ else H_p_dx[i]=H[i];
+ }
+}
+
+inline void db_UpdateRotFocalHomography(double H_p_dx[9],const double H[9],const double dx[4])
+{
+ double f,fp,fpi;
+ double R[9],dR[9];
+
+ /*Updated matrix is diag(f+df,f+df)*dR*R*diag(1/(f+df),1/(f+df),1)*/
+ f=db_FocalAndRotFromCamRotFocalHomography(R,H);
+ db_IncrementalRotationMatrix(dR,dx);
+ db_Multiply3x3_3x3(H_p_dx,dR,R);
+ fp=f+dx[3];
+ fpi=db_SafeReciprocal(fp);
+ H_p_dx[2]*=fp;
+ H_p_dx[5]*=fp;
+ H_p_dx[6]*=fpi;
+ H_p_dx[7]*=fpi;
+}
+
+/*\}*/
+#endif /* DB_UTILITIES_CAMERA */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_constants.h b/jni/feature_stab/db_vlvm/db_utilities_constants.h
new file mode 100644
index 000000000..07565efd2
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_constants.h
@@ -0,0 +1,208 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_constants.h,v 1.2 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_UTILITIES_CONSTANTS
+#define DB_UTILITIES_CONSTANTS
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+/****************Constants********************/
+#define DB_E 2.7182818284590452354
+#define DB_LOG2E 1.4426950408889634074
+#define DB_LOG10E 0.43429448190325182765
+#define DB_LN2 0.69314718055994530942
+#define DB_LN10 2.30258509299404568402
+#define DB_PI 3.1415926535897932384626433832795
+#define DB_PI_2 1.57079632679489661923
+#define DB_PI_4 0.78539816339744830962
+#define DB_1_PI 0.31830988618379067154
+#define DB_2_PI 0.63661977236758134308
+#define DB_SQRTPI 1.7724538509055160272981674833411
+#define DB_SQRT_2PI 2.506628274631000502415765284811
+#define DB_2_SQRTPI 1.12837916709551257390
+#define DB_SQRT2 1.41421356237309504880
+#define DB_SQRT3 1.7320508075688772935274463415059
+#define DB_SQRT1_2 0.70710678118654752440
+#define DB_EPS 2.220446049250313e-016 /* for 32 bit double */
+
+/****************Default Parameters********************/
+/*Preemptive ransac parameters*/
+#define DB_DEFAULT_NR_SAMPLES 500
+#define DB_DEFAULT_CHUNK_SIZE 100
+#define DB_DEFAULT_GROUP_SIZE 10
+
+/*Optimisation parameters*/
+#define DB_DEFAULT_MAX_POINTS 1000
+#define DB_DEFAULT_MAX_ITERATIONS 25
+#define DB_DEFAULT_IMP_REQ 0.001
+
+/*Feature standard deviation parameters*/
+#define DB_POINT_STANDARDDEV (1.0/(826.0)) /*1 pixel for CIF (fraction of (image width+image height)/2)*/
+#define DB_OUTLIER_THRESHOLD 3.0 /*In number of DB_POINT_STANDARDDEV's*/
+#define DB_WORST_CASE 50.0 /*In number of DB_POINT_STANDARDDEV's*/
+
+/*Front-end parameters*/
+#define DB_DEFAULT_TARGET_NR_CORNERS 5000
+#define DB_DEFAULT_NR_FEATURE_BLOCKS 10
+#define DB_DEFAULT_ABS_CORNER_THRESHOLD 50000000.0
+#define DB_DEFAULT_REL_CORNER_THRESHOLD 0.00005
+#define DB_DEFAULT_MAX_DISPARITY 0.1
+#define DB_DEFAULT_NO_DISPARITY -1.0
+#define DB_DEFAULT_MAX_TRACK_LENGTH 300
+
+#define DB_DEFAULT_MAX_NR_CAMERAS 1000
+
+#define DB_DEFAULT_TRIPLE_STEP 2
+#define DB_DEFAULT_DOUBLE_STEP 2
+#define DB_DEFAULT_SINGLE_STEP 1
+#define DB_DEFAULT_NR_SINGLES 10
+#define DB_DEFAULT_NR_DOUBLES 1
+#define DB_DEFAULT_NR_TRIPLES 1
+
+#define DB_DEFAULT_TRIFOCAL_FOUR_STEPS 40
+
+#define DB_DEFAULT_EPIPOLAR_ERROR 1 /*in pixels*/
+
+////////////////////////// DOXYGEN /////////////////////
+
+/*!
+ * \def DB_DEFAULT_GROUP_SIZE
+ * \ingroup LMRobust
+ * \brief Default group size for db_PreemptiveRansac class.
+ * Group size is the number of observation costs multiplied together
+ * before a log of the product is added to the total cost.
+*/
+
+/*!
+ * \def DB_DEFAULT_TARGET_NR_CORNERS
+ * \ingroup FeatureDetection
+ * \brief Default target number of corners
+*/
+/*!
+ * \def DB_DEFAULT_NR_FEATURE_BLOCKS
+ * \ingroup FeatureDetection
+ * \brief Default number of regions (horizontal or vertical) that are considered separately
+ * for feature detection. The greater the number, the more uniform the distribution of
+ * detected features.
+*/
+/*!
+ * \def DB_DEFAULT_ABS_CORNER_THRESHOLD
+ * \ingroup FeatureDetection
+ * \brief Absolute feature strength threshold.
+*/
+/*!
+ * \def DB_DEFAULT_REL_CORNER_THRESHOLD
+ * \ingroup FeatureDetection
+ * \brief Relative feature strength threshold.
+*/
+/*!
+ * \def DB_DEFAULT_MAX_DISPARITY
+ * \ingroup FeatureMatching
+ * \brief Maximum disparity (as fraction of image size) allowed in feature matching
+*/
+ /*!
+ * \def DB_DEFAULT_NO_DISPARITY
+ * \ingroup FeatureMatching
+ * \brief Indicates that vertical disparity is the same as horizontal disparity.
+*/
+///////////////////////////////////////////////////////////////////////////////////
+ /*!
+ * \def DB_E
+ * \ingroup LMBasicUtilities
+ * \brief e
+*/
+ /*!
+ * \def DB_LOG2E
+ * \ingroup LMBasicUtilities
+ * \brief log2(e)
+*/
+ /*!
+ * \def DB_LOG10E
+ * \ingroup LMBasicUtilities
+ * \brief log10(e)
+*/
+ /*!
+ * \def DB_LOG10E
+ * \ingroup LMBasicUtilities
+ * \brief log10(e)
+*/
+/*!
+ * \def DB_LN2
+ * \ingroup LMBasicUtilities
+ * \brief ln(2)
+*/
+/*!
+ * \def DB_LN10
+ * \ingroup LMBasicUtilities
+ * \brief ln(10)
+*/
+/*!
+ * \def DB_PI
+ * \ingroup LMBasicUtilities
+ * \brief Pi
+*/
+/*!
+ * \def DB_PI_2
+ * \ingroup LMBasicUtilities
+ * \brief Pi/2
+*/
+/*!
+ * \def DB_PI_4
+ * \ingroup LMBasicUtilities
+ * \brief Pi/4
+*/
+/*!
+ * \def DB_1_PI
+ * \ingroup LMBasicUtilities
+ * \brief 1/Pi
+*/
+/*!
+ * \def DB_2_PI
+ * \ingroup LMBasicUtilities
+ * \brief 2/Pi
+*/
+/*!
+ * \def DB_SQRTPI
+ * \ingroup LMBasicUtilities
+ * \brief sqrt(Pi)
+*/
+/*!
+ * \def DB_SQRT_2PI
+ * \ingroup LMBasicUtilities
+ * \brief sqrt(2*Pi)
+*/
+/*!
+ * \def DB_SQRT2
+ * \ingroup LMBasicUtilities
+ * \brief sqrt(2)
+*/
+/*!
+ * \def DB_SQRT3
+ * \ingroup LMBasicUtilities
+ * \brief sqrt(3)
+*/
+/*!
+ * \def DB_SQRT1_2
+ * \ingroup LMBasicUtilities
+ * \brief sqrt(1/2)
+*/
+#endif /* DB_UTILITIES_CONSTANTS */
+
+
diff --git a/jni/feature_stab/db_vlvm/db_utilities_geometry.h b/jni/feature_stab/db_vlvm/db_utilities_geometry.h
new file mode 100644
index 000000000..f21558467
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_geometry.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_geometry.h,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_UTILITIES_GEOMETRY_H
+#define DB_UTILITIES_GEOMETRY_H
+
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*! Get the inhomogenous 2D-point centroid of nr_point inhomogenous
+points in X*/
+inline void db_PointCentroid2D(double c[2],const double *X,int nr_points)
+{
+ int i;
+ double cx,cy,m;
+
+ cx=0;cy=0;
+ for(i=0;i<nr_points;i++)
+ {
+ cx+= *X++;
+ cy+= *X++;
+ }
+ if(nr_points)
+ {
+ m=1.0/((double)nr_points);
+ c[0]=cx*m;
+ c[1]=cy*m;
+ }
+ else c[0]=c[1]=0;
+}
+
+inline void db_PointCentroid2D(double c[2],const double * const *X,int nr_points)
+{
+ int i;
+ double cx,cy,m;
+ const double *temp;
+
+ cx=0;cy=0;
+ for(i=0;i<nr_points;i++)
+ {
+ temp= *X++;
+ cx+=temp[0];
+ cy+=temp[1];
+ }
+ if(nr_points)
+ {
+ m=1.0/((double)nr_points);
+ c[0]=cx*m;
+ c[1]=cy*m;
+ }
+ else c[0]=c[1]=0;
+}
+
+/*! Get the inhomogenous 3D-point centroid of nr_point inhomogenous
+points in X*/
+inline void db_PointCentroid3D(double c[3],const double *X,int nr_points)
+{
+ int i;
+ double cx,cy,cz,m;
+
+ cx=0;cy=0;cz=0;
+ for(i=0;i<nr_points;i++)
+ {
+ cx+= *X++;
+ cy+= *X++;
+ cz+= *X++;
+ }
+ if(nr_points)
+ {
+ m=1.0/((double)nr_points);
+ c[0]=cx*m;
+ c[1]=cy*m;
+ c[2]=cz*m;
+ }
+ else c[0]=c[1]=c[2]=0;
+}
+
+inline void db_PointCentroid3D(double c[3],const double * const *X,int nr_points)
+{
+ int i;
+ double cx,cy,cz,m;
+ const double *temp;
+
+ cx=0;cy=0;cz=0;
+ for(i=0;i<nr_points;i++)
+ {
+ temp= *X++;
+ cx+=temp[0];
+ cy+=temp[1];
+ cz+=temp[2];
+ }
+ if(nr_points)
+ {
+ m=1.0/((double)nr_points);
+ c[0]=cx*m;
+ c[1]=cy*m;
+ c[2]=cz*m;
+ }
+ else c[0]=c[1]=c[2]=0;
+}
+
+#endif /* DB_UTILITIES_GEOMETRY_H */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_indexing.cpp b/jni/feature_stab/db_vlvm/db_utilities_indexing.cpp
new file mode 100644
index 000000000..30ce03aa6
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_indexing.cpp
@@ -0,0 +1,120 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_indexing.cpp,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#include "db_utilities_indexing.h"
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+void db_Zero(double *d,long nr)
+{
+ long i;
+ for(i=0;i<nr;i++) d[i]=0.0;
+}
+
+/*This routine breaks number in source into values smaller and larger than
+a pivot element. Values equal to the pivot are ignored*/
+void db_LeanPartitionOnPivot(double pivot,double *dest,const double *source,long first,long last,long *first_equal,long *last_equal)
+{
+ double temp;
+ const double *s_point;
+ const double *s_top;
+ double *d_bottom;
+ double *d_top;
+
+ s_point=source+first;
+ s_top=source+last;
+ d_bottom=dest+first;
+ d_top=dest+last;
+
+ for(;s_point<=s_top;)
+ {
+ temp= *(s_point++);
+ if(temp<pivot) *(d_bottom++)=temp;
+ else if(temp>pivot) *(d_top--)=temp;
+ }
+ *first_equal=d_bottom-dest;
+ *last_equal=d_top-dest;
+}
+
+double db_LeanQuickSelect(const double *s,long nr_elements,long pos,double *temp)
+{
+ long first=0;
+ long last=nr_elements-1;
+ double pivot;
+ long first_equal,last_equal;
+ double *tempA;
+ double *tempB;
+ double *tempC;
+ const double *source;
+ double *dest;
+
+ tempA=temp;
+ tempB=temp+nr_elements;
+ source=s;
+ dest=tempA;
+
+ for(;last-first>2;)
+ {
+ pivot=db_TripleMedian(source[first],source[last],source[(first+last)/2]);
+ db_LeanPartitionOnPivot(pivot,dest,source,first,last,&first_equal,&last_equal);
+
+ if(first_equal>pos) last=first_equal-1;
+ else if(last_equal<pos) first=last_equal+1;
+ else
+ {
+ return(pivot);
+ }
+
+ /*Swap pointers*/
+ tempC=tempA;
+ tempA=tempB;
+ tempB=tempC;
+ source=tempB;
+ dest=tempA;
+ }
+ pivot=db_TripleMedian(source[first],source[last],source[(first+last)/2]);
+
+ return(pivot);
+}
+
+float* db_AlignPointer_f(float *p,unsigned long nr_bytes)
+{
+ float *ap;
+ unsigned long m;
+
+ m=((unsigned long)p)%nr_bytes;
+ if(m) ap=(float*) (((unsigned long)p)-m+nr_bytes);
+ else ap=p;
+ return(ap);
+}
+
+short* db_AlignPointer_s(short *p,unsigned long nr_bytes)
+{
+ short *ap;
+ unsigned long m;
+
+ m=((unsigned long)p)%nr_bytes;
+ if(m) ap=(short*) (((unsigned long)p)-m+nr_bytes);
+ else ap=p;
+ return(ap);
+}
diff --git a/jni/feature_stab/db_vlvm/db_utilities_indexing.h b/jni/feature_stab/db_vlvm/db_utilities_indexing.h
new file mode 100644
index 000000000..01eeb9ea2
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_indexing.h
@@ -0,0 +1,270 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_indexing.h,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_UTILITIES_INDEXING
+#define DB_UTILITIES_INDEXING
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+#include "db_utilities.h"
+
+/*!
+ * \defgroup LMIndexing (LM) Indexing Utilities (Order Statistics, Matrix Operations)
+ */
+/*\{*/
+
+inline void db_SetupMatrixRefs(double **ar,long rows,long cols,double *a)
+{
+ long i;
+ for(i=0;i<rows;i++) ar[i]=&a[i*cols];
+}
+
+inline void db_SymmetricExtendUpperToLower(double **A,int rows,int cols)
+{
+ int i,j;
+ for(i=1;i<rows;i++) for(j=0;j<i;j++) A[i][j]=A[j][i];
+}
+
+void inline db_MultiplyMatrixVectorAtb(double *c,const double * const *At,const double *b,int arows,int acols)
+{
+ int i,j;
+ double acc;
+
+ for(i=0;i<arows;i++)
+ {
+ acc=0;
+ for(j=0;j<acols;j++) acc+=At[j][i]*b[j];
+ c[i]=acc;
+ }
+}
+
+inline void db_MultiplyMatricesAB(double **C,const double * const *A,const double * const *B,int arows,int acols,int bcols)
+{
+ int i,j,k;
+ double acc;
+
+ for(i=0;i<arows;i++) for(j=0;j<bcols;j++)
+ {
+ acc=0;
+ for(k=0;k<acols;k++) acc+=A[i][k]*B[k][j];
+ C[i][j]=acc;
+ }
+}
+
+inline void db_UpperMultiplyMatricesAtB(double **Cu,const double * const *At,const double * const *B,int arows,int acols,int bcols)
+{
+ int i,j,k;
+ double acc;
+
+ for(i=0;i<arows;i++) for(j=i;j<bcols;j++)
+ {
+ acc=0;
+ for(k=0;k<acols;k++) acc+=At[k][i]*B[k][j];
+ Cu[i][j]=acc;
+ }
+}
+
+DB_API void db_Zero(double *d,long nr);
+
+inline int db_MaxIndex2(double s[2])
+{
+ if(s[0]>=s[1]) return(0);
+ return(1);
+}
+
+inline int db_MaxIndex3(const double s[3])
+{
+ double best;
+ int pos;
+
+ best=s[0];pos=0;
+ if(s[1]>best){best=s[1];pos=1;}
+ if(s[2]>best){best=s[2];pos=2;}
+ return(pos);
+}
+
+inline int db_MaxIndex4(const double s[4])
+{
+ double best;
+ int pos;
+
+ best=s[0];pos=0;
+ if(s[1]>best){best=s[1];pos=1;}
+ if(s[2]>best){best=s[2];pos=2;}
+ if(s[3]>best){best=s[3];pos=3;}
+ return(pos);
+}
+
+inline int db_MaxIndex5(const double s[5])
+{
+ double best;
+ int pos;
+
+ best=s[0];pos=0;
+ if(s[1]>best){best=s[1];pos=1;}
+ if(s[2]>best){best=s[2];pos=2;}
+ if(s[3]>best){best=s[3];pos=3;}
+ if(s[4]>best){best=s[4];pos=4;}
+ return(pos);
+}
+
+inline int db_MaxIndex6(const double s[6])
+{
+ double best;
+ int pos;
+
+ best=s[0];pos=0;
+ if(s[1]>best){best=s[1];pos=1;}
+ if(s[2]>best){best=s[2];pos=2;}
+ if(s[3]>best){best=s[3];pos=3;}
+ if(s[4]>best){best=s[4];pos=4;}
+ if(s[5]>best){best=s[5];pos=5;}
+ return(pos);
+}
+
+inline int db_MaxIndex7(const double s[7])
+{
+ double best;
+ int pos;
+
+ best=s[0];pos=0;
+ if(s[1]>best){best=s[1];pos=1;}
+ if(s[2]>best){best=s[2];pos=2;}
+ if(s[3]>best){best=s[3];pos=3;}
+ if(s[4]>best){best=s[4];pos=4;}
+ if(s[5]>best){best=s[5];pos=5;}
+ if(s[6]>best){best=s[6];pos=6;}
+ return(pos);
+}
+
+inline int db_MinIndex7(const double s[7])
+{
+ double best;
+ int pos;
+
+ best=s[0];pos=0;
+ if(s[1]<best){best=s[1];pos=1;}
+ if(s[2]<best){best=s[2];pos=2;}
+ if(s[3]<best){best=s[3];pos=3;}
+ if(s[4]<best){best=s[4];pos=4;}
+ if(s[5]<best){best=s[5];pos=5;}
+ if(s[6]<best){best=s[6];pos=6;}
+ return(pos);
+}
+
+inline int db_MinIndex9(const double s[9])
+{
+ double best;
+ int pos;
+
+ best=s[0];pos=0;
+ if(s[1]<best){best=s[1];pos=1;}
+ if(s[2]<best){best=s[2];pos=2;}
+ if(s[3]<best){best=s[3];pos=3;}
+ if(s[4]<best){best=s[4];pos=4;}
+ if(s[5]<best){best=s[5];pos=5;}
+ if(s[6]<best){best=s[6];pos=6;}
+ if(s[7]<best){best=s[7];pos=7;}
+ if(s[8]<best){best=s[8];pos=8;}
+ return(pos);
+}
+
+inline int db_MaxAbsIndex3(const double *s)
+{
+ double t,best;
+ int pos;
+
+ best=fabs(s[0]);pos=0;
+ t=fabs(s[1]);if(t>best){best=t;pos=1;}
+ t=fabs(s[2]);if(t>best){pos=2;}
+ return(pos);
+}
+
+inline int db_MaxAbsIndex9(const double *s)
+{
+ double t,best;
+ int pos;
+
+ best=fabs(s[0]);pos=0;
+ t=fabs(s[1]);if(t>best){best=t;pos=1;}
+ t=fabs(s[2]);if(t>best){best=t;pos=2;}
+ t=fabs(s[3]);if(t>best){best=t;pos=3;}
+ t=fabs(s[4]);if(t>best){best=t;pos=4;}
+ t=fabs(s[5]);if(t>best){best=t;pos=5;}
+ t=fabs(s[6]);if(t>best){best=t;pos=6;}
+ t=fabs(s[7]);if(t>best){best=t;pos=7;}
+ t=fabs(s[8]);if(t>best){best=t;pos=8;}
+ return(pos);
+}
+
+
+/*!
+Select ordinal pos (zero based) out of nr_elements in s.
+temp should point to alloced memory of at least nr_elements*2
+Optimized runtimes on 450MHz:
+\code
+ 30 with 3 microsecs
+ 100 with 11 microsecs
+ 300 with 30 microsecs
+ 500 with 40 microsecs
+1000 with 100 microsecs
+5000 with 540 microsecs
+\endcode
+so the expected runtime is around
+(nr_elements/10) microseconds
+The total quickselect cost of splitting 500 hypotheses recursively
+is thus around 100 microseconds
+
+Does the same operation as std::nth_element().
+*/
+DB_API double db_LeanQuickSelect(const double *s,long nr_elements,long pos,double *temp);
+
+/*!
+ Median of 3 doubles
+ */
+inline double db_TripleMedian(double a,double b,double c)
+{
+ if(a>b)
+ {
+ if(c>a) return(a);
+ else if(c>b) return(c);
+ else return(b);
+ }
+ else
+ {
+ if(c>b) return(b);
+ else if(c>a) return(c);
+ else return(a);
+ }
+}
+
+/*!
+Align float pointer to nr_bytes by moving forward
+*/
+DB_API float* db_AlignPointer_f(float *p,unsigned long nr_bytes);
+
+/*!
+Align short pointer to nr_bytes by moving forward
+*/
+DB_API short* db_AlignPointer_s(short *p,unsigned long nr_bytes);
+
+#endif /* DB_UTILITIES_INDEXING */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_linalg.cpp b/jni/feature_stab/db_vlvm/db_utilities_linalg.cpp
new file mode 100644
index 000000000..8f68b303a
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_linalg.cpp
@@ -0,0 +1,376 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_linalg.cpp,v 1.3 2011/06/17 14:03:31 mbansal Exp $ */
+
+#include "db_utilities_linalg.h"
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+/*Cholesky-factorize symmetric positive definite 6 x 6 matrix A. Upper
+part of A is used from the input. The Cholesky factor is output as
+subdiagonal part in A and diagonal in d, which is 6-dimensional*/
+void db_CholeskyDecomp6x6(double A[36],double d[6])
+{
+ double s,temp;
+
+ /*[50 mult 35 add 6sqrt=85flops 6func]*/
+ /*i=0*/
+ s=A[0];
+ d[0]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[0]);
+ A[6]=A[1]*temp;
+ A[12]=A[2]*temp;
+ A[18]=A[3]*temp;
+ A[24]=A[4]*temp;
+ A[30]=A[5]*temp;
+ /*i=1*/
+ s=A[7]-A[6]*A[6];
+ d[1]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[1]);
+ A[13]=(A[8]-A[6]*A[12])*temp;
+ A[19]=(A[9]-A[6]*A[18])*temp;
+ A[25]=(A[10]-A[6]*A[24])*temp;
+ A[31]=(A[11]-A[6]*A[30])*temp;
+ /*i=2*/
+ s=A[14]-A[12]*A[12]-A[13]*A[13];
+ d[2]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[2]);
+ A[20]=(A[15]-A[12]*A[18]-A[13]*A[19])*temp;
+ A[26]=(A[16]-A[12]*A[24]-A[13]*A[25])*temp;
+ A[32]=(A[17]-A[12]*A[30]-A[13]*A[31])*temp;
+ /*i=3*/
+ s=A[21]-A[18]*A[18]-A[19]*A[19]-A[20]*A[20];
+ d[3]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[3]);
+ A[27]=(A[22]-A[18]*A[24]-A[19]*A[25]-A[20]*A[26])*temp;
+ A[33]=(A[23]-A[18]*A[30]-A[19]*A[31]-A[20]*A[32])*temp;
+ /*i=4*/
+ s=A[28]-A[24]*A[24]-A[25]*A[25]-A[26]*A[26]-A[27]*A[27];
+ d[4]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[4]);
+ A[34]=(A[29]-A[24]*A[30]-A[25]*A[31]-A[26]*A[32]-A[27]*A[33])*temp;
+ /*i=5*/
+ s=A[35]-A[30]*A[30]-A[31]*A[31]-A[32]*A[32]-A[33]*A[33]-A[34]*A[34];
+ d[5]=((s>0.0)?sqrt(s):1.0);
+}
+
+/*Cholesky-factorize symmetric positive definite n x n matrix A.Part
+above diagonal of A is used from the input, diagonal of A is assumed to
+be stored in d. The Cholesky factor is output as
+subdiagonal part in A and diagonal in d, which is n-dimensional*/
+void db_CholeskyDecompSeparateDiagonal(double **A,double *d,int n)
+{
+ int i,j,k;
+ double s;
+ double temp = 0.0;
+
+ for(i=0;i<n;i++) for(j=i;j<n;j++)
+ {
+ if(i==j) s=d[i];
+ else s=A[i][j];
+ for(k=i-1;k>=0;k--) s-=A[i][k]*A[j][k];
+ if(i==j)
+ {
+ d[i]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[i]);
+ }
+ else A[j][i]=s*temp;
+ }
+}
+
+/*Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition
+of an n x n matrix and the right hand side b. The vector b is unchanged*/
+void db_CholeskyBacksub(double *x,const double * const *A,const double *d,int n,const double *b)
+{
+ int i,k;
+ double s;
+
+ for(i=0;i<n;i++)
+ {
+ for(s=b[i],k=i-1;k>=0;k--) s-=A[i][k]*x[k];
+ x[i]=db_SafeDivision(s,d[i]);
+ }
+ for(i=n-1;i>=0;i--)
+ {
+ for(s=x[i],k=i+1;k<n;k++) s-=A[k][i]*x[k];
+ x[i]=db_SafeDivision(s,d[i]);
+ }
+}
+
+/*Cholesky-factorize symmetric positive definite 3 x 3 matrix A. Part
+above diagonal of A is used from the input, diagonal of A is assumed to
+be stored in d. The Cholesky factor is output as subdiagonal part in A
+and diagonal in d, which is 3-dimensional*/
+void db_CholeskyDecomp3x3SeparateDiagonal(double A[9],double d[3])
+{
+ double s,temp;
+
+ /*i=0*/
+ s=d[0];
+ d[0]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[0]);
+ A[3]=A[1]*temp;
+ A[6]=A[2]*temp;
+ /*i=1*/
+ s=d[1]-A[3]*A[3];
+ d[1]=((s>0.0)?sqrt(s):1.0);
+ temp=db_SafeReciprocal(d[1]);
+ A[7]=(A[5]-A[3]*A[6])*temp;
+ /*i=2*/
+ s=d[2]-A[6]*A[6]-A[7]*A[7];
+ d[2]=((s>0.0)?sqrt(s):1.0);
+}
+
+/*Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition
+of a 3 x 3 matrix and the right hand side b. The vector b is unchanged*/
+void db_CholeskyBacksub3x3(double x[3],const double A[9],const double d[3],const double b[3])
+{
+ /*[42 mult 30 add=72flops]*/
+ x[0]=db_SafeDivision(b[0],d[0]);
+ x[1]=db_SafeDivision((b[1]-A[3]*x[0]),d[1]);
+ x[2]=db_SafeDivision((b[2]-A[6]*x[0]-A[7]*x[1]),d[2]);
+ x[2]=db_SafeDivision(x[2],d[2]);
+ x[1]=db_SafeDivision((x[1]-A[7]*x[2]),d[1]);
+ x[0]=db_SafeDivision((x[0]-A[6]*x[2]-A[3]*x[1]),d[0]);
+}
+
+/*Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition
+of a 6 x 6 matrix and the right hand side b. The vector b is unchanged*/
+void db_CholeskyBacksub6x6(double x[6],const double A[36],const double d[6],const double b[6])
+{
+ /*[42 mult 30 add=72flops]*/
+ x[0]=db_SafeDivision(b[0],d[0]);
+ x[1]=db_SafeDivision((b[1]-A[6]*x[0]),d[1]);
+ x[2]=db_SafeDivision((b[2]-A[12]*x[0]-A[13]*x[1]),d[2]);
+ x[3]=db_SafeDivision((b[3]-A[18]*x[0]-A[19]*x[1]-A[20]*x[2]),d[3]);
+ x[4]=db_SafeDivision((b[4]-A[24]*x[0]-A[25]*x[1]-A[26]*x[2]-A[27]*x[3]),d[4]);
+ x[5]=db_SafeDivision((b[5]-A[30]*x[0]-A[31]*x[1]-A[32]*x[2]-A[33]*x[3]-A[34]*x[4]),d[5]);
+ x[5]=db_SafeDivision(x[5],d[5]);
+ x[4]=db_SafeDivision((x[4]-A[34]*x[5]),d[4]);
+ x[3]=db_SafeDivision((x[3]-A[33]*x[5]-A[27]*x[4]),d[3]);
+ x[2]=db_SafeDivision((x[2]-A[32]*x[5]-A[26]*x[4]-A[20]*x[3]),d[2]);
+ x[1]=db_SafeDivision((x[1]-A[31]*x[5]-A[25]*x[4]-A[19]*x[3]-A[13]*x[2]),d[1]);
+ x[0]=db_SafeDivision((x[0]-A[30]*x[5]-A[24]*x[4]-A[18]*x[3]-A[12]*x[2]-A[6]*x[1]),d[0]);
+}
+
+
+void db_Orthogonalize6x7(double A[42],int orthonormalize)
+{
+ int i;
+ double ss[6];
+
+ /*Compute square sums of rows*/
+ ss[0]=db_SquareSum7(A);
+ ss[1]=db_SquareSum7(A+7);
+ ss[2]=db_SquareSum7(A+14);
+ ss[3]=db_SquareSum7(A+21);
+ ss[4]=db_SquareSum7(A+28);
+ ss[5]=db_SquareSum7(A+35);
+
+ ss[1]-=db_OrthogonalizePair7(A+7 ,A,ss[0]);
+ ss[2]-=db_OrthogonalizePair7(A+14,A,ss[0]);
+ ss[3]-=db_OrthogonalizePair7(A+21,A,ss[0]);
+ ss[4]-=db_OrthogonalizePair7(A+28,A,ss[0]);
+ ss[5]-=db_OrthogonalizePair7(A+35,A,ss[0]);
+
+ /*Pivot on largest ss (could also be done on ss/(original_ss))*/
+ i=db_MaxIndex5(ss+1);
+ db_OrthogonalizationSwap7(A+7,i,ss+1);
+
+ ss[2]-=db_OrthogonalizePair7(A+14,A+7,ss[1]);
+ ss[3]-=db_OrthogonalizePair7(A+21,A+7,ss[1]);
+ ss[4]-=db_OrthogonalizePair7(A+28,A+7,ss[1]);
+ ss[5]-=db_OrthogonalizePair7(A+35,A+7,ss[1]);
+
+ i=db_MaxIndex4(ss+2);
+ db_OrthogonalizationSwap7(A+14,i,ss+2);
+
+ ss[3]-=db_OrthogonalizePair7(A+21,A+14,ss[2]);
+ ss[4]-=db_OrthogonalizePair7(A+28,A+14,ss[2]);
+ ss[5]-=db_OrthogonalizePair7(A+35,A+14,ss[2]);
+
+ i=db_MaxIndex3(ss+3);
+ db_OrthogonalizationSwap7(A+21,i,ss+3);
+
+ ss[4]-=db_OrthogonalizePair7(A+28,A+21,ss[3]);
+ ss[5]-=db_OrthogonalizePair7(A+35,A+21,ss[3]);
+
+ i=db_MaxIndex2(ss+4);
+ db_OrthogonalizationSwap7(A+28,i,ss+4);
+
+ ss[5]-=db_OrthogonalizePair7(A+35,A+28,ss[4]);
+
+ if(orthonormalize)
+ {
+ db_MultiplyScalar7(A ,db_SafeSqrtReciprocal(ss[0]));
+ db_MultiplyScalar7(A+7 ,db_SafeSqrtReciprocal(ss[1]));
+ db_MultiplyScalar7(A+14,db_SafeSqrtReciprocal(ss[2]));
+ db_MultiplyScalar7(A+21,db_SafeSqrtReciprocal(ss[3]));
+ db_MultiplyScalar7(A+28,db_SafeSqrtReciprocal(ss[4]));
+ db_MultiplyScalar7(A+35,db_SafeSqrtReciprocal(ss[5]));
+ }
+}
+
+void db_Orthogonalize8x9(double A[72],int orthonormalize)
+{
+ int i;
+ double ss[8];
+
+ /*Compute square sums of rows*/
+ ss[0]=db_SquareSum9(A);
+ ss[1]=db_SquareSum9(A+9);
+ ss[2]=db_SquareSum9(A+18);
+ ss[3]=db_SquareSum9(A+27);
+ ss[4]=db_SquareSum9(A+36);
+ ss[5]=db_SquareSum9(A+45);
+ ss[6]=db_SquareSum9(A+54);
+ ss[7]=db_SquareSum9(A+63);
+
+ ss[1]-=db_OrthogonalizePair9(A+9 ,A,ss[0]);
+ ss[2]-=db_OrthogonalizePair9(A+18,A,ss[0]);
+ ss[3]-=db_OrthogonalizePair9(A+27,A,ss[0]);
+ ss[4]-=db_OrthogonalizePair9(A+36,A,ss[0]);
+ ss[5]-=db_OrthogonalizePair9(A+45,A,ss[0]);
+ ss[6]-=db_OrthogonalizePair9(A+54,A,ss[0]);
+ ss[7]-=db_OrthogonalizePair9(A+63,A,ss[0]);
+
+ /*Pivot on largest ss (could also be done on ss/(original_ss))*/
+ i=db_MaxIndex7(ss+1);
+ db_OrthogonalizationSwap9(A+9,i,ss+1);
+
+ ss[2]-=db_OrthogonalizePair9(A+18,A+9,ss[1]);
+ ss[3]-=db_OrthogonalizePair9(A+27,A+9,ss[1]);
+ ss[4]-=db_OrthogonalizePair9(A+36,A+9,ss[1]);
+ ss[5]-=db_OrthogonalizePair9(A+45,A+9,ss[1]);
+ ss[6]-=db_OrthogonalizePair9(A+54,A+9,ss[1]);
+ ss[7]-=db_OrthogonalizePair9(A+63,A+9,ss[1]);
+
+ i=db_MaxIndex6(ss+2);
+ db_OrthogonalizationSwap9(A+18,i,ss+2);
+
+ ss[3]-=db_OrthogonalizePair9(A+27,A+18,ss[2]);
+ ss[4]-=db_OrthogonalizePair9(A+36,A+18,ss[2]);
+ ss[5]-=db_OrthogonalizePair9(A+45,A+18,ss[2]);
+ ss[6]-=db_OrthogonalizePair9(A+54,A+18,ss[2]);
+ ss[7]-=db_OrthogonalizePair9(A+63,A+18,ss[2]);
+
+ i=db_MaxIndex5(ss+3);
+ db_OrthogonalizationSwap9(A+27,i,ss+3);
+
+ ss[4]-=db_OrthogonalizePair9(A+36,A+27,ss[3]);
+ ss[5]-=db_OrthogonalizePair9(A+45,A+27,ss[3]);
+ ss[6]-=db_OrthogonalizePair9(A+54,A+27,ss[3]);
+ ss[7]-=db_OrthogonalizePair9(A+63,A+27,ss[3]);
+
+ i=db_MaxIndex4(ss+4);
+ db_OrthogonalizationSwap9(A+36,i,ss+4);
+
+ ss[5]-=db_OrthogonalizePair9(A+45,A+36,ss[4]);
+ ss[6]-=db_OrthogonalizePair9(A+54,A+36,ss[4]);
+ ss[7]-=db_OrthogonalizePair9(A+63,A+36,ss[4]);
+
+ i=db_MaxIndex3(ss+5);
+ db_OrthogonalizationSwap9(A+45,i,ss+5);
+
+ ss[6]-=db_OrthogonalizePair9(A+54,A+45,ss[5]);
+ ss[7]-=db_OrthogonalizePair9(A+63,A+45,ss[5]);
+
+ i=db_MaxIndex2(ss+6);
+ db_OrthogonalizationSwap9(A+54,i,ss+6);
+
+ ss[7]-=db_OrthogonalizePair9(A+63,A+54,ss[6]);
+
+ if(orthonormalize)
+ {
+ db_MultiplyScalar9(A ,db_SafeSqrtReciprocal(ss[0]));
+ db_MultiplyScalar9(A+9 ,db_SafeSqrtReciprocal(ss[1]));
+ db_MultiplyScalar9(A+18,db_SafeSqrtReciprocal(ss[2]));
+ db_MultiplyScalar9(A+27,db_SafeSqrtReciprocal(ss[3]));
+ db_MultiplyScalar9(A+36,db_SafeSqrtReciprocal(ss[4]));
+ db_MultiplyScalar9(A+45,db_SafeSqrtReciprocal(ss[5]));
+ db_MultiplyScalar9(A+54,db_SafeSqrtReciprocal(ss[6]));
+ db_MultiplyScalar9(A+63,db_SafeSqrtReciprocal(ss[7]));
+ }
+}
+
+void db_NullVectorOrthonormal6x7(double x[7],const double A[42])
+{
+ int i;
+ double omss[7];
+ const double *B;
+
+ /*Pivot by choosing row of the identity matrix
+ (the one corresponding to column of A with smallest square sum)*/
+ omss[0]=db_SquareSum6Stride7(A);
+ omss[1]=db_SquareSum6Stride7(A+1);
+ omss[2]=db_SquareSum6Stride7(A+2);
+ omss[3]=db_SquareSum6Stride7(A+3);
+ omss[4]=db_SquareSum6Stride7(A+4);
+ omss[5]=db_SquareSum6Stride7(A+5);
+ omss[6]=db_SquareSum6Stride7(A+6);
+ i=db_MinIndex7(omss);
+ /*orthogonalize that row against all previous rows
+ and normalize it*/
+ B=A+i;
+ db_MultiplyScalarCopy7(x,A,-B[0]);
+ db_RowOperation7(x,A+7 ,B[7]);
+ db_RowOperation7(x,A+14,B[14]);
+ db_RowOperation7(x,A+21,B[21]);
+ db_RowOperation7(x,A+28,B[28]);
+ db_RowOperation7(x,A+35,B[35]);
+ x[i]+=1.0;
+ db_MultiplyScalar7(x,db_SafeSqrtReciprocal(1.0-omss[i]));
+}
+
+void db_NullVectorOrthonormal8x9(double x[9],const double A[72])
+{
+ int i;
+ double omss[9];
+ const double *B;
+
+ /*Pivot by choosing row of the identity matrix
+ (the one corresponding to column of A with smallest square sum)*/
+ omss[0]=db_SquareSum8Stride9(A);
+ omss[1]=db_SquareSum8Stride9(A+1);
+ omss[2]=db_SquareSum8Stride9(A+2);
+ omss[3]=db_SquareSum8Stride9(A+3);
+ omss[4]=db_SquareSum8Stride9(A+4);
+ omss[5]=db_SquareSum8Stride9(A+5);
+ omss[6]=db_SquareSum8Stride9(A+6);
+ omss[7]=db_SquareSum8Stride9(A+7);
+ omss[8]=db_SquareSum8Stride9(A+8);
+ i=db_MinIndex9(omss);
+ /*orthogonalize that row against all previous rows
+ and normalize it*/
+ B=A+i;
+ db_MultiplyScalarCopy9(x,A,-B[0]);
+ db_RowOperation9(x,A+9 ,B[9]);
+ db_RowOperation9(x,A+18,B[18]);
+ db_RowOperation9(x,A+27,B[27]);
+ db_RowOperation9(x,A+36,B[36]);
+ db_RowOperation9(x,A+45,B[45]);
+ db_RowOperation9(x,A+54,B[54]);
+ db_RowOperation9(x,A+63,B[63]);
+ x[i]+=1.0;
+ db_MultiplyScalar9(x,db_SafeSqrtReciprocal(1.0-omss[i]));
+}
+
diff --git a/jni/feature_stab/db_vlvm/db_utilities_linalg.h b/jni/feature_stab/db_vlvm/db_utilities_linalg.h
new file mode 100644
index 000000000..1f63d4e57
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_linalg.h
@@ -0,0 +1,802 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_linalg.h,v 1.5 2011/06/17 14:03:31 mbansal Exp $ */
+
+#ifndef DB_UTILITIES_LINALG
+#define DB_UTILITIES_LINALG
+
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMLinAlg (LM) Linear Algebra Utilities (QR factorization, orthogonal basis, etc.)
+ */
+
+/*!
+ \ingroup LMBasicUtilities
+ */
+inline void db_MultiplyScalar6(double A[6],double mult)
+{
+ (*A++) *= mult; (*A++) *= mult; (*A++) *= mult; (*A++) *= mult; (*A++) *= mult;
+ (*A++) *= mult;
+}
+/*!
+ \ingroup LMBasicUtilities
+ */
+inline void db_MultiplyScalar7(double A[7],double mult)
+{
+ (*A++) *= mult; (*A++) *= mult; (*A++) *= mult; (*A++) *= mult; (*A++) *= mult;
+ (*A++) *= mult; (*A++) *= mult;
+}
+/*!
+ \ingroup LMBasicUtilities
+ */
+inline void db_MultiplyScalar9(double A[9],double mult)
+{
+ (*A++) *= mult; (*A++) *= mult; (*A++) *= mult; (*A++) *= mult; (*A++) *= mult;
+ (*A++) *= mult; (*A++) *= mult; (*A++) *= mult; (*A++) *= mult;
+}
+
+/*!
+ \ingroup LMBasicUtilities
+ */
+inline double db_SquareSum6Stride7(const double *x)
+{
+ return(db_sqr(x[0])+db_sqr(x[7])+db_sqr(x[14])+
+ db_sqr(x[21])+db_sqr(x[28])+db_sqr(x[35]));
+}
+
+/*!
+ \ingroup LMBasicUtilities
+ */
+inline double db_SquareSum8Stride9(const double *x)
+{
+ return(db_sqr(x[0])+db_sqr(x[9])+db_sqr(x[18])+
+ db_sqr(x[27])+db_sqr(x[36])+db_sqr(x[45])+
+ db_sqr(x[54])+db_sqr(x[63]));
+}
+
+/*!
+ \ingroup LMLinAlg
+ Cholesky-factorize symmetric positive definite 6 x 6 matrix A. Upper
+part of A is used from the input. The Cholesky factor is output as
+subdiagonal part in A and diagonal in d, which is 6-dimensional
+1.9 microseconds on 450MHz*/
+DB_API void db_CholeskyDecomp6x6(double A[36],double d[6]);
+
+/*!
+ \ingroup LMLinAlg
+ Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition
+of a 6 x 6 matrix and the right hand side b. The vector b is unchanged
+1.3 microseconds on 450MHz*/
+DB_API void db_CholeskyBacksub6x6(double x[6],const double A[36],const double d[6],const double b[6]);
+
+/*!
+ \ingroup LMLinAlg
+ Cholesky-factorize symmetric positive definite n x n matrix A.Part
+above diagonal of A is used from the input, diagonal of A is assumed to
+be stored in d. The Cholesky factor is output as
+subdiagonal part in A and diagonal in d, which is n-dimensional*/
+DB_API void db_CholeskyDecompSeparateDiagonal(double **A,double *d,int n);
+
+/*!
+ \ingroup LMLinAlg
+ Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition
+of an n x n matrix and the right hand side b. The vector b is unchanged*/
+DB_API void db_CholeskyBacksub(double *x,const double * const *A,const double *d,int n,const double *b);
+
+/*!
+ \ingroup LMLinAlg
+ Cholesky-factorize symmetric positive definite 3 x 3 matrix A. Part
+above diagonal of A is used from the input, diagonal of A is assumed to
+be stored in d. The Cholesky factor is output as subdiagonal part in A
+and diagonal in d, which is 3-dimensional*/
+DB_API void db_CholeskyDecomp3x3SeparateDiagonal(double A[9],double d[3]);
+
+/*!
+ \ingroup LMLinAlg
+ Backsubstitute L%transpose(L)*x=b for x given the Cholesky decomposition
+of a 3 x 3 matrix and the right hand side b. The vector b is unchanged*/
+DB_API void db_CholeskyBacksub3x3(double x[3],const double A[9],const double d[3],const double b[3]);
+
+/*!
+ \ingroup LMLinAlg
+ perform A-=B*mult*/
+inline void db_RowOperation3(double A[3],const double B[3],double mult)
+{
+ *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++);
+}
+
+/*!
+ \ingroup LMLinAlg
+ */
+inline void db_RowOperation7(double A[7],const double B[7],double mult)
+{
+ *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++);
+ *A++ -= mult*(*B++); *A++ -= mult*(*B++);
+}
+
+/*!
+ \ingroup LMLinAlg
+ */
+inline void db_RowOperation9(double A[9],const double B[9],double mult)
+{
+ *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++);
+ *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++); *A++ -= mult*(*B++);
+}
+
+/*!
+ \ingroup LMBasicUtilities
+ Swap values of A[7] and B[7]
+ */
+inline void db_Swap7(double A[7],double B[7])
+{
+ double temp;
+ temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp;
+ temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp;
+ temp= *A; *A++ = *B; *B++ =temp;
+}
+
+/*!
+ \ingroup LMBasicUtilities
+ Swap values of A[9] and B[9]
+ */
+inline void db_Swap9(double A[9],double B[9])
+{
+ double temp;
+ temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp;
+ temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp;
+ temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp; temp= *A; *A++ = *B; *B++ =temp;
+}
+
+
+/*!
+ \ingroup LMLinAlg
+ */
+DB_API void db_Orthogonalize6x7(double A[42],int orthonormalize=0);
+
+/*!
+ \ingroup LMLinAlg
+ */
+DB_API void db_Orthogonalize8x9(double A[72],int orthonormalize=0);
+
+/*!
+ \ingroup LMLinAlg
+ */
+inline double db_OrthogonalizePair7(double *x,const double *v,double ssv)
+{
+ double m,sp,sp_m;
+
+ m=db_SafeReciprocal(ssv);
+ sp=db_ScalarProduct7(x,v);
+ sp_m=sp*m;
+ db_RowOperation7(x,v,sp_m);
+ return(sp*sp_m);
+}
+
+/*!
+ \ingroup LMLinAlg
+ */
+inline double db_OrthogonalizePair9(double *x,const double *v,double ssv)
+{
+ double m,sp,sp_m;
+
+ m=db_SafeReciprocal(ssv);
+ sp=db_ScalarProduct9(x,v);
+ sp_m=sp*m;
+ db_RowOperation9(x,v,sp_m);
+ return(sp*sp_m);
+}
+
+/*!
+ \ingroup LMLinAlg
+ */
+inline void db_OrthogonalizationSwap7(double *A,int i,double *ss)
+{
+ double temp;
+
+ db_Swap7(A,A+7*i);
+ temp=ss[0]; ss[0]=ss[i]; ss[i]=temp;
+}
+/*!
+ \ingroup LMLinAlg
+ */
+inline void db_OrthogonalizationSwap9(double *A,int i,double *ss)
+{
+ double temp;
+
+ db_Swap9(A,A+9*i);
+ temp=ss[0]; ss[0]=ss[i]; ss[i]=temp;
+}
+
+/*!
+ \ingroup LMLinAlg
+ */
+DB_API void db_NullVectorOrthonormal6x7(double x[7],const double A[42]);
+/*!
+ \ingroup LMLinAlg
+ */
+DB_API void db_NullVectorOrthonormal8x9(double x[9],const double A[72]);
+
+/*!
+ \ingroup LMLinAlg
+ */
+inline void db_NullVector6x7Destructive(double x[7],double A[42])
+{
+ db_Orthogonalize6x7(A,1);
+ db_NullVectorOrthonormal6x7(x,A);
+}
+
+/*!
+ \ingroup LMLinAlg
+ */
+inline void db_NullVector8x9Destructive(double x[9],double A[72])
+{
+ db_Orthogonalize8x9(A,1);
+ db_NullVectorOrthonormal8x9(x,A);
+}
+
+inline int db_ScalarProduct512_s(const short *f,const short *g)
+{
+#ifndef DB_USE_MMX
+ int back;
+ back=0;
+ for(int i=1; i<=512; i++)
+ back+=(*f++)*(*g++);
+
+ return(back);
+#endif
+}
+
+
+inline int db_ScalarProduct32_s(const short *f,const short *g)
+{
+#ifndef DB_USE_MMX
+ int back;
+ back=0;
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+
+ return(back);
+#endif
+}
+
+/*!
+ \ingroup LMLinAlg
+ Scalar product of 128-vectors (short)
+ Compile-time control: MMX, SSE2 or standard C
+ */
+inline int db_ScalarProduct128_s(const short *f,const short *g)
+{
+#ifndef DB_USE_MMX
+ int back;
+ back=0;
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+
+ return(back);
+#else
+#ifdef DB_USE_SSE2
+ int back;
+
+ _asm
+ {
+ mov eax,f
+ mov ecx,g
+ /*First iteration************************************/
+ movdqa xmm0,[eax]
+ pxor xmm7,xmm7 /*Set xmm7 to zero*/
+ pmaddwd xmm0,[ecx]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm2,[eax+16]
+ paddd xmm7,xmm0
+ pmaddwd xmm2,[ecx+16]
+ /*Stall*/
+ movdqa xmm1,[eax+32]
+ paddd xmm7,xmm2
+ pmaddwd xmm1,[ecx+32]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm0,[eax+48]
+ paddd xmm7,xmm1
+ pmaddwd xmm0,[ecx+48]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm2,[eax+64]
+ paddd xmm7,xmm0
+ pmaddwd xmm2,[ecx+64]
+ /*Stall*/
+ movdqa xmm1,[eax+80]
+ paddd xmm7,xmm2
+ pmaddwd xmm1,[ecx+80]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm0,[eax+96]
+ paddd xmm7,xmm1
+ pmaddwd xmm0,[ecx+96]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm2,[eax+112]
+ paddd xmm7,xmm0
+ pmaddwd xmm2,[ecx+112]
+ /*Stall*/
+ movdqa xmm1,[eax+128]
+ paddd xmm7,xmm2
+ pmaddwd xmm1,[ecx+128]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm0,[eax+144]
+ paddd xmm7,xmm1
+ pmaddwd xmm0,[ecx+144]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm2,[eax+160]
+ paddd xmm7,xmm0
+ pmaddwd xmm2,[ecx+160]
+ /*Stall*/
+ movdqa xmm1,[eax+176]
+ paddd xmm7,xmm2
+ pmaddwd xmm1,[ecx+176]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm0,[eax+192]
+ paddd xmm7,xmm1
+ pmaddwd xmm0,[ecx+192]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm2,[eax+208]
+ paddd xmm7,xmm0
+ pmaddwd xmm2,[ecx+208]
+ /*Stall*/
+ movdqa xmm1,[eax+224]
+ paddd xmm7,xmm2
+ pmaddwd xmm1,[ecx+224]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movdqa xmm0,[eax+240]
+ paddd xmm7,xmm1
+ pmaddwd xmm0,[ecx+240]
+ /*Stall*/
+ /*Rest iteration************************************/
+ paddd xmm7,xmm0
+
+ /* add up the sum squares */
+ movhlps xmm0,xmm7 /* high half to low half */
+ paddd xmm7,xmm0 /* add high to low */
+ pshuflw xmm0,xmm7, 0xE /* reshuffle */
+ paddd xmm7,xmm0 /* add remaining */
+ movd back,xmm7
+
+ emms
+ }
+
+ return(back);
+#else
+ int back;
+
+ _asm
+ {
+ mov eax,f
+ mov ecx,g
+ /*First iteration************************************/
+ movq mm0,[eax]
+ pxor mm7,mm7 /*Set mm7 to zero*/
+ pmaddwd mm0,[ecx]
+ /*Stall*/
+ movq mm1,[eax+8]
+ /*Stall*/
+ pmaddwd mm1,[ecx+8]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+16]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+16]
+ /*Stall*/
+ movq mm0,[eax+24]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+24]
+ /*Stall*/
+ movq mm1,[eax+32]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+32]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+40]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+40]
+ /*Stall*/
+ movq mm0,[eax+48]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+48]
+ /*Stall*/
+ movq mm1,[eax+56]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+56]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+64]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+64]
+ /*Stall*/
+ movq mm0,[eax+72]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+72]
+ /*Stall*/
+ movq mm1,[eax+80]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+80]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+88]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+88]
+ /*Stall*/
+ movq mm0,[eax+96]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+96]
+ /*Stall*/
+ movq mm1,[eax+104]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+104]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+112]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+112]
+ /*Stall*/
+ movq mm0,[eax+120]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+120]
+ /*Stall*/
+ movq mm1,[eax+128]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+128]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+136]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+136]
+ /*Stall*/
+ movq mm0,[eax+144]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+144]
+ /*Stall*/
+ movq mm1,[eax+152]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+152]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+160]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+160]
+ /*Stall*/
+ movq mm0,[eax+168]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+168]
+ /*Stall*/
+ movq mm1,[eax+176]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+176]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+184]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+184]
+ /*Stall*/
+ movq mm0,[eax+192]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+192]
+ /*Stall*/
+ movq mm1,[eax+200]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+200]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+208]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+208]
+ /*Stall*/
+ movq mm0,[eax+216]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+216]
+ /*Stall*/
+ movq mm1,[eax+224]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+224]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movq mm2,[eax+232]
+ paddd mm7,mm0
+ pmaddwd mm2,[ecx+232]
+ /*Stall*/
+ movq mm0,[eax+240]
+ paddd mm7,mm1
+ pmaddwd mm0,[ecx+240]
+ /*Stall*/
+ movq mm1,[eax+248]
+ paddd mm7,mm2
+ pmaddwd mm1,[ecx+248]
+ /*Stall*/
+ /*Rest iteration************************************/
+ paddd mm7,mm0
+ /*Stall*/
+ /*Stall*/
+ /*Stall*/
+ paddd mm7,mm1
+ /*Stall*/
+ movq mm0,mm7
+ psrlq mm7,32
+ paddd mm0,mm7
+ /*Stall*/
+ /*Stall*/
+ /*Stall*/
+ movd back,mm0
+ emms
+ }
+
+ return(back);
+#endif
+#endif /*DB_USE_MMX*/
+}
+
+/*!
+ \ingroup LMLinAlg
+ Scalar product of 16 byte aligned 128-vectors (float).
+ Compile-time control: SIMD (SSE) or standard C.
+ */
+inline float db_ScalarProduct128Aligned16_f(const float *f,const float *g)
+{
+#ifndef DB_USE_SIMD
+ float back;
+ back=0.0;
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+ back+=(*f++)*(*g++); back+=(*f++)*(*g++); back+=(*f++)*(*g++);
+
+ return(back);
+#else
+ float back;
+
+ _asm
+ {
+ mov eax,f
+ mov ecx,g
+ /*First iteration************************************/
+ movaps xmm0,[eax]
+ xorps xmm7,xmm7 /*Set mm7 to zero*/
+ mulps xmm0,[ecx]
+ /*Stall*/
+ movaps xmm1,[eax+16]
+ /*Stall*/
+ mulps xmm1,[ecx+16]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+32]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+32]
+ /*Stall*/
+ movaps xmm0,[eax+48]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+48]
+ /*Stall*/
+ movaps xmm1,[eax+64]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+64]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+80]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+80]
+ /*Stall*/
+ movaps xmm0,[eax+96]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+96]
+ /*Stall*/
+ movaps xmm1,[eax+112]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+112]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+128]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+128]
+ /*Stall*/
+ movaps xmm0,[eax+144]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+144]
+ /*Stall*/
+ movaps xmm1,[eax+160]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+160]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+176]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+176]
+ /*Stall*/
+ movaps xmm0,[eax+192]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+192]
+ /*Stall*/
+ movaps xmm1,[eax+208]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+208]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+224]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+224]
+ /*Stall*/
+ movaps xmm0,[eax+240]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+240]
+ /*Stall*/
+ movaps xmm1,[eax+256]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+256]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+272]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+272]
+ /*Stall*/
+ movaps xmm0,[eax+288]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+288]
+ /*Stall*/
+ movaps xmm1,[eax+304]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+304]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+320]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+320]
+ /*Stall*/
+ movaps xmm0,[eax+336]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+336]
+ /*Stall*/
+ movaps xmm1,[eax+352]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+352]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+368]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+368]
+ /*Stall*/
+ movaps xmm0,[eax+384]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+384]
+ /*Stall*/
+ movaps xmm1,[eax+400]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+400]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+416]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+416]
+ /*Stall*/
+ movaps xmm0,[eax+432]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+432]
+ /*Stall*/
+ movaps xmm1,[eax+448]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+448]
+ /*Stall*/
+ /*Standard iteration************************************/
+ movaps xmm2,[eax+464]
+ addps xmm7,xmm0
+ mulps xmm2,[ecx+464]
+ /*Stall*/
+ movaps xmm0,[eax+480]
+ addps xmm7,xmm1
+ mulps xmm0,[ecx+480]
+ /*Stall*/
+ movaps xmm1,[eax+496]
+ addps xmm7,xmm2
+ mulps xmm1,[ecx+496]
+ /*Stall*/
+ /*Rest iteration************************************/
+ addps xmm7,xmm0
+ /*Stall*/
+ addps xmm7,xmm1
+ /*Stall*/
+ movaps xmm6,xmm7
+ /*Stall*/
+ shufps xmm6,xmm6,4Eh
+ /*Stall*/
+ addps xmm7,xmm6
+ /*Stall*/
+ movaps xmm6,xmm7
+ /*Stall*/
+ shufps xmm6,xmm6,11h
+ /*Stall*/
+ addps xmm7,xmm6
+ /*Stall*/
+ movss back,xmm7
+ }
+
+ return(back);
+#endif /*DB_USE_SIMD*/
+}
+
+#endif /* DB_UTILITIES_LINALG */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_poly.cpp b/jni/feature_stab/db_vlvm/db_utilities_poly.cpp
new file mode 100644
index 000000000..013ac726e
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_poly.cpp
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_poly.cpp,v 1.2 2010/09/03 12:00:10 bsouthall Exp $ */
+
+#include "db_utilities_poly.h"
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+
+void db_SolveCubic(double *roots,int *nr_roots,double a,double b,double c,double d)
+{
+ double bp,bp2,cp,dp,q,r,srq;
+ double r2_min_q3,theta,bp_through3,theta_through3;
+ double cos_theta_through3,sin_theta_through3,min2_cos_theta_plu,min2_cos_theta_min;
+ double si_r_srq,A;
+
+ /*For nondegenerate cubics with three roots
+ [24 mult 9 add 2sqrt 1acos 1cos=33flops 4func]
+ For nondegenerate cubics with one root
+ [16 mult 6 add 1sqrt 1qbrt=24flops 3func]*/
+
+ if(a==0.0) db_SolveQuadratic(roots,nr_roots,b,c,d);
+ else
+ {
+ bp=b/a;
+ bp2=bp*bp;
+ cp=c/a;
+ dp=d/a;
+
+ q=(bp2-3.0*cp)/9.0;
+ r=(2.0*bp2*bp-9.0*bp*cp+27.0*dp)/54.0;
+ r2_min_q3=r*r-q*q*q;
+ if(r2_min_q3<0.0)
+ {
+ *nr_roots=3;
+ /*q has to be > 0*/
+ srq=sqrt(q);
+ theta=acos(db_maxd(-1.0,db_mind(1.0,r/(q*srq))));
+ bp_through3=bp/3.0;
+ theta_through3=theta/3.0;
+ cos_theta_through3=cos(theta_through3);
+ sin_theta_through3=sqrt(db_maxd(0.0,1.0-cos_theta_through3*cos_theta_through3));
+
+ /*cos(theta_through3+2*pi/3)=cos_theta_through3*cos(2*pi/3)-sin_theta_through3*sin(2*pi/3)
+ = -0.5*cos_theta_through3-sqrt(3)/2.0*sin_theta_through3
+ = -0.5*(cos_theta_through3+sqrt(3)*sin_theta_through3)*/
+ min2_cos_theta_plu=cos_theta_through3+DB_SQRT3*sin_theta_through3;
+ min2_cos_theta_min=cos_theta_through3-DB_SQRT3*sin_theta_through3;
+
+ roots[0]= -2.0*srq*cos_theta_through3-bp_through3;
+ roots[1]=srq*min2_cos_theta_plu-bp_through3;
+ roots[2]=srq*min2_cos_theta_min-bp_through3;
+ }
+ else if(r2_min_q3>0.0)
+ {
+ *nr_roots=1;
+ A= -db_sign(r)*db_CubRoot(db_absd(r)+sqrt(r2_min_q3));
+ bp_through3=bp/3.0;
+ if(A!=0.0) roots[0]=A+q/A-bp_through3;
+ else roots[0]= -bp_through3;
+ }
+ else
+ {
+ *nr_roots=2;
+ bp_through3=bp/3.0;
+ /*q has to be >= 0*/
+ si_r_srq=db_sign(r)*sqrt(q);
+ /*Single root*/
+ roots[0]= -2.0*si_r_srq-bp_through3;
+ /*Double root*/
+ roots[1]=si_r_srq-bp_through3;
+ }
+ }
+}
+
+void db_SolveQuartic(double *roots,int *nr_roots,double a,double b,double c,double d,double e)
+{
+ /*Normalized coefficients*/
+ double c0,c1,c2,c3;
+ /*Temporary coefficients*/
+ double c3through2,c3through4,c3c3through4_min_c2,min4_c0;
+ double lz,ms,ns,mn,m,n,lz_through2;
+ /*Cubic polynomial roots, nr of roots and coefficients*/
+ double c_roots[3];
+ int nr_c_roots;
+ double k0,k1;
+ /*nr additional roots from second quadratic*/
+ int addroots;
+
+ /*For nondegenerate quartics
+ [16mult 11add 2sqrt 1cubic 2quadratic=74flops 8funcs]*/
+
+ if(a==0.0) db_SolveCubic(roots,nr_roots,b,c,d,e);
+ else if(e==0.0)
+ {
+ db_SolveCubic(roots,nr_roots,a,b,c,d);
+ roots[*nr_roots]=0.0;
+ *nr_roots+=1;
+ }
+ else
+ {
+ /*Compute normalized coefficients*/
+ c3=b/a;
+ c2=c/a;
+ c1=d/a;
+ c0=e/a;
+ /*Compute temporary coefficients*/
+ c3through2=c3/2.0;
+ c3through4=c3/4.0;
+ c3c3through4_min_c2=c3*c3through4-c2;
+ min4_c0= -4.0*c0;
+ /*Compute coefficients of cubic*/
+ k0=min4_c0*c3c3through4_min_c2-c1*c1;
+ k1=c1*c3+min4_c0;
+ /*k2= -c2*/
+ /*k3=1.0*/
+
+ /*Solve it for roots*/
+ db_SolveCubic(c_roots,&nr_c_roots,1.0,-c2,k1,k0);
+
+ if(nr_c_roots>0)
+ {
+ lz=c_roots[0];
+ lz_through2=lz/2.0;
+ ms=lz+c3c3through4_min_c2;
+ ns=lz_through2*lz_through2-c0;
+ mn=lz*c3through4-c1/2.0;
+
+ if((ms>=0.0)&&(ns>=0.0))
+ {
+ m=sqrt(ms);
+ n=sqrt(ns)*db_sign(mn);
+
+ db_SolveQuadratic(roots,nr_roots,
+ 1.0,c3through2+m,lz_through2+n);
+
+ db_SolveQuadratic(&roots[*nr_roots],&addroots,
+ 1.0,c3through2-m,lz_through2-n);
+
+ *nr_roots+=addroots;
+ }
+ else *nr_roots=0;
+ }
+ else *nr_roots=0;
+ }
+}
+
+void db_SolveQuarticForced(double *roots,int *nr_roots,double a,double b,double c,double d,double e)
+{
+ /*Normalized coefficients*/
+ double c0,c1,c2,c3;
+ /*Temporary coefficients*/
+ double c3through2,c3through4,c3c3through4_min_c2,min4_c0;
+ double lz,ms,ns,mn,m,n,lz_through2;
+ /*Cubic polynomial roots, nr of roots and coefficients*/
+ double c_roots[3];
+ int nr_c_roots;
+ double k0,k1;
+ /*nr additional roots from second quadratic*/
+ int addroots;
+
+ /*For nondegenerate quartics
+ [16mult 11add 2sqrt 1cubic 2quadratic=74flops 8funcs]*/
+
+ if(a==0.0) db_SolveCubic(roots,nr_roots,b,c,d,e);
+ else if(e==0.0)
+ {
+ db_SolveCubic(roots,nr_roots,a,b,c,d);
+ roots[*nr_roots]=0.0;
+ *nr_roots+=1;
+ }
+ else
+ {
+ /*Compute normalized coefficients*/
+ c3=b/a;
+ c2=c/a;
+ c1=d/a;
+ c0=e/a;
+ /*Compute temporary coefficients*/
+ c3through2=c3/2.0;
+ c3through4=c3/4.0;
+ c3c3through4_min_c2=c3*c3through4-c2;
+ min4_c0= -4.0*c0;
+ /*Compute coefficients of cubic*/
+ k0=min4_c0*c3c3through4_min_c2-c1*c1;
+ k1=c1*c3+min4_c0;
+ /*k2= -c2*/
+ /*k3=1.0*/
+
+ /*Solve it for roots*/
+ db_SolveCubic(c_roots,&nr_c_roots,1.0,-c2,k1,k0);
+
+ if(nr_c_roots>0)
+ {
+ lz=c_roots[0];
+ lz_through2=lz/2.0;
+ ms=lz+c3c3through4_min_c2;
+ ns=lz_through2*lz_through2-c0;
+ mn=lz*c3through4-c1/2.0;
+
+ if(ms<0.0) ms=0.0;
+ if(ns<0.0) ns=0.0;
+
+ m=sqrt(ms);
+ n=sqrt(ns)*db_sign(mn);
+
+ db_SolveQuadratic(roots,nr_roots,
+ 1.0,c3through2+m,lz_through2+n);
+
+ db_SolveQuadratic(&roots[*nr_roots],&addroots,
+ 1.0,c3through2-m,lz_through2-n);
+
+ *nr_roots+=addroots;
+ }
+ else *nr_roots=0;
+ }
+}
diff --git a/jni/feature_stab/db_vlvm/db_utilities_poly.h b/jni/feature_stab/db_vlvm/db_utilities_poly.h
new file mode 100644
index 000000000..1f8789077
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_poly.h
@@ -0,0 +1,383 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_poly.h,v 1.2 2010/09/03 12:00:11 bsouthall Exp $ */
+
+#ifndef DB_UTILITIES_POLY
+#define DB_UTILITIES_POLY
+
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMPolynomial (LM) Polynomial utilities (solvers, arithmetic, evaluation, etc.)
+ */
+/*\{*/
+
+/*!
+In debug mode closed form quadratic solving takes on the order of 15 microseconds
+while eig of the companion matrix takes about 1.1 milliseconds
+Speed-optimized code in release mode solves a quadratic in 0.3 microseconds on 450MHz
+*/
+inline void db_SolveQuadratic(double *roots,int *nr_roots,double a,double b,double c)
+{
+ double rs,srs,q;
+
+ /*For non-degenerate quadratics
+ [5 mult 2 add 1 sqrt=7flops 1func]*/
+ if(a==0.0)
+ {
+ if(b==0.0) *nr_roots=0;
+ else
+ {
+ roots[0]= -c/b;
+ *nr_roots=1;
+ }
+ }
+ else
+ {
+ rs=b*b-4.0*a*c;
+ if(rs>=0.0)
+ {
+ *nr_roots=2;
+ srs=sqrt(rs);
+ q= -0.5*(b+db_sign(b)*srs);
+ roots[0]=q/a;
+ /*If b is zero db_sign(b) returns 1,
+ so q is only zero when b=0 and c=0*/
+ if(q==0.0) *nr_roots=1;
+ else roots[1]=c/q;
+ }
+ else *nr_roots=0;
+ }
+}
+
+/*!
+In debug mode closed form cubic solving takes on the order of 45 microseconds
+while eig of the companion matrix takes about 1.3 milliseconds
+Speed-optimized code in release mode solves a cubic in 1.5 microseconds on 450MHz
+For a non-degenerate cubic with two roots, the first root is the single root and
+the second root is the double root
+*/
+DB_API void db_SolveCubic(double *roots,int *nr_roots,double a,double b,double c,double d);
+/*!
+In debug mode closed form quartic solving takes on the order of 0.1 milliseconds
+while eig of the companion matrix takes about 1.5 milliseconds
+Speed-optimized code in release mode solves a quartic in 2.6 microseconds on 450MHz*/
+DB_API void db_SolveQuartic(double *roots,int *nr_roots,double a,double b,double c,double d,double e);
+/*!
+Quartic solving where a solution is forced when splitting into quadratics, which
+can be good if the quartic is sometimes in fact a quadratic, such as in absolute orientation
+when the data is planar*/
+DB_API void db_SolveQuarticForced(double *roots,int *nr_roots,double a,double b,double c,double d,double e);
+
+inline double db_PolyEval1(const double p[2],double x)
+{
+ return(p[0]+x*p[1]);
+}
+
+inline void db_MultiplyPoly1_1(double *d,const double *a,const double *b)
+{
+ double a0,a1;
+ double b0,b1;
+ a0=a[0];a1=a[1];
+ b0=b[0];b1=b[1];
+
+ d[0]=a0*b0;
+ d[1]=a0*b1+a1*b0;
+ d[2]= a1*b1;
+}
+
+inline void db_MultiplyPoly0_2(double *d,const double *a,const double *b)
+{
+ double a0;
+ double b0,b1,b2;
+ a0=a[0];
+ b0=b[0];b1=b[1];b2=b[2];
+
+ d[0]=a0*b0;
+ d[1]=a0*b1;
+ d[2]=a0*b2;
+}
+
+inline void db_MultiplyPoly1_2(double *d,const double *a,const double *b)
+{
+ double a0,a1;
+ double b0,b1,b2;
+ a0=a[0];a1=a[1];
+ b0=b[0];b1=b[1];b2=b[2];
+
+ d[0]=a0*b0;
+ d[1]=a0*b1+a1*b0;
+ d[2]=a0*b2+a1*b1;
+ d[3]= a1*b2;
+}
+
+
+inline void db_MultiplyPoly1_3(double *d,const double *a,const double *b)
+{
+ double a0,a1;
+ double b0,b1,b2,b3;
+ a0=a[0];a1=a[1];
+ b0=b[0];b1=b[1];b2=b[2];b3=b[3];
+
+ d[0]=a0*b0;
+ d[1]=a0*b1+a1*b0;
+ d[2]=a0*b2+a1*b1;
+ d[3]=a0*b3+a1*b2;
+ d[4]= a1*b3;
+}
+/*!
+Multiply d=a*b where a is one degree and b is two degree*/
+inline void db_AddPolyProduct0_1(double *d,const double *a,const double *b)
+{
+ double a0;
+ double b0,b1;
+ a0=a[0];
+ b0=b[0];b1=b[1];
+
+ d[0]+=a0*b0;
+ d[1]+=a0*b1;
+}
+inline void db_AddPolyProduct0_2(double *d,const double *a,const double *b)
+{
+ double a0;
+ double b0,b1,b2;
+ a0=a[0];
+ b0=b[0];b1=b[1];b2=b[2];
+
+ d[0]+=a0*b0;
+ d[1]+=a0*b1;
+ d[2]+=a0*b2;
+}
+/*!
+Multiply d=a*b where a is one degree and b is two degree*/
+inline void db_SubtractPolyProduct0_0(double *d,const double *a,const double *b)
+{
+ double a0;
+ double b0;
+ a0=a[0];
+ b0=b[0];
+
+ d[0]-=a0*b0;
+}
+
+inline void db_SubtractPolyProduct0_1(double *d,const double *a,const double *b)
+{
+ double a0;
+ double b0,b1;
+ a0=a[0];
+ b0=b[0];b1=b[1];
+
+ d[0]-=a0*b0;
+ d[1]-=a0*b1;
+}
+
+inline void db_SubtractPolyProduct0_2(double *d,const double *a,const double *b)
+{
+ double a0;
+ double b0,b1,b2;
+ a0=a[0];
+ b0=b[0];b1=b[1];b2=b[2];
+
+ d[0]-=a0*b0;
+ d[1]-=a0*b1;
+ d[2]-=a0*b2;
+}
+
+inline void db_SubtractPolyProduct1_3(double *d,const double *a,const double *b)
+{
+ double a0,a1;
+ double b0,b1,b2,b3;
+ a0=a[0];a1=a[1];
+ b0=b[0];b1=b[1];b2=b[2];b3=b[3];
+
+ d[0]-=a0*b0;
+ d[1]-=a0*b1+a1*b0;
+ d[2]-=a0*b2+a1*b1;
+ d[3]-=a0*b3+a1*b2;
+ d[4]-= a1*b3;
+}
+
+inline void db_CharacteristicPolynomial4x4(double p[5],const double A[16])
+{
+ /*All two by two determinants of the first two rows*/
+ double two01[3],two02[3],two03[3],two12[3],two13[3],two23[3];
+ /*Polynomials representing third and fourth row of A*/
+ double P0[2],P1[2],P2[2],P3[2];
+ double P4[2],P5[2],P6[2],P7[2];
+ /*All three by three determinants of the first three rows*/
+ double neg_three0[4],neg_three1[4],three2[4],three3[4];
+
+ /*Compute 2x2 determinants*/
+ two01[0]=A[0]*A[5]-A[1]*A[4];
+ two01[1]= -(A[0]+A[5]);
+ two01[2]=1.0;
+
+ two02[0]=A[0]*A[6]-A[2]*A[4];
+ two02[1]= -A[6];
+
+ two03[0]=A[0]*A[7]-A[3]*A[4];
+ two03[1]= -A[7];
+
+ two12[0]=A[1]*A[6]-A[2]*A[5];
+ two12[1]=A[2];
+
+ two13[0]=A[1]*A[7]-A[3]*A[5];
+ two13[1]=A[3];
+
+ two23[0]=A[2]*A[7]-A[3]*A[6];
+
+ P0[0]=A[8];
+ P1[0]=A[9];
+ P2[0]=A[10];P2[1]= -1.0;
+ P3[0]=A[11];
+
+ P4[0]=A[12];
+ P5[0]=A[13];
+ P6[0]=A[14];
+ P7[0]=A[15];P7[1]= -1.0;
+
+ /*Compute 3x3 determinants.Note that the highest
+ degree polynomial goes first and the smaller ones
+ are added or subtracted from it*/
+ db_MultiplyPoly1_1( neg_three0,P2,two13);
+ db_SubtractPolyProduct0_0(neg_three0,P1,two23);
+ db_SubtractPolyProduct0_1(neg_three0,P3,two12);
+
+ db_MultiplyPoly1_1( neg_three1,P2,two03);
+ db_SubtractPolyProduct0_1(neg_three1,P3,two02);
+ db_SubtractPolyProduct0_0(neg_three1,P0,two23);
+
+ db_MultiplyPoly0_2( three2,P3,two01);
+ db_AddPolyProduct0_1( three2,P0,two13);
+ db_SubtractPolyProduct0_1(three2,P1,two03);
+
+ db_MultiplyPoly1_2( three3,P2,two01);
+ db_AddPolyProduct0_1( three3,P0,two12);
+ db_SubtractPolyProduct0_1(three3,P1,two02);
+
+ /*Compute 4x4 determinants*/
+ db_MultiplyPoly1_3( p,P7,three3);
+ db_AddPolyProduct0_2( p,P4,neg_three0);
+ db_SubtractPolyProduct0_2(p,P5,neg_three1);
+ db_SubtractPolyProduct0_2(p,P6,three2);
+}
+
+inline void db_RealEigenvalues4x4(double lambda[4],int *nr_roots,const double A[16],int forced=0)
+{
+ double p[5];
+
+ db_CharacteristicPolynomial4x4(p,A);
+ if(forced) db_SolveQuarticForced(lambda,nr_roots,p[4],p[3],p[2],p[1],p[0]);
+ else db_SolveQuartic(lambda,nr_roots,p[4],p[3],p[2],p[1],p[0]);
+}
+
+/*!
+Compute the unit norm eigenvector v of the matrix A corresponding
+to the eigenvalue lambda
+[96mult 60add 1sqrt=156flops 1sqrt]*/
+inline void db_EigenVector4x4(double v[4],double lambda,const double A[16])
+{
+ double a0,a5,a10,a15;
+ double d01,d02,d03,d12,d13,d23;
+ double e01,e02,e03,e12,e13,e23;
+ double C[16],n0,n1,n2,n3,m;
+
+ /*Compute diagonal
+ [4add=4flops]*/
+ a0=A[0]-lambda;
+ a5=A[5]-lambda;
+ a10=A[10]-lambda;
+ a15=A[15]-lambda;
+
+ /*Compute 2x2 determinants of rows 1,2 and 3,4
+ [24mult 12add=36flops]*/
+ d01=a0*a5 -A[1]*A[4];
+ d02=a0*A[6] -A[2]*A[4];
+ d03=a0*A[7] -A[3]*A[4];
+ d12=A[1]*A[6]-A[2]*a5;
+ d13=A[1]*A[7]-A[3]*a5;
+ d23=A[2]*A[7]-A[3]*A[6];
+
+ e01=A[8]*A[13]-A[9] *A[12];
+ e02=A[8]*A[14]-a10 *A[12];
+ e03=A[8]*a15 -A[11]*A[12];
+ e12=A[9]*A[14]-a10 *A[13];
+ e13=A[9]*a15 -A[11]*A[13];
+ e23=a10 *a15 -A[11]*A[14];
+
+ /*Compute matrix of cofactors
+ [48mult 32 add=80flops*/
+ C[0]= (a5 *e23-A[6]*e13+A[7]*e12);
+ C[1]= -(A[4]*e23-A[6]*e03+A[7]*e02);
+ C[2]= (A[4]*e13-a5 *e03+A[7]*e01);
+ C[3]= -(A[4]*e12-a5 *e02+A[6]*e01);
+
+ C[4]= -(A[1]*e23-A[2]*e13+A[3]*e12);
+ C[5]= (a0 *e23-A[2]*e03+A[3]*e02);
+ C[6]= -(a0 *e13-A[1]*e03+A[3]*e01);
+ C[7]= (a0 *e12-A[1]*e02+A[2]*e01);
+
+ C[8]= (A[13]*d23-A[14]*d13+a15 *d12);
+ C[9]= -(A[12]*d23-A[14]*d03+a15 *d02);
+ C[10]= (A[12]*d13-A[13]*d03+a15 *d01);
+ C[11]= -(A[12]*d12-A[13]*d02+A[14]*d01);
+
+ C[12]= -(A[9]*d23-a10 *d13+A[11]*d12);
+ C[13]= (A[8]*d23-a10 *d03+A[11]*d02);
+ C[14]= -(A[8]*d13-A[9]*d03+A[11]*d01);
+ C[15]= (A[8]*d12-A[9]*d02+a10 *d01);
+
+ /*Compute square sums of rows
+ [16mult 12add=28flops*/
+ n0=db_sqr(C[0]) +db_sqr(C[1]) +db_sqr(C[2]) +db_sqr(C[3]);
+ n1=db_sqr(C[4]) +db_sqr(C[5]) +db_sqr(C[6]) +db_sqr(C[7]);
+ n2=db_sqr(C[8]) +db_sqr(C[9]) +db_sqr(C[10])+db_sqr(C[11]);
+ n3=db_sqr(C[12])+db_sqr(C[13])+db_sqr(C[14])+db_sqr(C[15]);
+
+ /*Take the largest norm row and normalize
+ [4mult 1 sqrt=4flops 1sqrt]*/
+ if(n0>=n1 && n0>=n2 && n0>=n3)
+ {
+ m=db_SafeReciprocal(sqrt(n0));
+ db_MultiplyScalarCopy4(v,C,m);
+ }
+ else if(n1>=n2 && n1>=n3)
+ {
+ m=db_SafeReciprocal(sqrt(n1));
+ db_MultiplyScalarCopy4(v,&(C[4]),m);
+ }
+ else if(n2>=n3)
+ {
+ m=db_SafeReciprocal(sqrt(n2));
+ db_MultiplyScalarCopy4(v,&(C[8]),m);
+ }
+ else
+ {
+ m=db_SafeReciprocal(sqrt(n3));
+ db_MultiplyScalarCopy4(v,&(C[12]),m);
+ }
+}
+
+
+
+/*\}*/
+#endif /* DB_UTILITIES_POLY */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_random.h b/jni/feature_stab/db_vlvm/db_utilities_random.h
new file mode 100644
index 000000000..ef24039c1
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_random.h
@@ -0,0 +1,98 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_random.h,v 1.1 2010/08/19 18:09:20 bsouthall Exp $ */
+
+#ifndef DB_UTILITIES_RANDOM
+#define DB_UTILITIES_RANDOM
+
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMRandom (LM) Random numbers, random sampling
+ */
+/*\{*/
+/*!
+ Random Number generator. Initialize with non-zero
+integer value r. A double between zero and one is
+returned.
+\param r seed
+\return random double
+*/
+inline double db_QuickRandomDouble(int &r)
+{
+ int c;
+ c=r/127773;
+ r=16807*(r-c*127773)-2836*c;
+ if(r<0) r+=2147483647;
+ return((1.0/((double)2147483647))*r);
+ //return (((double)rand())/(double)RAND_MAX);
+}
+
+/*!
+Random Number generator. Initialize with non-zero
+integer value r. An int between and including 0 and max
+ \param r seed
+ \param max upped limit
+ \return random int
+*/
+inline int db_RandomInt(int &r,int max)
+{
+ double dtemp;
+ int itemp;
+ dtemp=db_QuickRandomDouble(r)*(max+1);
+ itemp=(int) dtemp;
+ if(itemp<=0) return(0);
+ if(itemp>=max) return(max);
+ return(itemp);
+}
+
+/*!
+ Generate a random sample indexing into [0..pool_size-1].
+ \param s sample (out) pre-allocated array of size sample_size
+ \param sample_size size of sample
+ \param pool_size upper limit on item index
+ \param r_seed random number generator seed
+ */
+inline void db_RandomSample(int *s,int sample_size,int pool_size,int &r_seed)
+{
+ int temp,temp2,i,j;
+
+ for(i=0;i<sample_size;i++)
+ {
+ temp=db_RandomInt(r_seed,pool_size-1-i);
+
+ for(j=0;j<i;j++)
+ {
+ if(s[j]<=temp) temp++;
+ else
+ {
+ /*swap*/
+ temp2=temp;
+ temp=s[j];
+ s[j]=temp2;
+ }
+ }
+ s[i]=temp;
+ }
+}
+/*\}*/
+#endif /* DB_UTILITIES_RANDOM */
diff --git a/jni/feature_stab/db_vlvm/db_utilities_rotation.h b/jni/feature_stab/db_vlvm/db_utilities_rotation.h
new file mode 100644
index 000000000..7f5f937b4
--- /dev/null
+++ b/jni/feature_stab/db_vlvm/db_utilities_rotation.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/* $Id: db_utilities_rotation.h,v 1.2 2010/09/03 12:00:11 bsouthall Exp $ */
+
+#ifndef DB_UTILITIES_ROTATION
+#define DB_UTILITIES_ROTATION
+
+#include "db_utilities.h"
+
+
+
+/*****************************************************************
+* Lean and mean begins here *
+*****************************************************************/
+/*!
+ * \defgroup LMRotation (LM) Rotation Utilities (quaternions, orthonormal)
+ */
+/*\{*/
+/*!
+ Takes a unit quaternion and gives its corresponding rotation matrix.
+ \param R rotation matrix (out)
+ \param q quaternion
+ */
+inline void db_QuaternionToRotation(double R[9],const double q[4])
+{
+ double q0q0,q0qx,q0qy,q0qz,qxqx,qxqy,qxqz,qyqy,qyqz,qzqz;
+
+ q0q0=q[0]*q[0];
+ q0qx=q[0]*q[1];
+ q0qy=q[0]*q[2];
+ q0qz=q[0]*q[3];
+ qxqx=q[1]*q[1];
+ qxqy=q[1]*q[2];
+ qxqz=q[1]*q[3];
+ qyqy=q[2]*q[2];
+ qyqz=q[2]*q[3];
+ qzqz=q[3]*q[3];
+
+ R[0]=q0q0+qxqx-qyqy-qzqz; R[1]=2.0*(qxqy-q0qz); R[2]=2.0*(qxqz+q0qy);
+ R[3]=2.0*(qxqy+q0qz); R[4]=q0q0-qxqx+qyqy-qzqz; R[5]=2.0*(qyqz-q0qx);
+ R[6]=2.0*(qxqz-q0qy); R[7]=2.0*(qyqz+q0qx); R[8]=q0q0-qxqx-qyqy+qzqz;
+}
+
+/*\}*/
+#endif /* DB_UTILITIES_ROTATION */
diff --git a/jni/feature_stab/doc/Readme.txt b/jni/feature_stab/doc/Readme.txt
new file mode 100644
index 000000000..fcd7c38c5
--- /dev/null
+++ b/jni/feature_stab/doc/Readme.txt
@@ -0,0 +1,3 @@
+To generate the html docs, execute
+doxygen dbreg_API_doxyfile
+
diff --git a/jni/feature_stab/doc/dbreg_API_doxyfile b/jni/feature_stab/doc/dbreg_API_doxyfile
new file mode 100755
index 000000000..dc61a9c0f
--- /dev/null
+++ b/jni/feature_stab/doc/dbreg_API_doxyfile
@@ -0,0 +1,1557 @@
+# Doxyfile 1.6.1
+
+# This file describes the settings to be used by the documentation system
+# doxygen (www.doxygen.org) for a project
+#
+# All text after a hash (#) is considered a comment and will be ignored
+# The format is:
+# TAG = value [value, ...]
+# For lists items can also be appended using:
+# TAG += value [value, ...]
+# Values that contain spaces should be placed between quotes (" ")
+
+#---------------------------------------------------------------------------
+# Project related configuration options
+#---------------------------------------------------------------------------
+
+# This tag specifies the encoding used for all characters in the config file
+# that follow. The default is UTF-8 which is also the encoding used for all
+# text before the first occurrence of this tag. Doxygen uses libiconv (or the
+# iconv built into libc) for the transcoding. See
+# http://www.gnu.org/software/libiconv for the list of possible encodings.
+
+DOXYFILE_ENCODING = UTF-8
+
+# The PROJECT_NAME tag is a single word (or a sequence of words surrounded
+# by quotes) that should identify the project.
+
+PROJECT_NAME =
+
+# The PROJECT_NUMBER tag can be used to enter a project or revision number.
+# This could be handy for archiving the generated documentation or
+# if some version control system is used.
+
+PROJECT_NUMBER =
+
+# The OUTPUT_DIRECTORY tag is used to specify the (relative or absolute)
+# base path where the generated documentation will be put.
+# If a relative path is entered, it will be relative to the location
+# where doxygen was started. If left blank the current directory will be used.
+
+OUTPUT_DIRECTORY = .
+
+# If the CREATE_SUBDIRS tag is set to YES, then doxygen will create
+# 4096 sub-directories (in 2 levels) under the output directory of each output
+# format and will distribute the generated files over these directories.
+# Enabling this option can be useful when feeding doxygen a huge amount of
+# source files, where putting all generated files in the same directory would
+# otherwise cause performance problems for the file system.
+
+CREATE_SUBDIRS = NO
+
+# The OUTPUT_LANGUAGE tag is used to specify the language in which all
+# documentation generated by doxygen is written. Doxygen will use this
+# information to generate all constant output in the proper language.
+# The default language is English, other supported languages are:
+# Afrikaans, Arabic, Brazilian, Catalan, Chinese, Chinese-Traditional,
+# Croatian, Czech, Danish, Dutch, Esperanto, Farsi, Finnish, French, German,
+# Greek, Hungarian, Italian, Japanese, Japanese-en (Japanese with English
+# messages), Korean, Korean-en, Lithuanian, Norwegian, Macedonian, Persian,
+# Polish, Portuguese, Romanian, Russian, Serbian, Serbian-Cyrilic, Slovak,
+# Slovene, Spanish, Swedish, Ukrainian, and Vietnamese.
+
+OUTPUT_LANGUAGE = English
+
+# If the BRIEF_MEMBER_DESC tag is set to YES (the default) Doxygen will
+# include brief member descriptions after the members that are listed in
+# the file and class documentation (similar to JavaDoc).
+# Set to NO to disable this.
+
+BRIEF_MEMBER_DESC = YES
+
+# If the REPEAT_BRIEF tag is set to YES (the default) Doxygen will prepend
+# the brief description of a member or function before the detailed description.
+# Note: if both HIDE_UNDOC_MEMBERS and BRIEF_MEMBER_DESC are set to NO, the
+# brief descriptions will be completely suppressed.
+
+REPEAT_BRIEF = YES
+
+# This tag implements a quasi-intelligent brief description abbreviator
+# that is used to form the text in various listings. Each string
+# in this list, if found as the leading text of the brief description, will be
+# stripped from the text and the result after processing the whole list, is
+# used as the annotated text. Otherwise, the brief description is used as-is.
+# If left blank, the following values are used ("$name" is automatically
+# replaced with the name of the entity): "The $name class" "The $name widget"
+# "The $name file" "is" "provides" "specifies" "contains"
+# "represents" "a" "an" "the"
+
+ABBREVIATE_BRIEF = "The $name class" \
+ "The $name widget" \
+ "The $name file" \
+ is \
+ provides \
+ specifies \
+ contains \
+ represents \
+ a \
+ an \
+ the
+
+# If the ALWAYS_DETAILED_SEC and REPEAT_BRIEF tags are both set to YES then
+# Doxygen will generate a detailed section even if there is only a brief
+# description.
+
+ALWAYS_DETAILED_SEC = NO
+
+# If the INLINE_INHERITED_MEMB tag is set to YES, doxygen will show all
+# inherited members of a class in the documentation of that class as if those
+# members were ordinary class members. Constructors, destructors and assignment
+# operators of the base classes will not be shown.
+
+INLINE_INHERITED_MEMB = NO
+
+# If the FULL_PATH_NAMES tag is set to YES then Doxygen will prepend the full
+# path before files name in the file list and in the header files. If set
+# to NO the shortest path that makes the file name unique will be used.
+
+FULL_PATH_NAMES = YES
+
+# If the FULL_PATH_NAMES tag is set to YES then the STRIP_FROM_PATH tag
+# can be used to strip a user-defined part of the path. Stripping is
+# only done if one of the specified strings matches the left-hand part of
+# the path. The tag can be used to show relative paths in the file list.
+# If left blank the directory from which doxygen is run is used as the
+# path to strip.
+
+STRIP_FROM_PATH = /Users/dimitri/doxygen/mail/1.5.7/doxywizard/
+
+# The STRIP_FROM_INC_PATH tag can be used to strip a user-defined part of
+# the path mentioned in the documentation of a class, which tells
+# the reader which header file to include in order to use a class.
+# If left blank only the name of the header file containing the class
+# definition is used. Otherwise one should specify the include paths that
+# are normally passed to the compiler using the -I flag.
+
+STRIP_FROM_INC_PATH =
+
+# If the SHORT_NAMES tag is set to YES, doxygen will generate much shorter
+# (but less readable) file names. This can be useful is your file systems
+# doesn't support long names like on DOS, Mac, or CD-ROM.
+
+SHORT_NAMES = NO
+
+# If the JAVADOC_AUTOBRIEF tag is set to YES then Doxygen
+# will interpret the first line (until the first dot) of a JavaDoc-style
+# comment as the brief description. If set to NO, the JavaDoc
+# comments will behave just like regular Qt-style comments
+# (thus requiring an explicit @brief command for a brief description.)
+
+JAVADOC_AUTOBRIEF = NO
+
+# If the QT_AUTOBRIEF tag is set to YES then Doxygen will
+# interpret the first line (until the first dot) of a Qt-style
+# comment as the brief description. If set to NO, the comments
+# will behave just like regular Qt-style comments (thus requiring
+# an explicit \brief command for a brief description.)
+
+QT_AUTOBRIEF = NO
+
+# The MULTILINE_CPP_IS_BRIEF tag can be set to YES to make Doxygen
+# treat a multi-line C++ special comment block (i.e. a block of //! or ///
+# comments) as a brief description. This used to be the default behaviour.
+# The new default is to treat a multi-line C++ comment block as a detailed
+# description. Set this tag to YES if you prefer the old behaviour instead.
+
+MULTILINE_CPP_IS_BRIEF = NO
+
+# If the INHERIT_DOCS tag is set to YES (the default) then an undocumented
+# member inherits the documentation from any documented member that it
+# re-implements.
+
+INHERIT_DOCS = YES
+
+# If the SEPARATE_MEMBER_PAGES tag is set to YES, then doxygen will produce
+# a new page for each member. If set to NO, the documentation of a member will
+# be part of the file/class/namespace that contains it.
+
+SEPARATE_MEMBER_PAGES = NO
+
+# The TAB_SIZE tag can be used to set the number of spaces in a tab.
+# Doxygen uses this value to replace tabs by spaces in code fragments.
+
+TAB_SIZE = 8
+
+# This tag can be used to specify a number of aliases that acts
+# as commands in the documentation. An alias has the form "name=value".
+# For example adding "sideeffect=\par Side Effects:\n" will allow you to
+# put the command \sideeffect (or @sideeffect) in the documentation, which
+# will result in a user-defined paragraph with heading "Side Effects:".
+# You can put \n's in the value part of an alias to insert newlines.
+
+ALIASES =
+
+# Set the OPTIMIZE_OUTPUT_FOR_C tag to YES if your project consists of C
+# sources only. Doxygen will then generate output that is more tailored for C.
+# For instance, some of the names that are used will be different. The list
+# of all members will be omitted, etc.
+
+OPTIMIZE_OUTPUT_FOR_C = NO
+
+# Set the OPTIMIZE_OUTPUT_JAVA tag to YES if your project consists of Java
+# sources only. Doxygen will then generate output that is more tailored for
+# Java. For instance, namespaces will be presented as packages, qualified
+# scopes will look different, etc.
+
+OPTIMIZE_OUTPUT_JAVA = NO
+
+# Set the OPTIMIZE_FOR_FORTRAN tag to YES if your project consists of Fortran
+# sources only. Doxygen will then generate output that is more tailored for
+# Fortran.
+
+OPTIMIZE_FOR_FORTRAN = NO
+
+# Set the OPTIMIZE_OUTPUT_VHDL tag to YES if your project consists of VHDL
+# sources. Doxygen will then generate output that is tailored for
+# VHDL.
+
+OPTIMIZE_OUTPUT_VHDL = NO
+
+# Doxygen selects the parser to use depending on the extension of the files it parses.
+# With this tag you can assign which parser to use for a given extension.
+# Doxygen has a built-in mapping, but you can override or extend it using this tag.
+# The format is ext=language, where ext is a file extension, and language is one of
+# the parsers supported by doxygen: IDL, Java, Javascript, C#, C, C++, D, PHP,
+# Objective-C, Python, Fortran, VHDL, C, C++. For instance to make doxygen treat
+# .inc files as Fortran files (default is PHP), and .f files as C (default is Fortran),
+# use: inc=Fortran f=C. Note that for custom extensions you also need to set
+# FILE_PATTERNS otherwise the files are not read by doxygen.
+
+EXTENSION_MAPPING =
+
+# If you use STL classes (i.e. std::string, std::vector, etc.) but do not want
+# to include (a tag file for) the STL sources as input, then you should
+# set this tag to YES in order to let doxygen match functions declarations and
+# definitions whose arguments contain STL classes (e.g. func(std::string); v.s.
+# func(std::string) {}). This also make the inheritance and collaboration
+# diagrams that involve STL classes more complete and accurate.
+
+BUILTIN_STL_SUPPORT = NO
+
+# If you use Microsoft's C++/CLI language, you should set this option to YES to
+# enable parsing support.
+
+CPP_CLI_SUPPORT = NO
+
+# Set the SIP_SUPPORT tag to YES if your project consists of sip sources only.
+# Doxygen will parse them like normal C++ but will assume all classes use public
+# instead of private inheritance when no explicit protection keyword is present.
+
+SIP_SUPPORT = NO
+
+# For Microsoft's IDL there are propget and propput attributes to indicate getter
+# and setter methods for a property. Setting this option to YES (the default)
+# will make doxygen to replace the get and set methods by a property in the
+# documentation. This will only work if the methods are indeed getting or
+# setting a simple type. If this is not the case, or you want to show the
+# methods anyway, you should set this option to NO.
+
+IDL_PROPERTY_SUPPORT = YES
+
+# If member grouping is used in the documentation and the DISTRIBUTE_GROUP_DOC
+# tag is set to YES, then doxygen will reuse the documentation of the first
+# member in the group (if any) for the other members of the group. By default
+# all members of a group must be documented explicitly.
+
+DISTRIBUTE_GROUP_DOC = NO
+
+# Set the SUBGROUPING tag to YES (the default) to allow class member groups of
+# the same type (for instance a group of public functions) to be put as a
+# subgroup of that type (e.g. under the Public Functions section). Set it to
+# NO to prevent subgrouping. Alternatively, this can be done per class using
+# the \nosubgrouping command.
+
+SUBGROUPING = YES
+
+# When TYPEDEF_HIDES_STRUCT is enabled, a typedef of a struct, union, or enum
+# is documented as struct, union, or enum with the name of the typedef. So
+# typedef struct TypeS {} TypeT, will appear in the documentation as a struct
+# with name TypeT. When disabled the typedef will appear as a member of a file,
+# namespace, or class. And the struct will be named TypeS. This can typically
+# be useful for C code in case the coding convention dictates that all compound
+# types are typedef'ed and only the typedef is referenced, never the tag name.
+
+TYPEDEF_HIDES_STRUCT = NO
+
+# The SYMBOL_CACHE_SIZE determines the size of the internal cache use to
+# determine which symbols to keep in memory and which to flush to disk.
+# When the cache is full, less often used symbols will be written to disk.
+# For small to medium size projects (<1000 input files) the default value is
+# probably good enough. For larger projects a too small cache size can cause
+# doxygen to be busy swapping symbols to and from disk most of the time
+# causing a significant performance penality.
+# If the system has enough physical memory increasing the cache will improve the
+# performance by keeping more symbols in memory. Note that the value works on
+# a logarithmic scale so increasing the size by one will rougly double the
+# memory usage. The cache size is given by this formula:
+# 2^(16+SYMBOL_CACHE_SIZE). The valid range is 0..9, the default is 0,
+# corresponding to a cache size of 2^16 = 65536 symbols
+
+SYMBOL_CACHE_SIZE = 0
+
+#---------------------------------------------------------------------------
+# Build related configuration options
+#---------------------------------------------------------------------------
+
+# If the EXTRACT_ALL tag is set to YES doxygen will assume all entities in
+# documentation are documented, even if no documentation was available.
+# Private class members and static file members will be hidden unless
+# the EXTRACT_PRIVATE and EXTRACT_STATIC tags are set to YES
+
+EXTRACT_ALL = NO
+
+# If the EXTRACT_PRIVATE tag is set to YES all private members of a class
+# will be included in the documentation.
+
+EXTRACT_PRIVATE = NO
+
+# If the EXTRACT_STATIC tag is set to YES all static members of a file
+# will be included in the documentation.
+
+EXTRACT_STATIC = NO
+
+# If the EXTRACT_LOCAL_CLASSES tag is set to YES classes (and structs)
+# defined locally in source files will be included in the documentation.
+# If set to NO only classes defined in header files are included.
+
+EXTRACT_LOCAL_CLASSES = YES
+
+# This flag is only useful for Objective-C code. When set to YES local
+# methods, which are defined in the implementation section but not in
+# the interface are included in the documentation.
+# If set to NO (the default) only methods in the interface are included.
+
+EXTRACT_LOCAL_METHODS = NO
+
+# If this flag is set to YES, the members of anonymous namespaces will be
+# extracted and appear in the documentation as a namespace called
+# 'anonymous_namespace{file}', where file will be replaced with the base
+# name of the file that contains the anonymous namespace. By default
+# anonymous namespace are hidden.
+
+EXTRACT_ANON_NSPACES = NO
+
+# If the HIDE_UNDOC_MEMBERS tag is set to YES, Doxygen will hide all
+# undocumented members of documented classes, files or namespaces.
+# If set to NO (the default) these members will be included in the
+# various overviews, but no documentation section is generated.
+# This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_MEMBERS = NO
+
+# If the HIDE_UNDOC_CLASSES tag is set to YES, Doxygen will hide all
+# undocumented classes that are normally visible in the class hierarchy.
+# If set to NO (the default) these classes will be included in the various
+# overviews. This option has no effect if EXTRACT_ALL is enabled.
+
+HIDE_UNDOC_CLASSES = NO
+
+# If the HIDE_FRIEND_COMPOUNDS tag is set to YES, Doxygen will hide all
+# friend (class|struct|union) declarations.
+# If set to NO (the default) these declarations will be included in the
+# documentation.
+
+HIDE_FRIEND_COMPOUNDS = NO
+
+# If the HIDE_IN_BODY_DOCS tag is set to YES, Doxygen will hide any
+# documentation blocks found inside the body of a function.
+# If set to NO (the default) these blocks will be appended to the
+# function's detailed documentation block.
+
+HIDE_IN_BODY_DOCS = NO
+
+# The INTERNAL_DOCS tag determines if documentation
+# that is typed after a \internal command is included. If the tag is set
+# to NO (the default) then the documentation will be excluded.
+# Set it to YES to include the internal documentation.
+
+INTERNAL_DOCS = NO
+
+# If the CASE_SENSE_NAMES tag is set to NO then Doxygen will only generate
+# file names in lower-case letters. If set to YES upper-case letters are also
+# allowed. This is useful if you have classes or files whose names only differ
+# in case and if your file system supports case sensitive file names. Windows
+# and Mac users are advised to set this option to NO.
+
+CASE_SENSE_NAMES = NO
+
+# If the HIDE_SCOPE_NAMES tag is set to NO (the default) then Doxygen
+# will show members with their full class and namespace scopes in the
+# documentation. If set to YES the scope will be hidden.
+
+HIDE_SCOPE_NAMES = NO
+
+# If the SHOW_INCLUDE_FILES tag is set to YES (the default) then Doxygen
+# will put a list of the files that are included by a file in the documentation
+# of that file.
+
+SHOW_INCLUDE_FILES = YES
+
+# If the INLINE_INFO tag is set to YES (the default) then a tag [inline]
+# is inserted in the documentation for inline members.
+
+INLINE_INFO = YES
+
+# If the SORT_MEMBER_DOCS tag is set to YES (the default) then doxygen
+# will sort the (detailed) documentation of file and class members
+# alphabetically by member name. If set to NO the members will appear in
+# declaration order.
+
+SORT_MEMBER_DOCS = YES
+
+# If the SORT_BRIEF_DOCS tag is set to YES then doxygen will sort the
+# brief documentation of file, namespace and class members alphabetically
+# by member name. If set to NO (the default) the members will appear in
+# declaration order.
+
+SORT_BRIEF_DOCS = NO
+
+# If the SORT_MEMBERS_CTORS_1ST tag is set to YES then doxygen
+# will sort the (brief and detailed) documentation of class members so that
+# constructors and destructors are listed first. If set to NO (the default)
+# the constructors will appear in the respective orders defined by
+# SORT_MEMBER_DOCS and SORT_BRIEF_DOCS.
+# This tag will be ignored for brief docs if SORT_BRIEF_DOCS is set to NO
+# and ignored for detailed docs if SORT_MEMBER_DOCS is set to NO.
+
+SORT_MEMBERS_CTORS_1ST = NO
+
+# If the SORT_GROUP_NAMES tag is set to YES then doxygen will sort the
+# hierarchy of group names into alphabetical order. If set to NO (the default)
+# the group names will appear in their defined order.
+
+SORT_GROUP_NAMES = NO
+
+# If the SORT_BY_SCOPE_NAME tag is set to YES, the class list will be
+# sorted by fully-qualified names, including namespaces. If set to
+# NO (the default), the class list will be sorted only by class name,
+# not including the namespace part.
+# Note: This option is not very useful if HIDE_SCOPE_NAMES is set to YES.
+# Note: This option applies only to the class list, not to the
+# alphabetical list.
+
+SORT_BY_SCOPE_NAME = NO
+
+# The GENERATE_TODOLIST tag can be used to enable (YES) or
+# disable (NO) the todo list. This list is created by putting \todo
+# commands in the documentation.
+
+GENERATE_TODOLIST = YES
+
+# The GENERATE_TESTLIST tag can be used to enable (YES) or
+# disable (NO) the test list. This list is created by putting \test
+# commands in the documentation.
+
+GENERATE_TESTLIST = YES
+
+# The GENERATE_BUGLIST tag can be used to enable (YES) or
+# disable (NO) the bug list. This list is created by putting \bug
+# commands in the documentation.
+
+GENERATE_BUGLIST = YES
+
+# The GENERATE_DEPRECATEDLIST tag can be used to enable (YES) or
+# disable (NO) the deprecated list. This list is created by putting
+# \deprecated commands in the documentation.
+
+GENERATE_DEPRECATEDLIST= YES
+
+# The ENABLED_SECTIONS tag can be used to enable conditional
+# documentation sections, marked by \if sectionname ... \endif.
+
+ENABLED_SECTIONS =
+
+# The MAX_INITIALIZER_LINES tag determines the maximum number of lines
+# the initial value of a variable or define consists of for it to appear in
+# the documentation. If the initializer consists of more lines than specified
+# here it will be hidden. Use a value of 0 to hide initializers completely.
+# The appearance of the initializer of individual variables and defines in the
+# documentation can be controlled using \showinitializer or \hideinitializer
+# command in the documentation regardless of this setting.
+
+MAX_INITIALIZER_LINES = 30
+
+# Set the SHOW_USED_FILES tag to NO to disable the list of files generated
+# at the bottom of the documentation of classes and structs. If set to YES the
+# list will mention the files that were used to generate the documentation.
+
+SHOW_USED_FILES = YES
+
+# If the sources in your project are distributed over multiple directories
+# then setting the SHOW_DIRECTORIES tag to YES will show the directory hierarchy
+# in the documentation. The default is NO.
+
+SHOW_DIRECTORIES = NO
+
+# Set the SHOW_FILES tag to NO to disable the generation of the Files page.
+# This will remove the Files entry from the Quick Index and from the
+# Folder Tree View (if specified). The default is YES.
+
+SHOW_FILES = YES
+
+# Set the SHOW_NAMESPACES tag to NO to disable the generation of the
+# Namespaces page. This will remove the Namespaces entry from the Quick Index
+# and from the Folder Tree View (if specified). The default is YES.
+
+SHOW_NAMESPACES = YES
+
+# The FILE_VERSION_FILTER tag can be used to specify a program or script that
+# doxygen should invoke to get the current version for each file (typically from
+# the version control system). Doxygen will invoke the program by executing (via
+# popen()) the command <command> <input-file>, where <command> is the value of
+# the FILE_VERSION_FILTER tag, and <input-file> is the name of an input file
+# provided by doxygen. Whatever the program writes to standard output
+# is used as the file version. See the manual for examples.
+
+FILE_VERSION_FILTER =
+
+# The LAYOUT_FILE tag can be used to specify a layout file which will be parsed by
+# doxygen. The layout file controls the global structure of the generated output files
+# in an output format independent way. The create the layout file that represents
+# doxygen's defaults, run doxygen with the -l option. You can optionally specify a
+# file name after the option, if omitted DoxygenLayout.xml will be used as the name
+# of the layout file.
+
+LAYOUT_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to warning and progress messages
+#---------------------------------------------------------------------------
+
+# The QUIET tag can be used to turn on/off the messages that are generated
+# by doxygen. Possible values are YES and NO. If left blank NO is used.
+
+QUIET = NO
+
+# The WARNINGS tag can be used to turn on/off the warning messages that are
+# generated by doxygen. Possible values are YES and NO. If left blank
+# NO is used.
+
+WARNINGS = YES
+
+# If WARN_IF_UNDOCUMENTED is set to YES, then doxygen will generate warnings
+# for undocumented members. If EXTRACT_ALL is set to YES then this flag will
+# automatically be disabled.
+
+WARN_IF_UNDOCUMENTED = YES
+
+# If WARN_IF_DOC_ERROR is set to YES, doxygen will generate warnings for
+# potential errors in the documentation, such as not documenting some
+# parameters in a documented function, or documenting parameters that
+# don't exist or using markup commands wrongly.
+
+WARN_IF_DOC_ERROR = YES
+
+# This WARN_NO_PARAMDOC option can be abled to get warnings for
+# functions that are documented, but have no documentation for their parameters
+# or return value. If set to NO (the default) doxygen will only warn about
+# wrong or incomplete parameter documentation, but not about the absence of
+# documentation.
+
+WARN_NO_PARAMDOC = NO
+
+# The WARN_FORMAT tag determines the format of the warning messages that
+# doxygen can produce. The string should contain the $file, $line, and $text
+# tags, which will be replaced by the file and line number from which the
+# warning originated and the warning text. Optionally the format may contain
+# $version, which will be replaced by the version of the file (if it could
+# be obtained via FILE_VERSION_FILTER)
+
+WARN_FORMAT = "$file:$line: $text"
+
+# The WARN_LOGFILE tag can be used to specify a file to which warning
+# and error messages should be written. If left blank the output is written
+# to stderr.
+
+WARN_LOGFILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the input files
+#---------------------------------------------------------------------------
+
+# The INPUT tag can be used to specify the files and/or directories that contain
+# documented source files. You may enter file names like "myfile.cpp" or
+# directories like "/usr/src/myproject". Separate the files or directories
+# with spaces.
+
+INPUT = ../src/dbreg/dbreg.h
+
+# This tag can be used to specify the character encoding of the source files
+# that doxygen parses. Internally doxygen uses the UTF-8 encoding, which is
+# also the default input encoding. Doxygen uses libiconv (or the iconv built
+# into libc) for the transcoding. See http://www.gnu.org/software/libiconv for
+# the list of possible encodings.
+
+INPUT_ENCODING = UTF-8
+
+# If the value of the INPUT tag contains directories, you can use the
+# FILE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank the following patterns are tested:
+# *.c *.cc *.cxx *.cpp *.c++ *.java *.ii *.ixx *.ipp *.i++ *.inl *.h *.hh *.hxx
+# *.hpp *.h++ *.idl *.odl *.cs *.php *.php3 *.inc *.m *.mm *.py *.f90
+
+FILE_PATTERNS = *.c \
+ *.cc \
+ *.cxx \
+ *.cpp \
+ *.c++ \
+ *.d \
+ *.java \
+ *.ii \
+ *.ixx \
+ *.ipp \
+ *.i++ \
+ *.inl \
+ *.h \
+ *.hh \
+ *.hxx \
+ *.hpp \
+ *.h++ \
+ *.idl \
+ *.odl \
+ *.cs \
+ *.php \
+ *.php3 \
+ *.inc \
+ *.m \
+ *.mm \
+ *.dox \
+ *.py \
+ *.f90 \
+ *.f \
+ *.vhd \
+ *.vhdl
+
+# The RECURSIVE tag can be used to turn specify whether or not subdirectories
+# should be searched for input files as well. Possible values are YES and NO.
+# If left blank NO is used.
+
+RECURSIVE = NO
+
+# The EXCLUDE tag can be used to specify files and/or directories that should
+# excluded from the INPUT source files. This way you can easily exclude a
+# subdirectory from a directory tree whose root is specified with the INPUT tag.
+
+EXCLUDE =
+
+# The EXCLUDE_SYMLINKS tag can be used select whether or not files or
+# directories that are symbolic links (a Unix filesystem feature) are excluded
+# from the input.
+
+EXCLUDE_SYMLINKS = NO
+
+# If the value of the INPUT tag contains directories, you can use the
+# EXCLUDE_PATTERNS tag to specify one or more wildcard patterns to exclude
+# certain files from those directories. Note that the wildcards are matched
+# against the file with absolute path, so to exclude all test directories
+# for example use the pattern */test/*
+
+EXCLUDE_PATTERNS =
+
+# The EXCLUDE_SYMBOLS tag can be used to specify one or more symbol names
+# (namespaces, classes, functions, etc.) that should be excluded from the
+# output. The symbol name can be a fully qualified name, a word, or if the
+# wildcard * is used, a substring. Examples: ANamespace, AClass,
+# AClass::ANamespace, ANamespace::*Test
+
+EXCLUDE_SYMBOLS =
+
+# The EXAMPLE_PATH tag can be used to specify one or more files or
+# directories that contain example code fragments that are included (see
+# the \include command).
+
+EXAMPLE_PATH =
+
+# If the value of the EXAMPLE_PATH tag contains directories, you can use the
+# EXAMPLE_PATTERNS tag to specify one or more wildcard pattern (like *.cpp
+# and *.h) to filter out the source-files in the directories. If left
+# blank all files are included.
+
+EXAMPLE_PATTERNS = *
+
+# If the EXAMPLE_RECURSIVE tag is set to YES then subdirectories will be
+# searched for input files to be used with the \include or \dontinclude
+# commands irrespective of the value of the RECURSIVE tag.
+# Possible values are YES and NO. If left blank NO is used.
+
+EXAMPLE_RECURSIVE = NO
+
+# The IMAGE_PATH tag can be used to specify one or more files or
+# directories that contain image that are included in the documentation (see
+# the \image command).
+
+IMAGE_PATH =
+
+# The INPUT_FILTER tag can be used to specify a program that doxygen should
+# invoke to filter for each input file. Doxygen will invoke the filter program
+# by executing (via popen()) the command <filter> <input-file>, where <filter>
+# is the value of the INPUT_FILTER tag, and <input-file> is the name of an
+# input file. Doxygen will then use the output that the filter program writes
+# to standard output. If FILTER_PATTERNS is specified, this tag will be
+# ignored.
+
+INPUT_FILTER =
+
+# The FILTER_PATTERNS tag can be used to specify filters on a per file pattern
+# basis. Doxygen will compare the file name with each pattern and apply the
+# filter if there is a match. The filters are a list of the form:
+# pattern=filter (like *.cpp=my_cpp_filter). See INPUT_FILTER for further
+# info on how filters are used. If FILTER_PATTERNS is empty, INPUT_FILTER
+# is applied to all files.
+
+FILTER_PATTERNS =
+
+# If the FILTER_SOURCE_FILES tag is set to YES, the input filter (if set using
+# INPUT_FILTER) will be used to filter the input files when producing source
+# files to browse (i.e. when SOURCE_BROWSER is set to YES).
+
+FILTER_SOURCE_FILES = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to source browsing
+#---------------------------------------------------------------------------
+
+# If the SOURCE_BROWSER tag is set to YES then a list of source files will
+# be generated. Documented entities will be cross-referenced with these sources.
+# Note: To get rid of all source code in the generated output, make sure also
+# VERBATIM_HEADERS is set to NO.
+
+SOURCE_BROWSER = NO
+
+# Setting the INLINE_SOURCES tag to YES will include the body
+# of functions and classes directly in the documentation.
+
+INLINE_SOURCES = NO
+
+# Setting the STRIP_CODE_COMMENTS tag to YES (the default) will instruct
+# doxygen to hide any special comment blocks from generated source code
+# fragments. Normal C and C++ comments will always remain visible.
+
+STRIP_CODE_COMMENTS = YES
+
+# If the REFERENCED_BY_RELATION tag is set to YES
+# then for each documented function all documented
+# functions referencing it will be listed.
+
+REFERENCED_BY_RELATION = NO
+
+# If the REFERENCES_RELATION tag is set to YES
+# then for each documented function all documented entities
+# called/used by that function will be listed.
+
+REFERENCES_RELATION = NO
+
+# If the REFERENCES_LINK_SOURCE tag is set to YES (the default)
+# and SOURCE_BROWSER tag is set to YES, then the hyperlinks from
+# functions in REFERENCES_RELATION and REFERENCED_BY_RELATION lists will
+# link to the source code. Otherwise they will link to the documentation.
+
+REFERENCES_LINK_SOURCE = YES
+
+# If the USE_HTAGS tag is set to YES then the references to source code
+# will point to the HTML generated by the htags(1) tool instead of doxygen
+# built-in source browser. The htags tool is part of GNU's global source
+# tagging system (see http://www.gnu.org/software/global/global.html). You
+# will need version 4.8.6 or higher.
+
+USE_HTAGS = NO
+
+# If the VERBATIM_HEADERS tag is set to YES (the default) then Doxygen
+# will generate a verbatim copy of the header file for each class for
+# which an include is specified. Set to NO to disable this.
+
+VERBATIM_HEADERS = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the alphabetical class index
+#---------------------------------------------------------------------------
+
+# If the ALPHABETICAL_INDEX tag is set to YES, an alphabetical index
+# of all compounds will be generated. Enable this if the project
+# contains a lot of classes, structs, unions or interfaces.
+
+ALPHABETICAL_INDEX = NO
+
+# If the alphabetical index is enabled (see ALPHABETICAL_INDEX) then
+# the COLS_IN_ALPHA_INDEX tag can be used to specify the number of columns
+# in which this list will be split (can be a number in the range [1..20])
+
+COLS_IN_ALPHA_INDEX = 5
+
+# In case all classes in a project start with a common prefix, all
+# classes will be put under the same header in the alphabetical index.
+# The IGNORE_PREFIX tag can be used to specify one or more prefixes that
+# should be ignored while generating the index headers.
+
+IGNORE_PREFIX =
+
+#---------------------------------------------------------------------------
+# configuration options related to the HTML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_HTML tag is set to YES (the default) Doxygen will
+# generate HTML output.
+
+GENERATE_HTML = YES
+
+# The HTML_OUTPUT tag is used to specify where the HTML docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `html' will be used as the default path.
+
+HTML_OUTPUT = html
+
+# The HTML_FILE_EXTENSION tag can be used to specify the file extension for
+# each generated HTML page (for example: .htm,.php,.asp). If it is left blank
+# doxygen will generate files with .html extension.
+
+HTML_FILE_EXTENSION = .html
+
+# The HTML_HEADER tag can be used to specify a personal HTML header for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard header.
+
+HTML_HEADER =
+
+# The HTML_FOOTER tag can be used to specify a personal HTML footer for
+# each generated HTML page. If it is left blank doxygen will generate a
+# standard footer.
+
+HTML_FOOTER =
+
+# The HTML_STYLESHEET tag can be used to specify a user-defined cascading
+# style sheet that is used by each HTML page. It can be used to
+# fine-tune the look of the HTML output. If the tag is left blank doxygen
+# will generate a default style sheet. Note that doxygen will try to copy
+# the style sheet file to the HTML output directory, so don't put your own
+# stylesheet in the HTML output directory as well, or it will be erased!
+
+HTML_STYLESHEET =
+
+# If the HTML_ALIGN_MEMBERS tag is set to YES, the members of classes,
+# files or namespaces will be aligned in HTML using tables. If set to
+# NO a bullet list will be used.
+
+HTML_ALIGN_MEMBERS = YES
+
+# If the HTML_DYNAMIC_SECTIONS tag is set to YES then the generated HTML
+# documentation will contain sections that can be hidden and shown after the
+# page has loaded. For this to work a browser that supports
+# JavaScript and DHTML is required (for instance Mozilla 1.0+, Firefox
+# Netscape 6.0+, Internet explorer 5.0+, Konqueror, or Safari).
+
+HTML_DYNAMIC_SECTIONS = NO
+
+# If the GENERATE_DOCSET tag is set to YES, additional index files
+# will be generated that can be used as input for Apple's Xcode 3
+# integrated development environment, introduced with OSX 10.5 (Leopard).
+# To create a documentation set, doxygen will generate a Makefile in the
+# HTML output directory. Running make will produce the docset in that
+# directory and running "make install" will install the docset in
+# ~/Library/Developer/Shared/Documentation/DocSets so that Xcode will find
+# it at startup.
+# See http://developer.apple.com/tools/creatingdocsetswithdoxygen.html for more information.
+
+GENERATE_DOCSET = NO
+
+# When GENERATE_DOCSET tag is set to YES, this tag determines the name of the
+# feed. A documentation feed provides an umbrella under which multiple
+# documentation sets from a single provider (such as a company or product suite)
+# can be grouped.
+
+DOCSET_FEEDNAME = "Doxygen generated docs"
+
+# When GENERATE_DOCSET tag is set to YES, this tag specifies a string that
+# should uniquely identify the documentation set bundle. This should be a
+# reverse domain-name style string, e.g. com.mycompany.MyDocSet. Doxygen
+# will append .docset to the name.
+
+DOCSET_BUNDLE_ID = org.doxygen.Project
+
+# If the GENERATE_HTMLHELP tag is set to YES, additional index files
+# will be generated that can be used as input for tools like the
+# Microsoft HTML help workshop to generate a compiled HTML help file (.chm)
+# of the generated HTML documentation.
+
+GENERATE_HTMLHELP = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_FILE tag can
+# be used to specify the file name of the resulting .chm file. You
+# can add a path in front of the file if the result should not be
+# written to the html output directory.
+
+CHM_FILE =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the HHC_LOCATION tag can
+# be used to specify the location (absolute path including file name) of
+# the HTML help compiler (hhc.exe). If non-empty doxygen will try to run
+# the HTML help compiler on the generated index.hhp.
+
+HHC_LOCATION =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the GENERATE_CHI flag
+# controls if a separate .chi index file is generated (YES) or that
+# it should be included in the master .chm file (NO).
+
+GENERATE_CHI = NO
+
+# If the GENERATE_HTMLHELP tag is set to YES, the CHM_INDEX_ENCODING
+# is used to encode HtmlHelp index (hhk), content (hhc) and project file
+# content.
+
+CHM_INDEX_ENCODING =
+
+# If the GENERATE_HTMLHELP tag is set to YES, the BINARY_TOC flag
+# controls whether a binary table of contents is generated (YES) or a
+# normal table of contents (NO) in the .chm file.
+
+BINARY_TOC = NO
+
+# The TOC_EXPAND flag can be set to YES to add extra items for group members
+# to the contents of the HTML help documentation and to the tree view.
+
+TOC_EXPAND = NO
+
+# If the GENERATE_QHP tag is set to YES and both QHP_NAMESPACE and QHP_VIRTUAL_FOLDER
+# are set, an additional index file will be generated that can be used as input for
+# Qt's qhelpgenerator to generate a Qt Compressed Help (.qch) of the generated
+# HTML documentation.
+
+GENERATE_QHP = NO
+
+# If the QHG_LOCATION tag is specified, the QCH_FILE tag can
+# be used to specify the file name of the resulting .qch file.
+# The path specified is relative to the HTML output folder.
+
+QCH_FILE =
+
+# The QHP_NAMESPACE tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#namespace
+
+QHP_NAMESPACE =
+
+# The QHP_VIRTUAL_FOLDER tag specifies the namespace to use when generating
+# Qt Help Project output. For more information please see
+# http://doc.trolltech.com/qthelpproject.html#virtual-folders
+
+QHP_VIRTUAL_FOLDER = doc
+
+# If QHP_CUST_FILTER_NAME is set, it specifies the name of a custom filter to add.
+# For more information please see
+# http://doc.trolltech.com/qthelpproject.html#custom-filters
+
+QHP_CUST_FILTER_NAME =
+
+# The QHP_CUST_FILT_ATTRS tag specifies the list of the attributes of the custom filter to add.For more information please see
+# <a href="http://doc.trolltech.com/qthelpproject.html#custom-filters">Qt Help Project / Custom Filters</a>.
+
+QHP_CUST_FILTER_ATTRS =
+
+# The QHP_SECT_FILTER_ATTRS tag specifies the list of the attributes this project's
+# filter section matches.
+# <a href="http://doc.trolltech.com/qthelpproject.html#filter-attributes">Qt Help Project / Filter Attributes</a>.
+
+QHP_SECT_FILTER_ATTRS =
+
+# If the GENERATE_QHP tag is set to YES, the QHG_LOCATION tag can
+# be used to specify the location of Qt's qhelpgenerator.
+# If non-empty doxygen will try to run qhelpgenerator on the generated
+# .qhp file.
+
+QHG_LOCATION =
+
+# The DISABLE_INDEX tag can be used to turn on/off the condensed index at
+# top of each HTML page. The value NO (the default) enables the index and
+# the value YES disables it.
+
+DISABLE_INDEX = NO
+
+# This tag can be used to set the number of enum values (range [1..20])
+# that doxygen will group on one line in the generated HTML documentation.
+
+ENUM_VALUES_PER_LINE = 4
+
+# The GENERATE_TREEVIEW tag is used to specify whether a tree-like index
+# structure should be generated to display hierarchical information.
+# If the tag value is set to YES, a side panel will be generated
+# containing a tree-like index structure (just like the one that
+# is generated for HTML Help). For this to work a browser that supports
+# JavaScript, DHTML, CSS and frames is required (i.e. any modern browser).
+# Windows users are probably better off using the HTML help feature.
+
+GENERATE_TREEVIEW = NO
+
+# By enabling USE_INLINE_TREES, doxygen will generate the Groups, Directories,
+# and Class Hierarchy pages using a tree view instead of an ordered list.
+
+USE_INLINE_TREES = NO
+
+# If the treeview is enabled (see GENERATE_TREEVIEW) then this tag can be
+# used to set the initial width (in pixels) of the frame in which the tree
+# is shown.
+
+TREEVIEW_WIDTH = 250
+
+# Use this tag to change the font size of Latex formulas included
+# as images in the HTML documentation. The default is 10. Note that
+# when you change the font size after a successful doxygen run you need
+# to manually remove any form_*.png images from the HTML output directory
+# to force them to be regenerated.
+
+FORMULA_FONTSIZE = 10
+
+# When the SEARCHENGINE tag is enable doxygen will generate a search box
+# for the HTML output. The underlying search engine uses javascript
+# and DHTML and should work on any modern browser. Note that when using
+# HTML help (GENERATE_HTMLHELP) or Qt help (GENERATE_QHP)
+# there is already a search function so this one should typically
+# be disabled.
+
+SEARCHENGINE = YES
+
+#---------------------------------------------------------------------------
+# configuration options related to the LaTeX output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_LATEX tag is set to YES (the default) Doxygen will
+# generate Latex output.
+
+GENERATE_LATEX = NO
+
+# The LATEX_OUTPUT tag is used to specify where the LaTeX docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `latex' will be used as the default path.
+
+LATEX_OUTPUT = latex
+
+# The LATEX_CMD_NAME tag can be used to specify the LaTeX command name to be
+# invoked. If left blank `latex' will be used as the default command name.
+
+LATEX_CMD_NAME = latex
+
+# The MAKEINDEX_CMD_NAME tag can be used to specify the command name to
+# generate index for LaTeX. If left blank `makeindex' will be used as the
+# default command name.
+
+MAKEINDEX_CMD_NAME = makeindex
+
+# If the COMPACT_LATEX tag is set to YES Doxygen generates more compact
+# LaTeX documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_LATEX = NO
+
+# The PAPER_TYPE tag can be used to set the paper type that is used
+# by the printer. Possible values are: a4, a4wide, letter, legal and
+# executive. If left blank a4wide will be used.
+
+PAPER_TYPE = a4wide
+
+# The EXTRA_PACKAGES tag can be to specify one or more names of LaTeX
+# packages that should be included in the LaTeX output.
+
+EXTRA_PACKAGES =
+
+# The LATEX_HEADER tag can be used to specify a personal LaTeX header for
+# the generated latex document. The header should contain everything until
+# the first chapter. If it is left blank doxygen will generate a
+# standard header. Notice: only use this tag if you know what you are doing!
+
+LATEX_HEADER =
+
+# If the PDF_HYPERLINKS tag is set to YES, the LaTeX that is generated
+# is prepared for conversion to pdf (using ps2pdf). The pdf file will
+# contain links (just like the HTML output) instead of page references
+# This makes the output suitable for online browsing using a pdf viewer.
+
+PDF_HYPERLINKS = YES
+
+# If the USE_PDFLATEX tag is set to YES, pdflatex will be used instead of
+# plain latex in the generated Makefile. Set this option to YES to get a
+# higher quality PDF documentation.
+
+USE_PDFLATEX = YES
+
+# If the LATEX_BATCHMODE tag is set to YES, doxygen will add the \\batchmode.
+# command to the generated LaTeX files. This will instruct LaTeX to keep
+# running if errors occur, instead of asking the user for help.
+# This option is also used when generating formulas in HTML.
+
+LATEX_BATCHMODE = NO
+
+# If LATEX_HIDE_INDICES is set to YES then doxygen will not
+# include the index chapters (such as File Index, Compound Index, etc.)
+# in the output.
+
+LATEX_HIDE_INDICES = NO
+
+# If LATEX_SOURCE_CODE is set to YES then doxygen will include
+# source code with syntax highlighting in the LaTeX output.
+# Note that which sources are shown also depends on other settings
+# such as SOURCE_BROWSER.
+
+LATEX_SOURCE_CODE = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the RTF output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_RTF tag is set to YES Doxygen will generate RTF output
+# The RTF output is optimized for Word 97 and may not look very pretty with
+# other RTF readers or editors.
+
+GENERATE_RTF = NO
+
+# The RTF_OUTPUT tag is used to specify where the RTF docs will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `rtf' will be used as the default path.
+
+RTF_OUTPUT = rtf
+
+# If the COMPACT_RTF tag is set to YES Doxygen generates more compact
+# RTF documents. This may be useful for small projects and may help to
+# save some trees in general.
+
+COMPACT_RTF = NO
+
+# If the RTF_HYPERLINKS tag is set to YES, the RTF that is generated
+# will contain hyperlink fields. The RTF file will
+# contain links (just like the HTML output) instead of page references.
+# This makes the output suitable for online browsing using WORD or other
+# programs which support those fields.
+# Note: wordpad (write) and others do not support links.
+
+RTF_HYPERLINKS = NO
+
+# Load stylesheet definitions from file. Syntax is similar to doxygen's
+# config file, i.e. a series of assignments. You only have to provide
+# replacements, missing definitions are set to their default value.
+
+RTF_STYLESHEET_FILE =
+
+# Set optional variables used in the generation of an rtf document.
+# Syntax is similar to doxygen's config file.
+
+RTF_EXTENSIONS_FILE =
+
+#---------------------------------------------------------------------------
+# configuration options related to the man page output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_MAN tag is set to YES (the default) Doxygen will
+# generate man pages
+
+GENERATE_MAN = NO
+
+# The MAN_OUTPUT tag is used to specify where the man pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `man' will be used as the default path.
+
+MAN_OUTPUT = man
+
+# The MAN_EXTENSION tag determines the extension that is added to
+# the generated man pages (default is the subroutine's section .3)
+
+MAN_EXTENSION = .3
+
+# If the MAN_LINKS tag is set to YES and Doxygen generates man output,
+# then it will generate one additional man file for each entity
+# documented in the real man page(s). These additional files
+# only source the real man page, but without them the man command
+# would be unable to find the correct page. The default is NO.
+
+MAN_LINKS = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the XML output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_XML tag is set to YES Doxygen will
+# generate an XML file that captures the structure of
+# the code including all documentation.
+
+GENERATE_XML = NO
+
+# The XML_OUTPUT tag is used to specify where the XML pages will be put.
+# If a relative path is entered the value of OUTPUT_DIRECTORY will be
+# put in front of it. If left blank `xml' will be used as the default path.
+
+XML_OUTPUT = xml
+
+# The XML_SCHEMA tag can be used to specify an XML schema,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_SCHEMA =
+
+# The XML_DTD tag can be used to specify an XML DTD,
+# which can be used by a validating XML parser to check the
+# syntax of the XML files.
+
+XML_DTD =
+
+# If the XML_PROGRAMLISTING tag is set to YES Doxygen will
+# dump the program listings (including syntax highlighting
+# and cross-referencing information) to the XML output. Note that
+# enabling this will significantly increase the size of the XML output.
+
+XML_PROGRAMLISTING = YES
+
+#---------------------------------------------------------------------------
+# configuration options for the AutoGen Definitions output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_AUTOGEN_DEF tag is set to YES Doxygen will
+# generate an AutoGen Definitions (see autogen.sf.net) file
+# that captures the structure of the code including all
+# documentation. Note that this feature is still experimental
+# and incomplete at the moment.
+
+GENERATE_AUTOGEN_DEF = NO
+
+#---------------------------------------------------------------------------
+# configuration options related to the Perl module output
+#---------------------------------------------------------------------------
+
+# If the GENERATE_PERLMOD tag is set to YES Doxygen will
+# generate a Perl module file that captures the structure of
+# the code including all documentation. Note that this
+# feature is still experimental and incomplete at the
+# moment.
+
+GENERATE_PERLMOD = NO
+
+# If the PERLMOD_LATEX tag is set to YES Doxygen will generate
+# the necessary Makefile rules, Perl scripts and LaTeX code to be able
+# to generate PDF and DVI output from the Perl module output.
+
+PERLMOD_LATEX = NO
+
+# If the PERLMOD_PRETTY tag is set to YES the Perl module output will be
+# nicely formatted so it can be parsed by a human reader. This is useful
+# if you want to understand what is going on. On the other hand, if this
+# tag is set to NO the size of the Perl module output will be much smaller
+# and Perl will parse it just the same.
+
+PERLMOD_PRETTY = YES
+
+# The names of the make variables in the generated doxyrules.make file
+# are prefixed with the string contained in PERLMOD_MAKEVAR_PREFIX.
+# This is useful so different doxyrules.make files included by the same
+# Makefile don't overwrite each other's variables.
+
+PERLMOD_MAKEVAR_PREFIX =
+
+#---------------------------------------------------------------------------
+# Configuration options related to the preprocessor
+#---------------------------------------------------------------------------
+
+# If the ENABLE_PREPROCESSING tag is set to YES (the default) Doxygen will
+# evaluate all C-preprocessor directives found in the sources and include
+# files.
+
+ENABLE_PREPROCESSING = YES
+
+# If the MACRO_EXPANSION tag is set to YES Doxygen will expand all macro
+# names in the source code. If set to NO (the default) only conditional
+# compilation will be performed. Macro expansion can be done in a controlled
+# way by setting EXPAND_ONLY_PREDEF to YES.
+
+MACRO_EXPANSION = NO
+
+# If the EXPAND_ONLY_PREDEF and MACRO_EXPANSION tags are both set to YES
+# then the macro expansion is limited to the macros specified with the
+# PREDEFINED and EXPAND_AS_DEFINED tags.
+
+EXPAND_ONLY_PREDEF = NO
+
+# If the SEARCH_INCLUDES tag is set to YES (the default) the includes files
+# in the INCLUDE_PATH (see below) will be search if a #include is found.
+
+SEARCH_INCLUDES = YES
+
+# The INCLUDE_PATH tag can be used to specify one or more directories that
+# contain include files that are not input files but should be processed by
+# the preprocessor.
+
+INCLUDE_PATH =
+
+# You can use the INCLUDE_FILE_PATTERNS tag to specify one or more wildcard
+# patterns (like *.h and *.hpp) to filter out the header-files in the
+# directories. If left blank, the patterns specified with FILE_PATTERNS will
+# be used.
+
+INCLUDE_FILE_PATTERNS =
+
+# The PREDEFINED tag can be used to specify one or more macro names that
+# are defined before the preprocessor is started (similar to the -D option of
+# gcc). The argument of the tag is a list of macros of the form: name
+# or name=definition (no spaces). If the definition and the = are
+# omitted =1 is assumed. To prevent a macro definition from being
+# undefined via #undef or recursively expanded use the := operator
+# instead of the = operator.
+
+PREDEFINED =
+
+# If the MACRO_EXPANSION and EXPAND_ONLY_PREDEF tags are set to YES then
+# this tag can be used to specify a list of macro names that should be expanded.
+# The macro definition that is found in the sources will be used.
+# Use the PREDEFINED tag if you want to use a different macro definition.
+
+EXPAND_AS_DEFINED =
+
+# If the SKIP_FUNCTION_MACROS tag is set to YES (the default) then
+# doxygen's preprocessor will remove all function-like macros that are alone
+# on a line, have an all uppercase name, and do not end with a semicolon. Such
+# function macros are typically used for boiler-plate code, and will confuse
+# the parser if not removed.
+
+SKIP_FUNCTION_MACROS = YES
+
+#---------------------------------------------------------------------------
+# Configuration::additions related to external references
+#---------------------------------------------------------------------------
+
+# The TAGFILES option can be used to specify one or more tagfiles.
+# Optionally an initial location of the external documentation
+# can be added for each tagfile. The format of a tag file without
+# this location is as follows:
+# TAGFILES = file1 file2 ...
+# Adding location for the tag files is done as follows:
+# TAGFILES = file1=loc1 "file2 = loc2" ...
+# where "loc1" and "loc2" can be relative or absolute paths or
+# URLs. If a location is present for each tag, the installdox tool
+# does not have to be run to correct the links.
+# Note that each tag file must have a unique name
+# (where the name does NOT include the path)
+# If a tag file is not located in the directory in which doxygen
+# is run, you must also specify the path to the tagfile here.
+
+TAGFILES =
+
+# When a file name is specified after GENERATE_TAGFILE, doxygen will create
+# a tag file that is based on the input files it reads.
+
+GENERATE_TAGFILE =
+
+# If the ALLEXTERNALS tag is set to YES all external classes will be listed
+# in the class index. If set to NO only the inherited external classes
+# will be listed.
+
+ALLEXTERNALS = NO
+
+# If the EXTERNAL_GROUPS tag is set to YES all external groups will be listed
+# in the modules index. If set to NO, only the current project's groups will
+# be listed.
+
+EXTERNAL_GROUPS = YES
+
+# The PERL_PATH should be the absolute path and name of the perl script
+# interpreter (i.e. the result of `which perl').
+
+PERL_PATH = /usr/bin/perl
+
+#---------------------------------------------------------------------------
+# Configuration options related to the dot tool
+#---------------------------------------------------------------------------
+
+# If the CLASS_DIAGRAMS tag is set to YES (the default) Doxygen will
+# generate a inheritance diagram (in HTML, RTF and LaTeX) for classes with base
+# or super classes. Setting the tag to NO turns the diagrams off. Note that
+# this option is superseded by the HAVE_DOT option below. This is only a
+# fallback. It is recommended to install and use dot, since it yields more
+# powerful graphs.
+
+CLASS_DIAGRAMS = YES
+
+# You can define message sequence charts within doxygen comments using the \msc
+# command. Doxygen will then run the mscgen tool (see
+# http://www.mcternan.me.uk/mscgen/) to produce the chart and insert it in the
+# documentation. The MSCGEN_PATH tag allows you to specify the directory where
+# the mscgen tool resides. If left empty the tool is assumed to be found in the
+# default search path.
+
+MSCGEN_PATH =
+
+# If set to YES, the inheritance and collaboration graphs will hide
+# inheritance and usage relations if the target is undocumented
+# or is not a class.
+
+HIDE_UNDOC_RELATIONS = YES
+
+# If you set the HAVE_DOT tag to YES then doxygen will assume the dot tool is
+# available from the path. This tool is part of Graphviz, a graph visualization
+# toolkit from AT&T and Lucent Bell Labs. The other options in this section
+# have no effect if this option is set to NO (the default)
+
+HAVE_DOT = NO
+
+# By default doxygen will write a font called FreeSans.ttf to the output
+# directory and reference it in all dot files that doxygen generates. This
+# font does not include all possible unicode characters however, so when you need
+# these (or just want a differently looking font) you can specify the font name
+# using DOT_FONTNAME. You need need to make sure dot is able to find the font,
+# which can be done by putting it in a standard location or by setting the
+# DOTFONTPATH environment variable or by setting DOT_FONTPATH to the directory
+# containing the font.
+
+DOT_FONTNAME = FreeSans
+
+# The DOT_FONTSIZE tag can be used to set the size of the font of dot graphs.
+# The default size is 10pt.
+
+DOT_FONTSIZE = 10
+
+# By default doxygen will tell dot to use the output directory to look for the
+# FreeSans.ttf font (which doxygen will put there itself). If you specify a
+# different font using DOT_FONTNAME you can set the path where dot
+# can find it using this tag.
+
+DOT_FONTPATH =
+
+# If the CLASS_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect inheritance relations. Setting this tag to YES will force the
+# the CLASS_DIAGRAMS tag to NO.
+
+CLASS_GRAPH = YES
+
+# If the COLLABORATION_GRAPH and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for each documented class showing the direct and
+# indirect implementation dependencies (inheritance, containment, and
+# class references variables) of the class with other documented classes.
+
+COLLABORATION_GRAPH = YES
+
+# If the GROUP_GRAPHS and HAVE_DOT tags are set to YES then doxygen
+# will generate a graph for groups, showing the direct groups dependencies
+
+GROUP_GRAPHS = YES
+
+# If the UML_LOOK tag is set to YES doxygen will generate inheritance and
+# collaboration diagrams in a style similar to the OMG's Unified Modeling
+# Language.
+
+UML_LOOK = NO
+
+# If set to YES, the inheritance and collaboration graphs will show the
+# relations between templates and their instances.
+
+TEMPLATE_RELATIONS = NO
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDE_GRAPH, and HAVE_DOT
+# tags are set to YES then doxygen will generate a graph for each documented
+# file showing the direct and indirect include dependencies of the file with
+# other documented files.
+
+INCLUDE_GRAPH = YES
+
+# If the ENABLE_PREPROCESSING, SEARCH_INCLUDES, INCLUDED_BY_GRAPH, and
+# HAVE_DOT tags are set to YES then doxygen will generate a graph for each
+# documented header file showing the documented files that directly or
+# indirectly include this file.
+
+INCLUDED_BY_GRAPH = YES
+
+# If the CALL_GRAPH and HAVE_DOT options are set to YES then
+# doxygen will generate a call dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable call graphs
+# for selected functions only using the \callgraph command.
+
+CALL_GRAPH = NO
+
+# If the CALLER_GRAPH and HAVE_DOT tags are set to YES then
+# doxygen will generate a caller dependency graph for every global function
+# or class method. Note that enabling this option will significantly increase
+# the time of a run. So in most cases it will be better to enable caller
+# graphs for selected functions only using the \callergraph command.
+
+CALLER_GRAPH = NO
+
+# If the GRAPHICAL_HIERARCHY and HAVE_DOT tags are set to YES then doxygen
+# will graphical hierarchy of all classes instead of a textual one.
+
+GRAPHICAL_HIERARCHY = YES
+
+# If the DIRECTORY_GRAPH, SHOW_DIRECTORIES and HAVE_DOT tags are set to YES
+# then doxygen will show the dependencies a directory has on other directories
+# in a graphical way. The dependency relations are determined by the #include
+# relations between the files in the directories.
+
+DIRECTORY_GRAPH = YES
+
+# The DOT_IMAGE_FORMAT tag can be used to set the image format of the images
+# generated by dot. Possible values are png, jpg, or gif
+# If left blank png will be used.
+
+DOT_IMAGE_FORMAT = png
+
+# The tag DOT_PATH can be used to specify the path where the dot tool can be
+# found. If left blank, it is assumed the dot tool can be found in the path.
+
+DOT_PATH =
+
+# The DOTFILE_DIRS tag can be used to specify one or more directories that
+# contain dot files that are included in the documentation (see the
+# \dotfile command).
+
+DOTFILE_DIRS =
+
+# The DOT_GRAPH_MAX_NODES tag can be used to set the maximum number of
+# nodes that will be shown in the graph. If the number of nodes in a graph
+# becomes larger than this value, doxygen will truncate the graph, which is
+# visualized by representing a node as a red box. Note that doxygen if the
+# number of direct children of the root node in a graph is already larger than
+# DOT_GRAPH_MAX_NODES then the graph will not be shown at all. Also note
+# that the size of a graph can be further restricted by MAX_DOT_GRAPH_DEPTH.
+
+DOT_GRAPH_MAX_NODES = 50
+
+# The MAX_DOT_GRAPH_DEPTH tag can be used to set the maximum depth of the
+# graphs generated by dot. A depth value of 3 means that only nodes reachable
+# from the root by following a path via at most 3 edges will be shown. Nodes
+# that lay further from the root node will be omitted. Note that setting this
+# option to 1 or 2 may greatly reduce the computation time needed for large
+# code bases. Also note that the size of a graph can be further restricted by
+# DOT_GRAPH_MAX_NODES. Using a depth of 0 means no depth restriction.
+
+MAX_DOT_GRAPH_DEPTH = 0
+
+# Set the DOT_TRANSPARENT tag to YES to generate images with a transparent
+# background. This is disabled by default, because dot on Windows does not
+# seem to support this out of the box. Warning: Depending on the platform used,
+# enabling this option may lead to badly anti-aliased labels on the edges of
+# a graph (i.e. they become hard to read).
+
+DOT_TRANSPARENT = NO
+
+# Set the DOT_MULTI_TARGETS tag to YES allow dot to generate multiple output
+# files in one run (i.e. multiple -o and -T options on the command line). This
+# makes dot run faster, but since only newer versions of dot (>1.8.10)
+# support this, this feature is disabled by default.
+
+DOT_MULTI_TARGETS = NO
+
+# If the GENERATE_LEGEND tag is set to YES (the default) Doxygen will
+# generate a legend page explaining the meaning of the various boxes and
+# arrows in the dot generated graphs.
+
+GENERATE_LEGEND = YES
+
+# If the DOT_CLEANUP tag is set to YES (the default) Doxygen will
+# remove the intermediate dot files that are used to generate
+# the various graphs.
+
+DOT_CLEANUP = YES
diff --git a/jni/feature_stab/src/dbreg/dbreg.cpp b/jni/feature_stab/src/dbreg/dbreg.cpp
new file mode 100644
index 000000000..da06aa2ab
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/dbreg.cpp
@@ -0,0 +1,794 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// $Id: dbreg.cpp,v 1.31 2011/06/17 14:04:32 mbansal Exp $
+#include "dbreg.h"
+#include <string.h>
+#include <stdio.h>
+
+
+#if PROFILE
+#endif
+
+//#include <iostream>
+
+db_FrameToReferenceRegistration::db_FrameToReferenceRegistration() :
+ m_initialized(false),m_nr_matches(0),m_over_allocation(256),m_nr_bins(20),m_max_cost_pix(30), m_quarter_resolution(false)
+{
+ m_reference_image = NULL;
+ m_aligned_ins_image = NULL;
+
+ m_quarter_res_image = NULL;
+ m_horz_smooth_subsample_image = NULL;
+
+ m_x_corners_ref = NULL;
+ m_y_corners_ref = NULL;
+
+ m_x_corners_ins = NULL;
+ m_y_corners_ins = NULL;
+
+ m_match_index_ref = NULL;
+ m_match_index_ins = NULL;
+
+ m_inlier_indices = NULL;
+
+ m_num_inlier_indices = 0;
+
+ m_temp_double = NULL;
+ m_temp_int = NULL;
+
+ m_corners_ref = NULL;
+ m_corners_ins = NULL;
+
+ m_sq_cost = NULL;
+ m_cost_histogram = NULL;
+
+ profile_string = NULL;
+
+ db_Identity3x3(m_K);
+ db_Identity3x3(m_H_ref_to_ins);
+ db_Identity3x3(m_H_dref_to_ref);
+
+ m_sq_cost_computed = false;
+ m_reference_set = false;
+
+ m_reference_update_period = 0;
+ m_nr_frames_processed = 0;
+
+ return;
+}
+
+db_FrameToReferenceRegistration::~db_FrameToReferenceRegistration()
+{
+ Clean();
+}
+
+void db_FrameToReferenceRegistration::Clean()
+{
+ if ( m_reference_image )
+ db_FreeImage_u(m_reference_image,m_im_height);
+
+ if ( m_aligned_ins_image )
+ db_FreeImage_u(m_aligned_ins_image,m_im_height);
+
+ if ( m_quarter_res_image )
+ {
+ db_FreeImage_u(m_quarter_res_image, m_im_height);
+ }
+
+ if ( m_horz_smooth_subsample_image )
+ {
+ db_FreeImage_u(m_horz_smooth_subsample_image, m_im_height*2);
+ }
+
+ delete [] m_x_corners_ref;
+ delete [] m_y_corners_ref;
+
+ delete [] m_x_corners_ins;
+ delete [] m_y_corners_ins;
+
+ delete [] m_match_index_ref;
+ delete [] m_match_index_ins;
+
+ delete [] m_temp_double;
+ delete [] m_temp_int;
+
+ delete [] m_corners_ref;
+ delete [] m_corners_ins;
+
+ delete [] m_sq_cost;
+ delete [] m_cost_histogram;
+
+ delete [] m_inlier_indices;
+
+ if(profile_string)
+ delete [] profile_string;
+
+ m_reference_image = NULL;
+ m_aligned_ins_image = NULL;
+
+ m_quarter_res_image = NULL;
+ m_horz_smooth_subsample_image = NULL;
+
+ m_x_corners_ref = NULL;
+ m_y_corners_ref = NULL;
+
+ m_x_corners_ins = NULL;
+ m_y_corners_ins = NULL;
+
+ m_match_index_ref = NULL;
+ m_match_index_ins = NULL;
+
+ m_inlier_indices = NULL;
+
+ m_temp_double = NULL;
+ m_temp_int = NULL;
+
+ m_corners_ref = NULL;
+ m_corners_ins = NULL;
+
+ m_sq_cost = NULL;
+ m_cost_histogram = NULL;
+}
+
+void db_FrameToReferenceRegistration::Init(int width, int height,
+ int homography_type,
+ int max_iterations,
+ bool linear_polish,
+ bool quarter_resolution,
+ double scale,
+ unsigned int reference_update_period,
+ bool do_motion_smoothing,
+ double motion_smoothing_gain,
+ int nr_samples,
+ int chunk_size,
+ int cd_target_nr_corners,
+ double cm_max_disparity,
+ bool cm_use_smaller_matching_window,
+ int cd_nr_horz_blocks,
+ int cd_nr_vert_blocks
+ )
+{
+ Clean();
+
+ m_reference_update_period = reference_update_period;
+ m_nr_frames_processed = 0;
+
+ m_do_motion_smoothing = do_motion_smoothing;
+ m_motion_smoothing_gain = motion_smoothing_gain;
+
+ m_stab_smoother.setSmoothingFactor(m_motion_smoothing_gain);
+
+ m_quarter_resolution = quarter_resolution;
+
+ profile_string = new char[10240];
+
+ if (m_quarter_resolution == true)
+ {
+ width = width/2;
+ height = height/2;
+
+ m_horz_smooth_subsample_image = db_AllocImage_u(width,height*2,m_over_allocation);
+ m_quarter_res_image = db_AllocImage_u(width,height,m_over_allocation);
+ }
+
+ m_im_width = width;
+ m_im_height = height;
+
+ double temp[9];
+ db_Approx3DCalMat(m_K,temp,m_im_width,m_im_height);
+
+ m_homography_type = homography_type;
+ m_max_iterations = max_iterations;
+ m_scale = 2/(m_K[0]+m_K[4]);
+ m_nr_samples = nr_samples;
+ m_chunk_size = chunk_size;
+
+ double outlier_t1 = 5.0;
+
+ m_outlier_t2 = outlier_t1*outlier_t1;//*m_scale*m_scale;
+
+ m_current_is_reference = false;
+
+ m_linear_polish = linear_polish;
+
+ m_reference_image = db_AllocImage_u(m_im_width,m_im_height,m_over_allocation);
+ m_aligned_ins_image = db_AllocImage_u(m_im_width,m_im_height,m_over_allocation);
+
+ // initialize feature detection and matching:
+ //m_max_nr_corners = m_cd.Init(m_im_width,m_im_height,cd_target_nr_corners,cd_nr_horz_blocks,cd_nr_vert_blocks,0.0,0.0);
+ m_max_nr_corners = m_cd.Init(m_im_width,m_im_height,cd_target_nr_corners,cd_nr_horz_blocks,cd_nr_vert_blocks,DB_DEFAULT_ABS_CORNER_THRESHOLD/500.0,0.0);
+
+ int use_21 = 0;
+ m_max_nr_matches = m_cm.Init(m_im_width,m_im_height,cm_max_disparity,m_max_nr_corners,DB_DEFAULT_NO_DISPARITY,cm_use_smaller_matching_window,use_21);
+
+ // allocate space for corner feature locations for reference and inspection images:
+ m_x_corners_ref = new double [m_max_nr_corners];
+ m_y_corners_ref = new double [m_max_nr_corners];
+
+ m_x_corners_ins = new double [m_max_nr_corners];
+ m_y_corners_ins = new double [m_max_nr_corners];
+
+ // allocate space for match indices:
+ m_match_index_ref = new int [m_max_nr_matches];
+ m_match_index_ins = new int [m_max_nr_matches];
+
+ m_temp_double = new double [12*DB_DEFAULT_NR_SAMPLES+10*m_max_nr_matches];
+ m_temp_int = new int [db_maxi(DB_DEFAULT_NR_SAMPLES,m_max_nr_matches)];
+
+ // allocate space for homogenous image points:
+ m_corners_ref = new double [3*m_max_nr_corners];
+ m_corners_ins = new double [3*m_max_nr_corners];
+
+ // allocate cost array and histogram:
+ m_sq_cost = new double [m_max_nr_matches];
+ m_cost_histogram = new int [m_nr_bins];
+
+ // reserve array:
+ //m_inlier_indices.reserve(m_max_nr_matches);
+ m_inlier_indices = new int[m_max_nr_matches];
+
+ m_initialized = true;
+
+ m_max_inlier_count = 0;
+}
+
+
+#define MB 0
+// Save the reference image, detect features and update the dref-to-ref transformation
+int db_FrameToReferenceRegistration::UpdateReference(const unsigned char * const * im, bool subsample, bool detect_corners)
+{
+ double temp[9];
+ db_Multiply3x3_3x3(temp,m_H_dref_to_ref,m_H_ref_to_ins);
+ db_Copy9(m_H_dref_to_ref,temp);
+
+ const unsigned char * const * imptr = im;
+
+ if (m_quarter_resolution && subsample)
+ {
+ GenerateQuarterResImage(im);
+ imptr = m_quarter_res_image;
+ }
+
+ // save the reference image, detect features and quit
+ db_CopyImage_u(m_reference_image,imptr,m_im_width,m_im_height,m_over_allocation);
+
+ if(detect_corners)
+ {
+ #if MB
+ m_cd.DetectCorners(imptr, m_x_corners_ref,m_y_corners_ref,&m_nr_corners_ref);
+ int nr = 0;
+ for(int k=0; k<m_nr_corners_ref; k++)
+ {
+ if(m_x_corners_ref[k]>m_im_width/3)
+ {
+ m_x_corners_ref[nr] = m_x_corners_ref[k];
+ m_y_corners_ref[nr] = m_y_corners_ref[k];
+ nr++;
+ }
+
+ }
+ m_nr_corners_ref = nr;
+ #else
+ m_cd.DetectCorners(imptr, m_x_corners_ref,m_y_corners_ref,&m_nr_corners_ref);
+ #endif
+ }
+ else
+ {
+ m_nr_corners_ref = m_nr_corners_ins;
+
+ for(int k=0; k<m_nr_corners_ins; k++)
+ {
+ m_x_corners_ref[k] = m_x_corners_ins[k];
+ m_y_corners_ref[k] = m_y_corners_ins[k];
+ }
+
+ }
+
+ db_Identity3x3(m_H_ref_to_ins);
+
+ m_max_inlier_count = 0; // Reset to 0 as no inliers seen until now
+ m_sq_cost_computed = false;
+ m_reference_set = true;
+ m_current_is_reference = true;
+ return 1;
+}
+
+void db_FrameToReferenceRegistration::Get_H_dref_to_ref(double H[9])
+{
+ db_Copy9(H,m_H_dref_to_ref);
+}
+
+void db_FrameToReferenceRegistration::Get_H_dref_to_ins(double H[9])
+{
+ db_Multiply3x3_3x3(H,m_H_dref_to_ref,m_H_ref_to_ins);
+}
+
+void db_FrameToReferenceRegistration::Set_H_dref_to_ins(double H[9])
+{
+ double H_ins_to_ref[9];
+
+ db_Identity3x3(H_ins_to_ref); // Ensure it has proper values
+ db_InvertAffineTransform(H_ins_to_ref,m_H_ref_to_ins); // Invert to get ins to ref
+ db_Multiply3x3_3x3(m_H_dref_to_ref,H,H_ins_to_ref); // Update dref to ref using the input H from dref to ins
+}
+
+
+void db_FrameToReferenceRegistration::ResetDisplayReference()
+{
+ db_Identity3x3(m_H_dref_to_ref);
+}
+
+bool db_FrameToReferenceRegistration::NeedReferenceUpdate()
+{
+ // If less than 50% of the starting number of inliers left, then its time to update the reference.
+ if(m_max_inlier_count>0 && float(m_num_inlier_indices)/float(m_max_inlier_count)<0.5)
+ return true;
+ else
+ return false;
+}
+
+int db_FrameToReferenceRegistration::AddFrame(const unsigned char * const * im, double H[9],bool force_reference,bool prewarp)
+{
+ m_current_is_reference = false;
+ if(!m_reference_set || force_reference)
+ {
+ db_Identity3x3(m_H_ref_to_ins);
+ db_Copy9(H,m_H_ref_to_ins);
+
+ UpdateReference(im,true,true);
+ return 0;
+ }
+
+ const unsigned char * const * imptr = im;
+
+ if (m_quarter_resolution)
+ {
+ if (m_quarter_res_image)
+ {
+ GenerateQuarterResImage(im);
+ }
+
+ imptr = (const unsigned char * const* )m_quarter_res_image;
+ }
+
+ double H_last[9];
+ db_Copy9(H_last,m_H_ref_to_ins);
+ db_Identity3x3(m_H_ref_to_ins);
+
+ m_sq_cost_computed = false;
+
+ // detect corners on inspection image and match to reference image features:s
+
+ // @jke - Adding code to time the functions. TODO: Remove after test
+#if PROFILE
+ double iTimer1, iTimer2;
+ char str[255];
+ strcpy(profile_string,"\n");
+ sprintf(str,"[%dx%d] %p\n",m_im_width,m_im_height,im);
+ strcat(profile_string, str);
+#endif
+
+ // @jke - Adding code to time the functions. TODO: Remove after test
+#if PROFILE
+ iTimer1 = now_ms();
+#endif
+ m_cd.DetectCorners(imptr, m_x_corners_ins,m_y_corners_ins,&m_nr_corners_ins);
+ // @jke - Adding code to time the functions. TODO: Remove after test
+# if PROFILE
+ iTimer2 = now_ms();
+ double elapsedTimeCorner = iTimer2 - iTimer1;
+ sprintf(str,"Corner Detection [%d corners] = %g ms\n",m_nr_corners_ins, elapsedTimeCorner);
+ strcat(profile_string, str);
+#endif
+
+ // @jke - Adding code to time the functions. TODO: Remove after test
+#if PROFILE
+ iTimer1 = now_ms();
+#endif
+ if(prewarp)
+ m_cm.Match(m_reference_image,imptr,m_x_corners_ref,m_y_corners_ref,m_nr_corners_ref,
+ m_x_corners_ins,m_y_corners_ins,m_nr_corners_ins,
+ m_match_index_ref,m_match_index_ins,&m_nr_matches,H,0);
+ else
+ m_cm.Match(m_reference_image,imptr,m_x_corners_ref,m_y_corners_ref,m_nr_corners_ref,
+ m_x_corners_ins,m_y_corners_ins,m_nr_corners_ins,
+ m_match_index_ref,m_match_index_ins,&m_nr_matches);
+ // @jke - Adding code to time the functions. TODO: Remove after test
+# if PROFILE
+ iTimer2 = now_ms();
+ double elapsedTimeMatch = iTimer2 - iTimer1;
+ sprintf(str,"Matching [%d] = %g ms\n",m_nr_matches,elapsedTimeMatch);
+ strcat(profile_string, str);
+#endif
+
+
+ // copy out matching features:
+ for ( int i = 0; i < m_nr_matches; ++i )
+ {
+ int offset = 3*i;
+ m_corners_ref[offset ] = m_x_corners_ref[m_match_index_ref[i]];
+ m_corners_ref[offset+1] = m_y_corners_ref[m_match_index_ref[i]];
+ m_corners_ref[offset+2] = 1.0;
+
+ m_corners_ins[offset ] = m_x_corners_ins[m_match_index_ins[i]];
+ m_corners_ins[offset+1] = m_y_corners_ins[m_match_index_ins[i]];
+ m_corners_ins[offset+2] = 1.0;
+ }
+
+ // @jke - Adding code to time the functions. TODO: Remove after test
+#if PROFILE
+ iTimer1 = now_ms();
+#endif
+ // perform the alignment:
+ db_RobImageHomography(m_H_ref_to_ins, m_corners_ref, m_corners_ins, m_nr_matches, m_K, m_K, m_temp_double, m_temp_int,
+ m_homography_type,NULL,m_max_iterations,m_max_nr_matches,m_scale,
+ m_nr_samples, m_chunk_size);
+ // @jke - Adding code to time the functions. TODO: Remove after test
+# if PROFILE
+ iTimer2 = now_ms();
+ double elapsedTimeHomography = iTimer2 - iTimer1;
+ sprintf(str,"Homography = %g ms\n",elapsedTimeHomography);
+ strcat(profile_string, str);
+#endif
+
+
+ SetOutlierThreshold();
+
+ // Compute the inliers for the db compute m_H_ref_to_ins
+ ComputeInliers(m_H_ref_to_ins);
+
+ // Update the max inlier count
+ m_max_inlier_count = (m_max_inlier_count > m_num_inlier_indices)?m_max_inlier_count:m_num_inlier_indices;
+
+ // Fit a least-squares model to just the inliers and put it in m_H_ref_to_ins
+ if(m_linear_polish)
+ Polish(m_inlier_indices, m_num_inlier_indices);
+
+ if (m_quarter_resolution)
+ {
+ m_H_ref_to_ins[2] *= 2.0;
+ m_H_ref_to_ins[5] *= 2.0;
+ }
+
+#if PROFILE
+ sprintf(str,"#Inliers = %d \n",m_num_inlier_indices);
+ strcat(profile_string, str);
+#endif
+/*
+ ///// CHECK IF CURRENT TRANSFORMATION GOOD OR BAD ////
+ ///// IF BAD, then update reference to the last correctly aligned inspection frame;
+ if(m_num_inlier_indices<5)//0.9*m_nr_matches || m_nr_matches < 20)
+ {
+ db_Copy9(m_H_ref_to_ins,H_last);
+ UpdateReference(imptr,false);
+// UpdateReference(m_aligned_ins_image,false);
+ }
+ else
+ {
+ ///// IF GOOD, then update the last correctly aligned inspection frame to be this;
+ //db_CopyImage_u(m_aligned_ins_image,imptr,m_im_width,m_im_height,m_over_allocation);
+*/
+ if(m_do_motion_smoothing)
+ SmoothMotion();
+
+ // Disable debug printing
+ // db_PrintDoubleMatrix(m_H_ref_to_ins,3,3);
+
+ db_Copy9(H, m_H_ref_to_ins);
+
+ m_nr_frames_processed++;
+{
+ if ( (m_nr_frames_processed % m_reference_update_period) == 0 )
+ {
+ //UpdateReference(imptr,false, false);
+
+ #if MB
+ UpdateReference(imptr,false, true);
+ #else
+ UpdateReference(imptr,false, false);
+ #endif
+ }
+
+
+ }
+
+
+
+ return 1;
+}
+
+//void db_FrameToReferenceRegistration::ComputeInliers(double H[9],std::vector<int> &inlier_indices)
+void db_FrameToReferenceRegistration::ComputeInliers(double H[9])
+{
+ double totnummatches = m_nr_matches;
+ int inliercount=0;
+
+ m_num_inlier_indices = 0;
+// inlier_indices.clear();
+
+ for(int c=0; c < totnummatches; c++ )
+ {
+ if (m_sq_cost[c] <= m_outlier_t2)
+ {
+ m_inlier_indices[inliercount] = c;
+ inliercount++;
+ }
+ }
+
+ m_num_inlier_indices = inliercount;
+ double frac=inliercount/totnummatches;
+}
+
+//void db_FrameToReferenceRegistration::Polish(std::vector<int> &inlier_indices)
+void db_FrameToReferenceRegistration::Polish(int *inlier_indices, int &num_inlier_indices)
+{
+ db_Zero(m_polish_C,36);
+ db_Zero(m_polish_D,6);
+ for (int i=0;i<num_inlier_indices;i++)
+ {
+ int j = 3*inlier_indices[i];
+ m_polish_C[0]+=m_corners_ref[j]*m_corners_ref[j];
+ m_polish_C[1]+=m_corners_ref[j]*m_corners_ref[j+1];
+ m_polish_C[2]+=m_corners_ref[j];
+ m_polish_C[7]+=m_corners_ref[j+1]*m_corners_ref[j+1];
+ m_polish_C[8]+=m_corners_ref[j+1];
+ m_polish_C[14]+=1;
+ m_polish_D[0]+=m_corners_ref[j]*m_corners_ins[j];
+ m_polish_D[1]+=m_corners_ref[j+1]*m_corners_ins[j];
+ m_polish_D[2]+=m_corners_ins[j];
+ m_polish_D[3]+=m_corners_ref[j]*m_corners_ins[j+1];
+ m_polish_D[4]+=m_corners_ref[j+1]*m_corners_ins[j+1];
+ m_polish_D[5]+=m_corners_ins[j+1];
+ }
+
+ double a=db_maxd(m_polish_C[0],m_polish_C[7]);
+ m_polish_C[0]/=a; m_polish_C[1]/=a; m_polish_C[2]/=a;
+ m_polish_C[7]/=a; m_polish_C[8]/=a; m_polish_C[14]/=a;
+
+ m_polish_D[0]/=a; m_polish_D[1]/=a; m_polish_D[2]/=a;
+ m_polish_D[3]/=a; m_polish_D[4]/=a; m_polish_D[5]/=a;
+
+
+ m_polish_C[6]=m_polish_C[1];
+ m_polish_C[12]=m_polish_C[2];
+ m_polish_C[13]=m_polish_C[8];
+
+ m_polish_C[21]=m_polish_C[0]; m_polish_C[22]=m_polish_C[1]; m_polish_C[23]=m_polish_C[2];
+ m_polish_C[28]=m_polish_C[7]; m_polish_C[29]=m_polish_C[8];
+ m_polish_C[35]=m_polish_C[14];
+
+
+ double d[6];
+ db_CholeskyDecomp6x6(m_polish_C,d);
+ db_CholeskyBacksub6x6(m_H_ref_to_ins,m_polish_C,d,m_polish_D);
+}
+
+void db_FrameToReferenceRegistration::EstimateSecondaryModel(double H[9])
+{
+ /* if ( m_current_is_reference )
+ {
+ db_Identity3x3(H);
+ return;
+ }
+ */
+
+ // select the outliers of the current model:
+ SelectOutliers();
+
+ // perform the alignment:
+ db_RobImageHomography(m_H_ref_to_ins, m_corners_ref, m_corners_ins, m_nr_matches, m_K, m_K, m_temp_double, m_temp_int,
+ m_homography_type,NULL,m_max_iterations,m_max_nr_matches,m_scale,
+ m_nr_samples, m_chunk_size);
+
+ db_Copy9(H,m_H_ref_to_ins);
+}
+
+void db_FrameToReferenceRegistration::ComputeCostArray()
+{
+ if ( m_sq_cost_computed ) return;
+
+ for( int c=0, k=0 ;c < m_nr_matches; c++, k=k+3)
+ {
+ m_sq_cost[c] = SquaredInhomogenousHomographyError(m_corners_ins+k,m_H_ref_to_ins,m_corners_ref+k);
+ }
+
+ m_sq_cost_computed = true;
+}
+
+void db_FrameToReferenceRegistration::SelectOutliers()
+{
+ int nr_outliers=0;
+
+ ComputeCostArray();
+
+ for(int c=0, k=0 ;c<m_nr_matches;c++,k=k+3)
+ {
+ if (m_sq_cost[c] > m_outlier_t2)
+ {
+ int offset = 3*nr_outliers++;
+ db_Copy3(m_corners_ref+offset,m_corners_ref+k);
+ db_Copy3(m_corners_ins+offset,m_corners_ins+k);
+ }
+ }
+
+ m_nr_matches = nr_outliers;
+}
+
+void db_FrameToReferenceRegistration::ComputeCostHistogram()
+{
+ ComputeCostArray();
+
+ for ( int b = 0; b < m_nr_bins; ++b )
+ m_cost_histogram[b] = 0;
+
+ for(int c = 0; c < m_nr_matches; c++)
+ {
+ double error = db_SafeSqrt(m_sq_cost[c]);
+ int bin = (int)(error/m_max_cost_pix*m_nr_bins);
+ if ( bin < m_nr_bins )
+ m_cost_histogram[bin]++;
+ else
+ m_cost_histogram[m_nr_bins-1]++;
+ }
+
+/*
+ for ( int i = 0; i < m_nr_bins; ++i )
+ std::cout << m_cost_histogram[i] << " ";
+ std::cout << std::endl;
+*/
+}
+
+void db_FrameToReferenceRegistration::SetOutlierThreshold()
+{
+ ComputeCostHistogram();
+
+ int i = 0, last=0;
+ for (; i < m_nr_bins-1; ++i )
+ {
+ if ( last > m_cost_histogram[i] )
+ break;
+ last = m_cost_histogram[i];
+ }
+
+ //std::cout << "I " << i << std::endl;
+
+ int max = m_cost_histogram[i];
+
+ for (; i < m_nr_bins-1; ++i )
+ {
+ if ( m_cost_histogram[i] < (int)(0.1*max) )
+ //if ( last < m_cost_histogram[i] )
+ break;
+ last = m_cost_histogram[i];
+ }
+ //std::cout << "J " << i << std::endl;
+
+ m_outlier_t2 = db_sqr(i*m_max_cost_pix/m_nr_bins);
+
+ //std::cout << "m_outlier_t2 " << m_outlier_t2 << std::endl;
+}
+
+void db_FrameToReferenceRegistration::SmoothMotion(void)
+{
+ VP_MOTION inmot,outmot;
+
+ double H[9];
+
+ Get_H_dref_to_ins(H);
+
+ MXX(inmot) = H[0];
+ MXY(inmot) = H[1];
+ MXZ(inmot) = H[2];
+ MXW(inmot) = 0.0;
+
+ MYX(inmot) = H[3];
+ MYY(inmot) = H[4];
+ MYZ(inmot) = H[5];
+ MYW(inmot) = 0.0;
+
+ MZX(inmot) = H[6];
+ MZY(inmot) = H[7];
+ MZZ(inmot) = H[8];
+ MZW(inmot) = 0.0;
+
+ MWX(inmot) = 0.0;
+ MWY(inmot) = 0.0;
+ MWZ(inmot) = 0.0;
+ MWW(inmot) = 1.0;
+
+ inmot.type = VP_MOTION_AFFINE;
+
+ int w = m_im_width;
+ int h = m_im_height;
+
+ if(m_quarter_resolution)
+ {
+ w = w*2;
+ h = h*2;
+ }
+
+#if 0
+ m_stab_smoother.smoothMotionAdaptive(w,h,&inmot,&outmot);
+#else
+ m_stab_smoother.smoothMotion(&inmot,&outmot);
+#endif
+
+ H[0] = MXX(outmot);
+ H[1] = MXY(outmot);
+ H[2] = MXZ(outmot);
+
+ H[3] = MYX(outmot);
+ H[4] = MYY(outmot);
+ H[5] = MYZ(outmot);
+
+ H[6] = MZX(outmot);
+ H[7] = MZY(outmot);
+ H[8] = MZZ(outmot);
+
+ Set_H_dref_to_ins(H);
+}
+
+void db_FrameToReferenceRegistration::GenerateQuarterResImage(const unsigned char* const* im)
+{
+ int input_h = m_im_height*2;
+ int input_w = m_im_width*2;
+
+ for (int j = 0; j < input_h; j++)
+ {
+ const unsigned char* in_row_ptr = im[j];
+ unsigned char* out_row_ptr = m_horz_smooth_subsample_image[j]+1;
+
+ for (int i = 2; i < input_w-2; i += 2)
+ {
+ int smooth_val = (
+ 6*in_row_ptr[i] +
+ ((in_row_ptr[i-1]+in_row_ptr[i+1])<<2) +
+ in_row_ptr[i-2]+in_row_ptr[i+2]
+ ) >> 4;
+ *out_row_ptr++ = (unsigned char) smooth_val;
+
+ if ( (smooth_val < 0) || (smooth_val > 255))
+ {
+ return;
+ }
+
+ }
+ }
+
+ for (int j = 2; j < input_h-2; j+=2)
+ {
+
+ unsigned char* in_row_ptr = m_horz_smooth_subsample_image[j];
+ unsigned char* out_row_ptr = m_quarter_res_image[j/2];
+
+ for (int i = 1; i < m_im_width-1; i++)
+ {
+ int smooth_val = (
+ 6*in_row_ptr[i] +
+ ((in_row_ptr[i-m_im_width]+in_row_ptr[i+m_im_width]) << 2)+
+ in_row_ptr[i-2*m_im_width]+in_row_ptr[i+2*m_im_width]
+ ) >> 4;
+ *out_row_ptr++ = (unsigned char)smooth_val;
+
+ if ( (smooth_val < 0) || (smooth_val > 255))
+ {
+ return;
+ }
+
+ }
+ }
+}
diff --git a/jni/feature_stab/src/dbreg/dbreg.h b/jni/feature_stab/src/dbreg/dbreg.h
new file mode 100644
index 000000000..4eb244481
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/dbreg.h
@@ -0,0 +1,581 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+
+#pragma once
+
+#ifdef _WIN32
+#ifdef DBREG_EXPORTS
+#define DBREG_API __declspec(dllexport)
+#else
+#define DBREG_API __declspec(dllimport)
+#endif
+#else
+#define DBREG_API
+#endif
+
+// @jke - the next few lines are for extracting timing data. TODO: Remove after test
+#define PROFILE 0
+
+#include "dbstabsmooth.h"
+
+#include <db_feature_detection.h>
+#include <db_feature_matching.h>
+#include <db_rob_image_homography.h>
+
+#if PROFILE
+ #include <sys/time.h>
+#endif
+
+/*! \mainpage db_FrameToReferenceRegistration
+
+ \section intro Introduction
+
+ db_FrameToReferenceRegistration provides a simple interface to a set of sophisticated algorithms for stabilizing
+ video sequences. As its name suggests, the class is used to compute parameters that will allow us to warp incoming video
+ frames and register them with respect to a so-called <i>reference</i> frame. The reference frame is simply the first
+ frame of a sequence; the registration process is that of estimating the parameters of a warp that can be applied to
+ subsequent frames to make those frames align with the reference. A video made up of these warped frames will be more
+ stable than the input video.
+
+ For more technical information on the internal structure of the algorithms used within the db_FrameToRegistration class,
+ please follow this <a href="../Sarnoff image registration.docx">link</a>.
+
+ \section usage Usage
+ In addition to the class constructor, there are two main functions of db_FrameToReferenceRegistration that are of
+ interest to the programmer. db_FrameToReferenceRegistration::Init(...) is used to initialize the parameters of the
+ registration algorithm. db_FrameToReferenceRegistration::AddFrame(...) is the method by which each new video frame
+ is introduced to the registration algorithm, and produces the estimated registration warp parameters.
+
+ The following example illustrates how the major methods of the class db_FrameToReferenceRegistration can be used together
+ to calculate the registration parameters for an image sequence. In the example, the calls to the methods of
+ db_FrameToReferenceRegistration match those found in the API, but supporting code should be considered pseudo-code.
+ For a more complete example, please consult the source code for dbregtest.
+
+
+ \code
+ // feature-based image registration class:
+ db_FrameToReferenceRegistration reg;
+
+ // Image data
+ const unsigned char * const * image_storage;
+
+ // The 3x3 frame to reference registration parameters
+ double frame_to_ref_homography[9];
+
+ // a counter to count the number of frames processed.
+ unsigned long frame_counter;
+ // ...
+
+ // main loop - keep going while there are images to process.
+ while (ImagesAreAvailable)
+ {
+ // Call functions to place latest data into image_storage
+ // ...
+
+ // if the registration object is not yet initialized, then do so
+ // The arguments to this function are explained in the accompanying
+ // html API documentation
+ if (!reg.Initialized())
+ {
+ reg.Init(w,h,motion_model_type,25,linear_polish,quarter_resolution,
+ DB_POINT_STANDARDDEV,reference_update_period,
+ do_motion_smoothing,motion_smoothing_gain,
+ DB_DEFAULT_NR_SAMPLES,DB_DEFAULT_CHUNK_SIZE,
+ nr_corners,max_disparity);
+ }
+
+ // Present the new image data to the registration algorithm,
+ // with the result being stored in the frame_to_ref_homography
+ // variable.
+ reg.AddFrame(image_storage,frame_to_ref_homography);
+
+ // frame_to_ref_homography now contains the stabilizing transform
+ // use this to warp the latest image for display, etc.
+
+ // if this is the first frame, we need to tell the registration
+ // class to store the image as its reference. Otherwise, AddFrame
+ // takes care of that.
+ if (frame_counter == 0)
+ {
+ reg.UpdateReference(image_storage);
+ }
+
+ // increment the frame counter
+ frame_counter++;
+ }
+
+ \endcode
+
+ */
+
+/*!
+ * Performs feature-based frame to reference image registration.
+ */
+class DBREG_API db_FrameToReferenceRegistration
+{
+public:
+ db_FrameToReferenceRegistration(void);
+ ~db_FrameToReferenceRegistration();
+
+ /*!
+ * Set parameters and allocate memory. Note: The default values of these parameters have been set to the values used for the android implementation (i.e. the demo APK).
+ * \param width image width
+ * \param height image height
+ * \param homography_type see definitions in \ref LMRobImageHomography
+ * \param max_iterations max number of polishing steps
+ * \param linear_polish whether to perform a linear polishing step after RANSAC
+ * \param quarter_resolution whether to process input images at quarter resolution (for computational efficiency)
+ * \param scale Cauchy scale coefficient (see db_ExpCauchyReprojectionError() )
+ * \param reference_update_period how often to update the alignment reference (in units of number of frames)
+ * \param do_motion_smoothing whether to perform display reference smoothing
+ * \param motion_smoothing_gain weight factor to reflect how fast the display reference must follow the current frame if motion smoothing is enabled
+ * \param nr_samples number of times to compute a hypothesis
+ * \param chunk_size size of cost chunks
+ * \param cd_target_nr_corners target number of corners for corner detector
+ * \param cm_max_disparity maximum disparity search range for corner matcher (in units of ratio of image width)
+ * \param cm_use_smaller_matching_window if set to true, uses a correlation window of 5x5 instead of the default 11x11
+ * \param cd_nr_horz_blocks the number of horizontal blocks for the corner detector to partition the image
+ * \param cd_nr_vert_blocks the number of vertical blocks for the corner detector to partition the image
+ */
+ void Init(int width, int height,
+ int homography_type = DB_HOMOGRAPHY_TYPE_DEFAULT,
+ int max_iterations = DB_DEFAULT_MAX_ITERATIONS,
+ bool linear_polish = false,
+ bool quarter_resolution = true,
+ double scale = DB_POINT_STANDARDDEV,
+ unsigned int reference_update_period = 3,
+ bool do_motion_smoothing = false,
+ double motion_smoothing_gain = 0.75,
+ int nr_samples = DB_DEFAULT_NR_SAMPLES,
+ int chunk_size = DB_DEFAULT_CHUNK_SIZE,
+ int cd_target_nr_corners = 500,
+ double cm_max_disparity = 0.2,
+ bool cm_use_smaller_matching_window = false,
+ int cd_nr_horz_blocks = 5,
+ int cd_nr_vert_blocks = 5);
+
+ /*!
+ * Reset the transformation type that is being use to perform alignment. Use this to change the alignment type at run time.
+ * \param homography_type the type of transformation to use for performing alignment (see definitions in \ref LMRobImageHomography)
+ */
+ void ResetHomographyType(int homography_type) { m_homography_type = homography_type; }
+
+ /*!
+ * Enable/Disable motion smoothing. Use this to turn motion smoothing on/off at run time.
+ * \param enable flag indicating whether to turn the motion smoothing on or off.
+ */
+ void ResetSmoothing(bool enable) { m_do_motion_smoothing = enable; }
+
+ /*!
+ * Align an inspection image to an existing reference image, update the reference image if due and perform motion smoothing if enabled.
+ * \param im new inspection image
+ * \param H computed transformation from reference to inspection coordinate frame. Identity is returned if no reference frame was set.
+ * \param force_reference make this the new reference image
+ */
+ int AddFrame(const unsigned char * const * im, double H[9], bool force_reference=false, bool prewarp=false);
+
+ /*!
+ * Returns true if Init() was run.
+ */
+ bool Initialized() const { return m_initialized; }
+
+ /*!
+ * Returns true if the current frame is being used as the alignment reference.
+ */
+ bool IsCurrentReference() const { return m_current_is_reference; }
+
+ /*!
+ * Returns true if we need to call UpdateReference now.
+ */
+ bool NeedReferenceUpdate();
+
+ /*!
+ * Returns the pointer reference to the alignment reference image data
+ */
+ unsigned char ** GetReferenceImage() { return m_reference_image; }
+
+ /*!
+ * Returns the pointer reference to the double array containing the homogeneous coordinates for the matched reference image corners.
+ */
+ double * GetRefCorners() { return m_corners_ref; }
+ /*!
+ * Returns the pointer reference to the double array containing the homogeneous coordinates for the matched inspection image corners.
+ */
+ double * GetInsCorners() { return m_corners_ins; }
+ /*!
+ * Returns the number of correspondences between the reference and inspection images.
+ */
+ int GetNrMatches() { return m_nr_matches; }
+
+ /*!
+ * Returns the number of corners detected in the current reference image.
+ */
+ int GetNrRefCorners() { return m_nr_corners_ref; }
+
+ /*!
+ * Returns the pointer to an array of indices that were found to be RANSAC inliers from the matched corner lists.
+ */
+ int* GetInliers() { return m_inlier_indices; }
+
+ /*!
+ * Returns the number of inliers from the RANSAC matching step.
+ */
+ int GetNrInliers() { return m_num_inlier_indices; }
+
+ //std::vector<int>& GetInliers();
+ //void Polish(std::vector<int> &inlier_indices);
+
+ /*!
+ * Perform a linear polishing step by re-estimating the alignment transformation using the RANSAC inliers.
+ * \param inlier_indices pointer to an array of indices that were found to be RANSAC inliers from the matched corner lists.
+ * \param num_inlier_indices number of inliers i.e. the length of the array passed as the first argument.
+ */
+ void Polish(int *inlier_indices, int &num_inlier_indices);
+
+ /*!
+ * Reset the motion smoothing parameters to their initial values.
+ */
+ void ResetMotionSmoothingParameters() { m_stab_smoother.Init(); }
+
+ /*!
+ * Update the alignment reference image to the specified image.
+ * \param im pointer to the image data to be used as the new alignment reference.
+ * \param subsample boolean flag to control whether the function should internally subsample the provided image to the size provided in the Init() function.
+ */
+ int UpdateReference(const unsigned char * const * im, bool subsample = true, bool detect_corners = true);
+
+ /*!
+ * Returns the transformation from the display reference to the alignment reference frame
+ */
+ void Get_H_dref_to_ref(double H[9]);
+ /*!
+ * Returns the transformation from the display reference to the inspection reference frame
+ */
+ void Get_H_dref_to_ins(double H[9]);
+ /*!
+ * Set the transformation from the display reference to the inspection reference frame
+ * \param H the transformation to set
+ */
+ void Set_H_dref_to_ins(double H[9]);
+
+ /*!
+ * Reset the display reference to the current frame.
+ */
+ void ResetDisplayReference();
+
+ /*!
+ * Estimate a secondary motion model starting from the specified transformation.
+ * \param H the primary motion model to start from
+ */
+ void EstimateSecondaryModel(double H[9]);
+
+ /*!
+ *
+ */
+ void SelectOutliers();
+
+ char *profile_string;
+
+protected:
+ void Clean();
+ void GenerateQuarterResImage(const unsigned char* const * im);
+
+ int m_im_width;
+ int m_im_height;
+
+ // RANSAC and refinement parameters:
+ int m_homography_type;
+ int m_max_iterations;
+ double m_scale;
+ int m_nr_samples;
+ int m_chunk_size;
+ double m_outlier_t2;
+
+ // Whether to fit a linear model to just the inliers at the end
+ bool m_linear_polish;
+ double m_polish_C[36];
+ double m_polish_D[6];
+
+ // local state
+ bool m_current_is_reference;
+ bool m_initialized;
+
+ // inspection to reference homography:
+ double m_H_ref_to_ins[9];
+ double m_H_dref_to_ref[9];
+
+ // feature extraction and matching:
+ db_CornerDetector_u m_cd;
+ db_Matcher_u m_cm;
+
+ // length of corner arrays:
+ unsigned long m_max_nr_corners;
+
+ // corner locations of reference image features:
+ double * m_x_corners_ref;
+ double * m_y_corners_ref;
+ int m_nr_corners_ref;
+
+ // corner locations of inspection image features:
+ double * m_x_corners_ins;
+ double * m_y_corners_ins;
+ int m_nr_corners_ins;
+
+ // length of match index arrays:
+ unsigned long m_max_nr_matches;
+
+ // match indices:
+ int * m_match_index_ref;
+ int * m_match_index_ins;
+ int m_nr_matches;
+
+ // pointer to internal copy of the reference image:
+ unsigned char ** m_reference_image;
+
+ // pointer to internal copy of last aligned inspection image:
+ unsigned char ** m_aligned_ins_image;
+
+ // pointer to quarter resolution image, if used.
+ unsigned char** m_quarter_res_image;
+
+ // temporary storage for the quarter resolution image processing
+ unsigned char** m_horz_smooth_subsample_image;
+
+ // temporary space for homography computation:
+ double * m_temp_double;
+ int * m_temp_int;
+
+ // homogenous image point arrays:
+ double * m_corners_ref;
+ double * m_corners_ins;
+
+ // Indices of the points within the match lists
+ int * m_inlier_indices;
+ int m_num_inlier_indices;
+
+ //void ComputeInliers(double H[9], std::vector<int> &inlier_indices);
+ void ComputeInliers(double H[9]);
+
+ // cost arrays:
+ void ComputeCostArray();
+ bool m_sq_cost_computed;
+ double * m_sq_cost;
+
+ // cost histogram:
+ void ComputeCostHistogram();
+ int *m_cost_histogram;
+
+ void SetOutlierThreshold();
+
+ // utility function for smoothing the motion parameters.
+ void SmoothMotion(void);
+
+private:
+ double m_K[9];
+ const int m_over_allocation;
+
+ bool m_reference_set;
+
+ // Maximum number of inliers seen until now w.r.t the current reference frame
+ int m_max_inlier_count;
+
+ // Number of cost histogram bins:
+ int m_nr_bins;
+ // All costs above this threshold get put into the last bin:
+ int m_max_cost_pix;
+
+ // whether to quarter the image resolution for processing, or not
+ bool m_quarter_resolution;
+
+ // the period (in number of frames) for reference update.
+ unsigned int m_reference_update_period;
+
+ // the number of frames processed so far.
+ unsigned int m_nr_frames_processed;
+
+ // smoother for motion transformations
+ db_StabilizationSmoother m_stab_smoother;
+
+ // boolean to control whether motion smoothing occurs (or not)
+ bool m_do_motion_smoothing;
+
+ // double to set the gain for motion smoothing
+ double m_motion_smoothing_gain;
+};
+/*!
+ Create look-up tables to undistort images. Only Bougeut (Matlab toolkit)
+ is currently supported. Can be used with db_WarpImageLut_u().
+ \code
+ xd = H*xs;
+ xd = xd/xd(3);
+ \endcode
+ \param lut_x pre-allocated float image
+ \param lut_y pre-allocated float image
+ \param w width
+ \param h height
+ \param H image homography from source to destination
+ */
+inline void db_GenerateHomographyLut(float ** lut_x,float ** lut_y,int w,int h,const double H[9])
+{
+ assert(lut_x && lut_y);
+ double x[3] = {0.0,0.0,1.0};
+ double xb[3];
+
+/*
+ double xl[3];
+
+ // Determine the output coordinate system ROI
+ double Hinv[9];
+ db_InvertAffineTransform(Hinv,H);
+ db_Multiply3x3_3x1(xl, Hinv, x);
+ xl[0] = db_SafeDivision(xl[0],xl[2]);
+ xl[1] = db_SafeDivision(xl[1],xl[2]);
+*/
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ x[0] = double(i);
+ x[1] = double(j);
+ db_Multiply3x3_3x1(xb, H, x);
+ xb[0] = db_SafeDivision(xb[0],xb[2]);
+ xb[1] = db_SafeDivision(xb[1],xb[2]);
+
+ lut_x[j][i] = float(xb[0]);
+ lut_y[j][i] = float(xb[1]);
+ }
+}
+
+/*!
+ * Perform a look-up table warp for packed RGB ([rgbrgbrgb...]) images.
+ * The LUTs must be float images of the same size as source image.
+ * The source value x_s is determined from destination (x_d,y_d) through lut_x
+ * and y_s is determined from lut_y:
+ \code
+ x_s = lut_x[y_d][x_d];
+ y_s = lut_y[y_d][x_d];
+ \endcode
+
+ * \param src source image (w*3 by h)
+ * \param dst destination image (w*3 by h)
+ * \param w width
+ * \param h height
+ * \param lut_x LUT for x
+ * \param lut_y LUT for y
+ */
+inline void db_WarpImageLutFast_rgb(const unsigned char * const * src, unsigned char ** dst, int w, int h,
+ const float * const * lut_x, const float * const * lut_y)
+{
+ assert(src && dst);
+ int xd=0, yd=0;
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ xd = static_cast<unsigned int>(lut_x[j][i]);
+ yd = static_cast<unsigned int>(lut_y[j][i]);
+ if ( xd >= w || yd >= h ||
+ xd < 0 || yd < 0)
+ {
+ dst[j][3*i ] = 0;
+ dst[j][3*i+1] = 0;
+ dst[j][3*i+2] = 0;
+ }
+ else
+ {
+ dst[j][3*i ] = src[yd][3*xd ];
+ dst[j][3*i+1] = src[yd][3*xd+1];
+ dst[j][3*i+2] = src[yd][3*xd+2];
+ }
+ }
+}
+
+inline unsigned char db_BilinearInterpolationRGB(double y, double x, const unsigned char * const * v, int offset)
+{
+ int floor_x=(int) x;
+ int floor_y=(int) y;
+
+ int ceil_x=floor_x+1;
+ int ceil_y=floor_y+1;
+
+ unsigned char f00 = v[floor_y][3*floor_x+offset];
+ unsigned char f01 = v[floor_y][3*ceil_x+offset];
+ unsigned char f10 = v[ceil_y][3*floor_x+offset];
+ unsigned char f11 = v[ceil_y][3*ceil_x+offset];
+
+ double xl = x-floor_x;
+ double yl = y-floor_y;
+
+ return (unsigned char)(f00*(1-yl)*(1-xl) + f10*yl*(1-xl) + f01*(1-yl)*xl + f11*yl*xl);
+}
+
+inline void db_WarpImageLutBilinear_rgb(const unsigned char * const * src, unsigned char ** dst, int w, int h,
+ const float * const * lut_x, const float * const * lut_y)
+{
+ assert(src && dst);
+ double xd=0.0, yd=0.0;
+
+ for ( int i = 0; i < w; ++i )
+ for ( int j = 0; j < h; ++j )
+ {
+ xd = static_cast<double>(lut_x[j][i]);
+ yd = static_cast<double>(lut_y[j][i]);
+ if ( xd > w-2 || yd > h-2 ||
+ xd < 0.0 || yd < 0.0)
+ {
+ dst[j][3*i ] = 0;
+ dst[j][3*i+1] = 0;
+ dst[j][3*i+2] = 0;
+ }
+ else
+ {
+ dst[j][3*i ] = db_BilinearInterpolationRGB(yd,xd,src,0);
+ dst[j][3*i+1] = db_BilinearInterpolationRGB(yd,xd,src,1);
+ dst[j][3*i+2] = db_BilinearInterpolationRGB(yd,xd,src,2);
+ }
+ }
+}
+
+inline double SquaredInhomogenousHomographyError(double y[3],double H[9],double x[3]){
+ double x0,x1,x2,mult;
+ double sd;
+
+ x0=H[0]*x[0]+H[1]*x[1]+H[2];
+ x1=H[3]*x[0]+H[4]*x[1]+H[5];
+ x2=H[6]*x[0]+H[7]*x[1]+H[8];
+ mult=1.0/((x2!=0.0)?x2:1.0);
+ sd=(y[0]-x0*mult)*(y[0]-x0*mult)+(y[1]-x1*mult)*(y[1]-x1*mult);
+
+ return(sd);
+}
+
+
+// functions related to profiling
+#if PROFILE
+
+/* return current time in milliseconds */
+static double
+now_ms(void)
+{
+ //struct timespec res;
+ struct timeval res;
+ //clock_gettime(CLOCK_REALTIME, &res);
+ gettimeofday(&res, NULL);
+ return 1000.0*res.tv_sec + (double)res.tv_usec/1e3;
+}
+
+#endif
diff --git a/jni/feature_stab/src/dbreg/dbstabsmooth.cpp b/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
new file mode 100644
index 000000000..dffff8ab1
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/dbstabsmooth.cpp
@@ -0,0 +1,330 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <stdlib.h>
+#include "dbstabsmooth.h"
+
+///// TODO TODO ////////// Replace this with the actual definition from Jayan's reply /////////////
+#define vp_copy_motion_no_id vp_copy_motion
+///////////////////////////////////////////////////////////////////////////////////////////////////
+
+static bool vpmotion_add(VP_MOTION *in1, VP_MOTION *in2, VP_MOTION *out);
+static bool vpmotion_multiply(VP_MOTION *in1, double factor, VP_MOTION *out);
+
+db_StabilizationSmoother::db_StabilizationSmoother()
+{
+ Init();
+}
+
+void db_StabilizationSmoother::Init()
+{
+ f_smoothOn = true;
+ f_smoothReset = false;
+ f_smoothFactor = 1.0f;
+ f_minDampingFactor = 0.2f;
+ f_zoom = 1.0f;
+ VP_MOTION_ID(f_motLF);
+ VP_MOTION_ID(f_imotLF);
+ f_hsize = 0;
+ f_vsize = 0;
+
+ VP_MOTION_ID(f_disp_mot);
+ VP_MOTION_ID(f_src_mot);
+ VP_MOTION_ID(f_diff_avg);
+
+ for( int i = 0; i < MOTION_ARRAY-1; i++) {
+ VP_MOTION_ID(f_hist_mot_speed[i]);
+ VP_MOTION_ID(f_hist_mot[i]);
+ VP_MOTION_ID(f_hist_diff_mot[i]);
+ }
+ VP_MOTION_ID(f_hist_mot[MOTION_ARRAY-1]);
+
+}
+
+db_StabilizationSmoother::~db_StabilizationSmoother()
+{}
+
+
+bool db_StabilizationSmoother::smoothMotion(VP_MOTION *inmot, VP_MOTION *outmot)
+{
+ VP_MOTION_ID(f_motLF);
+ VP_MOTION_ID(f_imotLF);
+ f_motLF.insid = inmot->refid;
+ f_motLF.refid = inmot->insid;
+
+ if(f_smoothOn) {
+ if(!f_smoothReset) {
+ MXX(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MXX(f_motLF) + (1.0-f_smoothFactor)* (double) MXX(*inmot));
+ MXY(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MXY(f_motLF) + (1.0-f_smoothFactor)* (double) MXY(*inmot));
+ MXZ(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MXZ(f_motLF) + (1.0-f_smoothFactor)* (double) MXZ(*inmot));
+ MXW(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MXW(f_motLF) + (1.0-f_smoothFactor)* (double) MXW(*inmot));
+
+ MYX(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MYX(f_motLF) + (1.0-f_smoothFactor)* (double) MYX(*inmot));
+ MYY(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MYY(f_motLF) + (1.0-f_smoothFactor)* (double) MYY(*inmot));
+ MYZ(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MYZ(f_motLF) + (1.0-f_smoothFactor)* (double) MYZ(*inmot));
+ MYW(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MYW(f_motLF) + (1.0-f_smoothFactor)* (double) MYW(*inmot));
+
+ MZX(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MZX(f_motLF) + (1.0-f_smoothFactor)* (double) MZX(*inmot));
+ MZY(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MZY(f_motLF) + (1.0-f_smoothFactor)* (double) MZY(*inmot));
+ MZZ(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MZZ(f_motLF) + (1.0-f_smoothFactor)* (double) MZZ(*inmot));
+ MZW(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MZW(f_motLF) + (1.0-f_smoothFactor)* (double) MZW(*inmot));
+
+ MWX(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MWX(f_motLF) + (1.0-f_smoothFactor)* (double) MWX(*inmot));
+ MWY(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MWY(f_motLF) + (1.0-f_smoothFactor)* (double) MWY(*inmot));
+ MWZ(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MWZ(f_motLF) + (1.0-f_smoothFactor)* (double) MWZ(*inmot));
+ MWW(f_motLF) = (VP_PAR) (f_smoothFactor*(double) MWW(f_motLF) + (1.0-f_smoothFactor)* (double) MWW(*inmot));
+ }
+ else
+ vp_copy_motion_no_id(inmot, &f_motLF); // f_smoothFactor = 0.0
+
+ // Only allow LF motion to be compensated. Remove HF motion from
+ // the output transformation
+ if(!vp_invert_motion(&f_motLF, &f_imotLF))
+ return false;
+
+ if(!vp_cascade_motion(&f_imotLF, inmot, outmot))
+ return false;
+ }
+ else {
+ vp_copy_motion_no_id(inmot, outmot);
+ }
+
+ return true;
+}
+
+bool db_StabilizationSmoother::smoothMotionAdaptive(/*VP_BIMG *bimg,*/int hsize, int vsize, VP_MOTION *inmot, VP_MOTION *outmot)
+{
+ VP_MOTION tmpMotion, testMotion;
+ VP_PAR p1x, p2x, p3x, p4x;
+ VP_PAR p1y, p2y, p3y, p4y;
+ double smoothFactor;
+ double minSmoothFactor = f_minDampingFactor;
+
+// int hsize = bimg->w;
+// int vsize = bimg->h;
+ double border_factor = 0.01;//0.2;
+ double border_x = border_factor * hsize;
+ double border_y = border_factor * vsize;
+
+ VP_MOTION_ID(f_motLF);
+ VP_MOTION_ID(f_imotLF);
+ VP_MOTION_ID(testMotion);
+ VP_MOTION_ID(tmpMotion);
+
+ if (f_smoothOn) {
+ VP_MOTION identityMotion;
+ VP_MOTION_ID(identityMotion); // initialize the motion
+ vp_copy_motion(inmot/*in*/, &testMotion/*out*/);
+ VP_PAR delta = vp_motion_cornerdiff(&testMotion, &identityMotion, 0, 0,(int)hsize, (int)vsize);
+
+ smoothFactor = 0.99 - 0.0015 * delta;
+
+ if(smoothFactor < minSmoothFactor)
+ smoothFactor = minSmoothFactor;
+
+ // Find the amount of motion that must be compensated so that no "border" pixels are seen in the stable video
+ for (smoothFactor = smoothFactor; smoothFactor >= minSmoothFactor; smoothFactor -= 0.01) {
+ // Compute the smoothed motion
+ if(!smoothMotion(inmot, &tmpMotion, smoothFactor))
+ break;
+
+ // TmpMotion, or Qsi where s is the smoothed display reference and i is the
+ // current image, tells us how points in the S co-ordinate system map to
+ // points in the I CS. We would like to check whether the four corners of the
+ // warped and smoothed display reference lies entirely within the I co-ordinate
+ // system. If yes, then the amount of smoothing is sufficient so that NO
+ // border pixels are seen at the output. We test for f_smoothFactor terms
+ // between 0.9 and 1.0, in steps of 0.01, and between 0.5 ands 0.9 in steps of 0.1
+
+ (void) vp_zoom_motion2d(&tmpMotion, &testMotion, 1, hsize, vsize, (double)f_zoom); // needs to return bool
+
+ VP_WARP_POINT_2D(0, 0, testMotion, p1x, p1y);
+ VP_WARP_POINT_2D(hsize - 1, 0, testMotion, p2x, p2y);
+ VP_WARP_POINT_2D(hsize - 1, vsize - 1, testMotion, p3x, p3y);
+ VP_WARP_POINT_2D(0, vsize - 1, testMotion, p4x, p4y);
+
+ if (!is_point_in_rect((double)p1x,(double)p1y,-border_x,-border_y,(double)(hsize+2.0*border_x),(double)(vsize+2.0*border_y))) {
+ continue;
+ }
+ if (!is_point_in_rect((double)p2x, (double)p2y,-border_x,-border_y,(double)(hsize+2.0*border_x),(double)(vsize+2.0*border_y))) {
+ continue;
+ }
+ if (!is_point_in_rect((double)p3x,(double)p3y,-border_x,-border_y,(double)(hsize+2.0*border_x),(double)(vsize+2.0*border_y))) {
+ continue;
+ }
+ if (!is_point_in_rect((double)p4x, (double)p4y,-border_x,-border_y,(double)(hsize+2.0*border_x),(double)(vsize+2.0*border_y))) {
+ continue;
+ }
+
+ // If we get here, then all the points are in the rectangle.
+ // Therefore, break out of this loop
+ break;
+ }
+
+ // if we get here and f_smoothFactor <= fMinDampingFactor, reset the stab reference
+ if (smoothFactor < f_minDampingFactor)
+ smoothFactor = f_minDampingFactor;
+
+ // use the smoothed motion for stabilization
+ vp_copy_motion_no_id(&tmpMotion/*in*/, outmot/*out*/);
+ }
+ else
+ {
+ vp_copy_motion_no_id(inmot, outmot);
+ }
+
+ return true;
+}
+
+bool db_StabilizationSmoother::smoothMotion(VP_MOTION *inmot, VP_MOTION *outmot, double smooth_factor)
+{
+ f_motLF.insid = inmot->refid;
+ f_motLF.refid = inmot->insid;
+
+ if(f_smoothOn) {
+ if(!f_smoothReset) {
+ MXX(f_motLF) = (VP_PAR) (smooth_factor*(double) MXX(f_motLF) + (1.0-smooth_factor)* (double) MXX(*inmot));
+ MXY(f_motLF) = (VP_PAR) (smooth_factor*(double) MXY(f_motLF) + (1.0-smooth_factor)* (double) MXY(*inmot));
+ MXZ(f_motLF) = (VP_PAR) (smooth_factor*(double) MXZ(f_motLF) + (1.0-smooth_factor)* (double) MXZ(*inmot));
+ MXW(f_motLF) = (VP_PAR) (smooth_factor*(double) MXW(f_motLF) + (1.0-smooth_factor)* (double) MXW(*inmot));
+
+ MYX(f_motLF) = (VP_PAR) (smooth_factor*(double) MYX(f_motLF) + (1.0-smooth_factor)* (double) MYX(*inmot));
+ MYY(f_motLF) = (VP_PAR) (smooth_factor*(double) MYY(f_motLF) + (1.0-smooth_factor)* (double) MYY(*inmot));
+ MYZ(f_motLF) = (VP_PAR) (smooth_factor*(double) MYZ(f_motLF) + (1.0-smooth_factor)* (double) MYZ(*inmot));
+ MYW(f_motLF) = (VP_PAR) (smooth_factor*(double) MYW(f_motLF) + (1.0-smooth_factor)* (double) MYW(*inmot));
+
+ MZX(f_motLF) = (VP_PAR) (smooth_factor*(double) MZX(f_motLF) + (1.0-smooth_factor)* (double) MZX(*inmot));
+ MZY(f_motLF) = (VP_PAR) (smooth_factor*(double) MZY(f_motLF) + (1.0-smooth_factor)* (double) MZY(*inmot));
+ MZZ(f_motLF) = (VP_PAR) (smooth_factor*(double) MZZ(f_motLF) + (1.0-smooth_factor)* (double) MZZ(*inmot));
+ MZW(f_motLF) = (VP_PAR) (smooth_factor*(double) MZW(f_motLF) + (1.0-smooth_factor)* (double) MZW(*inmot));
+
+ MWX(f_motLF) = (VP_PAR) (smooth_factor*(double) MWX(f_motLF) + (1.0-smooth_factor)* (double) MWX(*inmot));
+ MWY(f_motLF) = (VP_PAR) (smooth_factor*(double) MWY(f_motLF) + (1.0-smooth_factor)* (double) MWY(*inmot));
+ MWZ(f_motLF) = (VP_PAR) (smooth_factor*(double) MWZ(f_motLF) + (1.0-smooth_factor)* (double) MWZ(*inmot));
+ MWW(f_motLF) = (VP_PAR) (smooth_factor*(double) MWW(f_motLF) + (1.0-smooth_factor)* (double) MWW(*inmot));
+ }
+ else
+ vp_copy_motion_no_id(inmot, &f_motLF); // smooth_factor = 0.0
+
+ // Only allow LF motion to be compensated. Remove HF motion from
+ // the output transformation
+ if(!vp_invert_motion(&f_motLF, &f_imotLF))
+ return false;
+
+ if(!vp_cascade_motion(&f_imotLF, inmot, outmot))
+ return false;
+ }
+ else {
+ vp_copy_motion_no_id(inmot, outmot);
+ }
+
+ return true;
+}
+
+//! Overloaded smoother function that takes in user-specidied smoothing factor
+bool
+db_StabilizationSmoother::smoothMotion1(VP_MOTION *inmot, VP_MOTION *outmot, VP_MOTION *motLF, VP_MOTION *imotLF, double factor)
+{
+
+ if(!f_smoothOn) {
+ vp_copy_motion(inmot, outmot);
+ return true;
+ }
+ else {
+ if(!f_smoothReset) {
+ MXX(*motLF) = (VP_PAR) (factor*(double) MXX(*motLF) + (1.0-factor)* (double) MXX(*inmot));
+ MXY(*motLF) = (VP_PAR) (factor*(double) MXY(*motLF) + (1.0-factor)* (double) MXY(*inmot));
+ MXZ(*motLF) = (VP_PAR) (factor*(double) MXZ(*motLF) + (1.0-factor)* (double) MXZ(*inmot));
+ MXW(*motLF) = (VP_PAR) (factor*(double) MXW(*motLF) + (1.0-factor)* (double) MXW(*inmot));
+
+ MYX(*motLF) = (VP_PAR) (factor*(double) MYX(*motLF) + (1.0-factor)* (double) MYX(*inmot));
+ MYY(*motLF) = (VP_PAR) (factor*(double) MYY(*motLF) + (1.0-factor)* (double) MYY(*inmot));
+ MYZ(*motLF) = (VP_PAR) (factor*(double) MYZ(*motLF) + (1.0-factor)* (double) MYZ(*inmot));
+ MYW(*motLF) = (VP_PAR) (factor*(double) MYW(*motLF) + (1.0-factor)* (double) MYW(*inmot));
+
+ MZX(*motLF) = (VP_PAR) (factor*(double) MZX(*motLF) + (1.0-factor)* (double) MZX(*inmot));
+ MZY(*motLF) = (VP_PAR) (factor*(double) MZY(*motLF) + (1.0-factor)* (double) MZY(*inmot));
+ MZZ(*motLF) = (VP_PAR) (factor*(double) MZZ(*motLF) + (1.0-factor)* (double) MZZ(*inmot));
+ MZW(*motLF) = (VP_PAR) (factor*(double) MZW(*motLF) + (1.0-factor)* (double) MZW(*inmot));
+
+ MWX(*motLF) = (VP_PAR) (factor*(double) MWX(*motLF) + (1.0-factor)* (double) MWX(*inmot));
+ MWY(*motLF) = (VP_PAR) (factor*(double) MWY(*motLF) + (1.0-factor)* (double) MWY(*inmot));
+ MWZ(*motLF) = (VP_PAR) (factor*(double) MWZ(*motLF) + (1.0-factor)* (double) MWZ(*inmot));
+ MWW(*motLF) = (VP_PAR) (factor*(double) MWW(*motLF) + (1.0-factor)* (double) MWW(*inmot));
+ }
+ else {
+ vp_copy_motion(inmot, motLF);
+ }
+ // Only allow LF motion to be compensated. Remove HF motion from the output transformation
+ if(!vp_invert_motion(motLF, imotLF)) {
+#if DEBUG_PRINT
+ printfOS("Invert failed \n");
+#endif
+ return false;
+ }
+ if(!vp_cascade_motion(imotLF, inmot, outmot)) {
+#if DEBUG_PRINT
+ printfOS("cascade failed \n");
+#endif
+ return false;
+ }
+ }
+ return true;
+}
+
+
+
+
+bool db_StabilizationSmoother::is_point_in_rect(double px, double py, double rx, double ry, double w, double h)
+{
+ if (px < rx)
+ return(false);
+ if (px >= rx + w)
+ return(false);
+ if (py < ry)
+ return(false);
+ if (py >= ry + h)
+ return(false);
+
+ return(true);
+}
+
+
+
+static bool vpmotion_add(VP_MOTION *in1, VP_MOTION *in2, VP_MOTION *out)
+{
+ int i;
+ if(in1 == NULL || in2 == NULL || out == NULL)
+ return false;
+
+ for(i = 0; i < VP_MAX_MOTION_PAR; i++)
+ out->par[i] = in1->par[i] + in2->par[i];
+
+ return true;
+}
+
+static bool vpmotion_multiply(VP_MOTION *in1, double factor, VP_MOTION *out)
+{
+ int i;
+ if(in1 == NULL || out == NULL)
+ return false;
+
+ for(i = 0; i < VP_MAX_MOTION_PAR; i++)
+ out->par[i] = in1->par[i] * factor;
+
+ return true;
+}
+
diff --git a/jni/feature_stab/src/dbreg/dbstabsmooth.h b/jni/feature_stab/src/dbreg/dbstabsmooth.h
new file mode 100644
index 000000000..f03546ef6
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/dbstabsmooth.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+
+#ifdef _WIN32
+#ifdef DBREG_EXPORTS
+#define DBREG_API __declspec(dllexport)
+#else
+#define DBREG_API __declspec(dllimport)
+#endif
+#else
+#define DBREG_API
+#endif
+
+extern "C" {
+#include "vp_motionmodel.h"
+}
+
+#define MOTION_ARRAY 5
+
+
+/*!
+ * Performs smoothing on the motion estimate from feature_stab.
+ */
+class DBREG_API db_StabilizationSmoother
+{
+public:
+ db_StabilizationSmoother();
+ ~db_StabilizationSmoother();
+
+ /*!
+ * Initialize parameters for stab-smoother.
+ */
+ void Init();
+
+ //! Smothing type
+ typedef enum {
+ SimpleSmooth = 0, //!< simple smooth
+ AdaptSmooth = 1, //!< adaptive smooth
+ PanSmooth = 2 //!< pan motion smooth
+ } SmoothType;
+
+ /*!
+ * Smooth-motion is to do a weight-average between the current affine and
+ * motLF. The way to change the affine is only for the display purpose.
+ * It removes the high frequency motion and keep the low frequency motion
+ * to the display. IIR implmentation.
+ * \param inmot input motion parameters
+ * \param outmot smoothed output motion parameters
+ */
+ bool smoothMotion(VP_MOTION *inmot, VP_MOTION *outmot);
+
+ /*!
+ * The adaptive smoothing version of the above fixed smoothing function.
+ * \param hsize width of the image being aligned
+ * \param vsize height of the image being aligned
+ * \param inmot input motion parameters
+ * \param outmot smoothed output motion parameters
+ */
+ bool smoothMotionAdaptive(/*VP_BIMG *bimg,*/int hsize, int vsize, VP_MOTION *inmot, VP_MOTION *outmot);
+ bool smoothPanMotion_1(VP_MOTION *inmot, VP_MOTION *outmot);
+ bool smoothPanMotion_2(VP_MOTION *inmot, VP_MOTION *outmot);
+
+ /*!
+ * Set the smoothing factor for the stab-smoother.
+ * \param factor the factor value to set
+ */
+ inline void setSmoothingFactor(float factor) { f_smoothFactor = factor; }
+
+ /*!
+ * Reset smoothing
+ */
+ inline void resetSmoothing(bool flag) { f_smoothReset = flag; }
+ /*!
+ * Set the zoom factor value.
+ * \param zoom the value to set to
+ */
+ inline void setZoomFactor(float zoom) { f_zoom = zoom; }
+ /*!
+ * Set the minimum damping factor value.
+ * \param factor the value to set to
+ */
+ inline void setminDampingFactor(float factor) { f_minDampingFactor = factor; }
+
+ /*!
+ * Returns the current smoothing factor.
+ */
+ inline float getSmoothingFactor(void) { return f_smoothFactor; }
+ /*!
+ * Returns the current zoom factor.
+ */
+ inline float getZoomFactor(void) { return f_zoom; }
+ /*!
+ * Returns the current minimum damping factor.
+ */
+ inline float getminDampingFactor(void) { return f_minDampingFactor; }
+ /*!
+ * Returns the current state of the smoothing reset flag.
+ */
+ inline bool getSmoothReset(void) { return f_smoothReset; }
+ /*!
+ * Returns the current low frequency motion parameters.
+ */
+ inline VP_MOTION getMotLF(void) { return f_motLF; }
+ /*!
+ * Returns the inverse of the current low frequency motion parameters.
+ */
+ inline VP_MOTION getImotLF(void) { return f_imotLF; }
+ /*!
+ * Set the dimensions of the alignment image.
+ * \param hsize width of the image
+ * \param vsize height of the image
+ */
+ inline void setSize(int hsize, int vsize) { f_hsize = hsize; f_vsize = vsize; }
+
+protected:
+
+ bool smoothMotion(VP_MOTION *inmot, VP_MOTION *outmot, double smooth_factor);
+ bool smoothMotion1(VP_MOTION *inmot, VP_MOTION *outmot, VP_MOTION *motLF, VP_MOTION *imotLF, double smooth_factor);
+ void iterativeSmooth(VP_MOTION *input, VP_MOTION *output, double border_factor);
+ bool is_point_in_rect(double px, double py, double rx, double ry, double w, double h);
+
+
+private:
+ int f_hsize;
+ int f_vsize;
+ bool f_smoothOn;
+ bool f_smoothReset;
+ float f_smoothFactor;
+ float f_minDampingFactor;
+ float f_zoom;
+ VP_MOTION f_motLF;
+ VP_MOTION f_imotLF;
+ VP_MOTION f_hist_mot[MOTION_ARRAY];
+ VP_MOTION f_hist_mot_speed[MOTION_ARRAY-1];
+ VP_MOTION f_hist_diff_mot[MOTION_ARRAY-1];
+ VP_MOTION f_disp_mot;
+ VP_MOTION f_src_mot;
+ VP_MOTION f_diff_avg;
+
+};
+
diff --git a/jni/feature_stab/src/dbreg/targetver.h b/jni/feature_stab/src/dbreg/targetver.h
new file mode 100644
index 000000000..3ca3e8792
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/targetver.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef WINVER // Specifies that the minimum required platform is Windows Vista.
+#define WINVER 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+
+#ifndef _WIN32_WINDOWS // Specifies that the minimum required platform is Windows 98.
+#define _WIN32_WINDOWS 0x0410 // Change this to the appropriate value to target Windows Me or later.
+#endif
+
+#ifndef _WIN32_IE // Specifies that the minimum required platform is Internet Explorer 7.0.
+#define _WIN32_IE 0x0700 // Change this to the appropriate value to target other versions of IE.
+#endif
diff --git a/jni/feature_stab/src/dbreg/vp_motionmodel.c b/jni/feature_stab/src/dbreg/vp_motionmodel.c
new file mode 100644
index 000000000..1f6af15bd
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/vp_motionmodel.c
@@ -0,0 +1,377 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+#sourcefile vpmotion/vp_motionmodel.c
+#category motion-model
+*
+* Copyright 1998 Sarnoff Corporation
+* All Rights Reserved
+*
+* Modification History
+* Date: 02/14/98
+* Author: supuns
+* Shop Order: 17xxx
+* @(#) $Id: vp_motionmodel.c,v 1.4 2011/06/17 14:04:33 mbansal Exp $
+*/
+
+/*
+* ===================================================================
+* Include Files
+*/
+
+#include <string.h> /* memmove */
+#include <math.h>
+#include "vp_motionmodel.h"
+
+/* Static Functions */
+static
+double Det3(double m[3][3])
+{
+ double result;
+
+ result =
+ m[0][0]*m[1][1]*m[2][2] + m[0][1]*m[1][2]*m[2][0] +
+ m[0][2]*m[1][0]*m[2][1] - m[0][2]*m[1][1]*m[2][0] -
+ m[0][0]*m[1][2]*m[2][1] - m[0][1]*m[1][0]*m[2][2];
+
+ return(result);
+}
+
+typedef double MATRIX[4][4];
+
+static
+double Det4(MATRIX m)
+{
+ /* ==> This is a poor implementation of determinant.
+ Writing the formula out in closed form is unnecessarily complicated
+ and mistakes are easy to make. */
+ double result;
+
+ result=
+ m[0][3] *m[1][2] *m[2][1] *m[3][0] - m[0][2] *m[1][3] *m[2][1] *m[3][0] - m[0][3] *m[1][1] *m[2][2] *m[3][0] +
+ m[0][1] *m[1][3] *m[2][2] *m[3][0] + m[0][2] *m[1][1] *m[2][3] *m[3][0] - m[0][1] *m[1][2] *m[2][3] *m[3][0] - m[0][3] *m[1][2] *m[2][0] *m[3][1] +
+ m[0][2] *m[1][3] *m[2][0] *m[3][1] + m[0][3] *m[1][0] *m[2][2] *m[3][1] - m[0][0] *m[1][3] *m[2][2] *m[3][1] - m[0][2] *m[1][0] *m[2][3] *m[3][1] +
+ m[0][0] *m[1][2] *m[2][3] *m[3][1] + m[0][3] *m[1][1] *m[2][0] *m[3][2] - m[0][1] *m[1][3] *m[2][0] *m[3][2] - m[0][3] *m[1][0] *m[2][1] *m[3][2] +
+ m[0][0] *m[1][3] *m[2][1] *m[3][2] + m[0][1] *m[1][0] *m[2][3] *m[3][2] - m[0][0] *m[1][1] *m[2][3] *m[3][2] - m[0][2] *m[1][1] *m[2][0] *m[3][3] +
+ m[0][1] *m[1][2] *m[2][0] *m[3][3] + m[0][2] *m[1][0] *m[2][1] *m[3][3] - m[0][0] *m[1][2] *m[2][1] *m[3][3] - m[0][1] *m[1][0] *m[2][2] *m[3][3] +
+ m[0][0] *m[1][1] *m[2][2] *m[3][3];
+ /*
+ m[0][0]*m[1][1]*m[2][2]*m[3][3]-m[0][1]*m[1][0]*m[2][2]*m[3][3]+
+ m[0][1]*m[1][2]*m[2][0]*m[3][3]-m[0][2]*m[1][1]*m[2][0]*m[3][3]+
+ m[0][2]*m[1][0]*m[2][1]*m[3][3]-m[0][0]*m[1][2]*m[2][1]*m[3][3]+
+ m[0][0]*m[1][2]*m[2][3]*m[3][1]-m[0][2]*m[1][0]*m[2][3]*m[3][1]+
+ m[0][2]*m[1][3]*m[2][0]*m[3][1]-m[0][3]*m[1][2]*m[2][0]*m[3][1]+
+ m[0][3]*m[1][0]*m[2][2]*m[3][1]-m[0][0]*m[1][3]*m[2][2]*m[3][1]+
+ m[0][0]*m[1][3]*m[2][1]*m[3][2]-m[0][3]*m[1][0]*m[2][3]*m[3][2]+
+ m[0][1]*m[1][0]*m[2][3]*m[3][2]-m[0][0]*m[1][1]*m[2][0]*m[3][2]+
+ m[0][3]*m[1][1]*m[2][0]*m[3][2]-m[0][1]*m[1][3]*m[2][1]*m[3][2]+
+ m[0][1]*m[1][3]*m[2][2]*m[3][0]-m[0][3]*m[1][1]*m[2][2]*m[3][0]+
+ m[0][2]*m[1][1]*m[2][3]*m[3][0]-m[0][1]*m[1][2]*m[2][3]*m[3][0]+
+ m[0][3]*m[1][2]*m[2][1]*m[3][0]-m[0][2]*m[1][3]*m[2][1]*m[3][0];
+ */
+ return(result);
+}
+
+static
+int inv4Mat(const VP_MOTION* in, VP_MOTION* out)
+{
+ /* ==> This is a poor implementation of inversion. The determinant
+ method is O(N^4), i.e. unnecessarily slow, and not numerically accurate.
+ The real complexity of inversion is O(N^3), and is best done using
+ LU decomposition. */
+
+ MATRIX inmat,outmat;
+ int i, j, k, l, m, n,ntemp;
+ double mat[3][3], indet, temp;
+
+ /* check for non-empty structures structure */
+ if (((VP_MOTION *) NULL == in) || ((VP_MOTION *) NULL == out)) {
+ return 1;
+ }
+
+ for(k=0,i=0;i<4;i++)
+ for(j=0;j<4;j++,k++)
+ inmat[i][j]=(double)in->par[k];
+
+ indet = Det4(inmat);
+ if (indet==0) return(-1);
+
+ for (i=0;i<4;i++) {
+ for (j=0;j<4;j++) {
+ m = 0;
+ for (k=0;k<4;k++) {
+ if (i != k) {
+ n = 0;
+ for (l=0;l<4;l++)
+ if (j != l) {
+ mat[m][n] = inmat[k][l];
+ n++;
+ }
+ m++;
+ }
+ }
+
+ temp = -1.;
+ ntemp = (i +j ) %2;
+ if( ntemp == 0) temp = 1.;
+
+ outmat[j][i] = temp * Det3(mat)/indet;
+ }
+ }
+
+ for(k=0,i=0;i<4;i++)
+ for(j=0;j<4;j++,k++)
+ out->par[k]=(VP_PAR)outmat[i][j]; /*lint !e771*/
+
+ return(0);
+}
+
+/*
+* ===================================================================
+* Public Functions
+#htmlstart
+*/
+
+/*
+ * ===================================================================
+#fn vp_invert_motion
+#ft invert a motion
+#fd DEFINITION
+ Bool
+ vp_invert_motion(const VP_MOTION* in,VP_MOTION* out)
+#fd PURPOSE
+ This inverts the motion given in 'in'.
+ All motion models upto VP_MOTION_SEMI_PROJ_3D are supported.
+ It is assumed that the all 16 parameters are properly
+ initialized although you may not be using them. You could
+ use the VP_KEEP_ macro's defined in vp_motionmodel.h to set
+ the un-initialized parameters. This uses a 4x4 matrix invertion
+ function internally.
+ It is SAFE to pass the same pointer as both the 'in' and 'out'
+ parameters.
+#fd INPUTS
+ in - input motion
+#fd OUTPUTS
+ out - output inverted motion. If singular matrix uninitialized.
+ if MWW(in) is non-zero it is also normalized.
+#fd RETURNS
+ FALSE - matrix is singular or motion model not supported
+ TRUE - otherwise
+#fd SIDE EFFECTS
+ None
+#endfn
+*/
+
+int vp_invert_motion(const VP_MOTION* in,VP_MOTION* out)
+{
+ int refid;
+
+ /* check for non-empty structures structure */
+ if (((VP_MOTION *) NULL == in) || ((VP_MOTION *) NULL == out)) {
+ return FALSE;
+ }
+
+ if (in->type>VP_MOTION_SEMI_PROJ_3D) {
+ return FALSE;
+ }
+
+ if (inv4Mat(in,out)<0)
+ return FALSE;
+
+ /*VP_NORMALIZE(*out);*/
+ out->type = in->type;
+ refid=in->refid;
+ out->refid=in->insid;
+ out->insid=refid;
+ return TRUE;
+}
+
+/*
+* ===================================================================
+#fn vp_cascade_motion
+#ft Cascade two motion transforms
+#fd DEFINITION
+ Bool
+ vp_cascade_motion(const VP_MOTION* InAB,const VP_MOTION* InBC,VP_MOTION* OutAC)
+#fd PURPOSE
+ Given Motion Transforms A->B and B->C, this function will
+ generate a New Motion that describes the transformation
+ from A->C.
+ More specifically, OutAC = InBC * InAC.
+ This function works ok if InAB,InBC and OutAC are the same pointer.
+#fd INPUTS
+ InAB - First Motion Transform
+ InBC - Second Motion Tranform
+#fd OUTPUTS
+ OutAC - Cascaded Motion
+#fd RETURNS
+ FALSE - motion model not supported
+ TRUE - otherwise
+#fd SIDE EFFECTS
+ None
+#endfn
+*/
+
+int vp_cascade_motion(const VP_MOTION* InA, const VP_MOTION* InB,VP_MOTION* Out)
+{
+ /* ==> This is a poor implementation of matrix multiplication.
+ Writing the formula out in closed form is unnecessarily complicated
+ and mistakes are easy to make. */
+ VP_PAR mxx,mxy,mxz,mxw;
+ VP_PAR myx,myy,myz,myw;
+ VP_PAR mzx,mzy,mzz,mzw;
+ VP_PAR mwx,mwy,mwz,mww;
+
+ /* check for non-empty structures structure */
+ if (((VP_MOTION *) NULL == InA) || ((VP_MOTION *) NULL == InB) ||
+ ((VP_MOTION *) NULL == Out)) {
+ return FALSE;
+ }
+
+ if (InA->type>VP_MOTION_PROJ_3D) {
+ return FALSE;
+ }
+
+ if (InB->type>VP_MOTION_PROJ_3D) {
+ return FALSE;
+ }
+
+ mxx = MXX(*InB)*MXX(*InA)+MXY(*InB)*MYX(*InA)+MXZ(*InB)*MZX(*InA)+MXW(*InB)*MWX(*InA);
+ mxy = MXX(*InB)*MXY(*InA)+MXY(*InB)*MYY(*InA)+MXZ(*InB)*MZY(*InA)+MXW(*InB)*MWY(*InA);
+ mxz = MXX(*InB)*MXZ(*InA)+MXY(*InB)*MYZ(*InA)+MXZ(*InB)*MZZ(*InA)+MXW(*InB)*MWZ(*InA);
+ mxw = MXX(*InB)*MXW(*InA)+MXY(*InB)*MYW(*InA)+MXZ(*InB)*MZW(*InA)+MXW(*InB)*MWW(*InA);
+ myx = MYX(*InB)*MXX(*InA)+MYY(*InB)*MYX(*InA)+MYZ(*InB)*MZX(*InA)+MYW(*InB)*MWX(*InA);
+ myy = MYX(*InB)*MXY(*InA)+MYY(*InB)*MYY(*InA)+MYZ(*InB)*MZY(*InA)+MYW(*InB)*MWY(*InA);
+ myz = MYX(*InB)*MXZ(*InA)+MYY(*InB)*MYZ(*InA)+MYZ(*InB)*MZZ(*InA)+MYW(*InB)*MWZ(*InA);
+ myw = MYX(*InB)*MXW(*InA)+MYY(*InB)*MYW(*InA)+MYZ(*InB)*MZW(*InA)+MYW(*InB)*MWW(*InA);
+ mzx = MZX(*InB)*MXX(*InA)+MZY(*InB)*MYX(*InA)+MZZ(*InB)*MZX(*InA)+MZW(*InB)*MWX(*InA);
+ mzy = MZX(*InB)*MXY(*InA)+MZY(*InB)*MYY(*InA)+MZZ(*InB)*MZY(*InA)+MZW(*InB)*MWY(*InA);
+ mzz = MZX(*InB)*MXZ(*InA)+MZY(*InB)*MYZ(*InA)+MZZ(*InB)*MZZ(*InA)+MZW(*InB)*MWZ(*InA);
+ mzw = MZX(*InB)*MXW(*InA)+MZY(*InB)*MYW(*InA)+MZZ(*InB)*MZW(*InA)+MZW(*InB)*MWW(*InA);
+ mwx = MWX(*InB)*MXX(*InA)+MWY(*InB)*MYX(*InA)+MWZ(*InB)*MZX(*InA)+MWW(*InB)*MWX(*InA);
+ mwy = MWX(*InB)*MXY(*InA)+MWY(*InB)*MYY(*InA)+MWZ(*InB)*MZY(*InA)+MWW(*InB)*MWY(*InA);
+ mwz = MWX(*InB)*MXZ(*InA)+MWY(*InB)*MYZ(*InA)+MWZ(*InB)*MZZ(*InA)+MWW(*InB)*MWZ(*InA);
+ mww = MWX(*InB)*MXW(*InA)+MWY(*InB)*MYW(*InA)+MWZ(*InB)*MZW(*InA)+MWW(*InB)*MWW(*InA);
+
+ MXX(*Out)=mxx; MXY(*Out)=mxy; MXZ(*Out)=mxz; MXW(*Out)=mxw;
+ MYX(*Out)=myx; MYY(*Out)=myy; MYZ(*Out)=myz; MYW(*Out)=myw;
+ MZX(*Out)=mzx; MZY(*Out)=mzy; MZZ(*Out)=mzz; MZW(*Out)=mzw;
+ MWX(*Out)=mwx; MWY(*Out)=mwy; MWZ(*Out)=mwz; MWW(*Out)=mww;
+ /* VP_NORMALIZE(*Out); */
+ Out->type= (InA->type > InB->type) ? InA->type : InB->type;
+ Out->refid=InA->refid;
+ Out->insid=InB->insid;
+
+ return TRUE;
+}
+
+/*
+* ===================================================================
+#fn vp_copy_motion
+#ft Copies the source motion to the destination motion.
+#fd DEFINITION
+ void
+ vp_copy_motion (const VP_MOTION *src, VP_MOTION *dst)
+#fd PURPOSE
+ Copies the source motion to the destination motion.
+ It is OK if src == dst.
+ NOTE THAT THE SOURCE IS THE FIRST ARGUMENT.
+ This is different from some of the other VP
+ copy functions.
+#fd INPUTS
+ src is the source motion
+ dst is the destination motion
+#fd RETURNS
+ void
+#endfn
+*/
+void vp_copy_motion (const VP_MOTION *src, VP_MOTION *dst)
+{
+ /* Use memmove rather than memcpy because it handles overlapping memory
+ OK. */
+ memmove(dst, src, sizeof(VP_MOTION));
+ return;
+} /* vp_copy_motion() */
+
+#define VP_SQR(x) ( (x)*(x) )
+double vp_motion_cornerdiff(const VP_MOTION *mot_a, const VP_MOTION *mot_b,
+ int xo, int yo, int w, int h)
+{
+ double ax1, ay1, ax2, ay2, ax3, ay3, ax4, ay4;
+ double bx1, by1, bx2, by2, bx3, by3, bx4, by4;
+ double err;
+
+ /*lint -e639 -e632 -e633 */
+ VP_WARP_POINT_2D(xo, yo, *mot_a, ax1, ay1);
+ VP_WARP_POINT_2D(xo+w-1, yo, *mot_a, ax2, ay2);
+ VP_WARP_POINT_2D(xo+w-1, yo+h-1, *mot_a, ax3, ay3);
+ VP_WARP_POINT_2D(xo, yo+h-1, *mot_a, ax4, ay4);
+ VP_WARP_POINT_2D(xo, yo, *mot_b, bx1, by1);
+ VP_WARP_POINT_2D(xo+w-1, yo, *mot_b, bx2, by2);
+ VP_WARP_POINT_2D(xo+w-1, yo+h-1, *mot_b, bx3, by3);
+ VP_WARP_POINT_2D(xo, yo+h-1, *mot_b, bx4, by4);
+ /*lint +e639 +e632 +e633 */
+
+ err = 0;
+ err += (VP_SQR(ax1 - bx1) + VP_SQR(ay1 - by1));
+ err += (VP_SQR(ax2 - bx2) + VP_SQR(ay2 - by2));
+ err += (VP_SQR(ax3 - bx3) + VP_SQR(ay3 - by3));
+ err += (VP_SQR(ax4 - bx4) + VP_SQR(ay4 - by4));
+
+ return(sqrt(err));
+}
+
+int vp_zoom_motion2d(VP_MOTION* in, VP_MOTION* out,
+ int n, int w, int h, double zoom)
+{
+ int ii;
+ VP_PAR inv_zoom;
+ VP_PAR cx, cy;
+ VP_MOTION R2r,R2f;
+ VP_MOTION *res;
+
+ /* check for non-empty structures structure */
+ if (((VP_MOTION *) NULL == in)||(zoom <= 0.0)||(w <= 0)||(h <= 0)) {
+ return FALSE;
+ }
+
+ /* ==> Not sure why the special case of out=NULL is necessary. Why couldn't
+ the caller just pass the same pointer for both in and out? */
+ res = ((VP_MOTION *) NULL == out)?in:out;
+
+ cx = (VP_PAR) (w/2.0);
+ cy = (VP_PAR) (h/2.0);
+
+ VP_MOTION_ID(R2r);
+ inv_zoom = (VP_PAR)(1.0/zoom);
+ MXX(R2r) = inv_zoom;
+ MYY(R2r) = inv_zoom;
+ MXW(R2r)=cx*(((VP_PAR)1.0) - inv_zoom);
+ MYW(R2r)=cy*(((VP_PAR)1.0) - inv_zoom);
+
+ VP_KEEP_AFFINE_2D(R2r);
+
+ for(ii=0;ii<n;ii++) {
+ (void) vp_cascade_motion(&R2r,in+ii,&R2f);
+ res[ii]=R2f;
+ }
+
+ return TRUE;
+} /* vp_zoom_motion2d() */
+
+/* =================================================================== */
+/* end vp_motionmodel.c */
diff --git a/jni/feature_stab/src/dbreg/vp_motionmodel.h b/jni/feature_stab/src/dbreg/vp_motionmodel.h
new file mode 100644
index 000000000..a63ac0010
--- /dev/null
+++ b/jni/feature_stab/src/dbreg/vp_motionmodel.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/*
+#sourcefile vp_motionmodel.h
+#category warp
+#description general motion model for tranlation/affine/projective
+#title motion-model
+#parentlink hindex.html
+*
+* Copyright 1998 Sarnoff Corporation
+* All Rights Reserved
+*
+* Modification History
+* Date: 02/13/98
+* Author: supuns
+* Shop Order: 15491 001
+* @(#) $Id: vp_motionmodel.h,v 1.4 2011/06/17 14:04:33 mbansal Exp $
+*/
+
+#ifndef VP_MOTIONMODEL_H
+#define VP_MOTIONMODEL_H
+#include <stdio.h>
+
+#define FALSE 0
+#define TRUE 1
+
+#if 0 /* Moved mottomat.c and mattomot_d.c from vpmotion.h to vpcompat.h
+ in order to remove otherwise unnecessary dependency of vpmotion,
+ vpwarp, and newvpio on vpmath */
+#ifndef VPMATH_H
+#include "vpmath.h"
+#endif
+#endif
+
+#if 0
+#ifndef VP_WARP_H
+#include "vp_warp.h"
+#endif
+#endif
+/*
+
+#htmlstart
+# ===================================================================
+#h 1 Introduction
+
+ This defines a motion model that can describe translation,
+ affine, and projective projective 3d and 3d view transforms.
+
+ The main structure VP_MOTION contains a 16 parameter array (That
+ can be considered as elements of a 4x4 matrix) and a type field
+ which can be one of VP_MOTION_NONE,VP_MOTION_TRANSLATION,
+ VP_MOTION_AFFINE, VP_MOTION_PROJECTIVE,VP_MOTION_PROJ_3D or
+ VP_MOTION_VIEW_3D. (These are defined using enums with gaps of 10
+ so that subsets of these motions that are still consistant can be
+ added in between. Motion models that are inconsistant with this set
+ should be added at the end so the routines can hadle them
+ independently.
+
+ The transformation VP_MOTION_NONE,VP_MOTION_TRANSLATION,
+ VP_MOTION_AFFINE, VP_MOTION_PROJECTIVE, VP_MOTION_PROJ_3D and
+ VP_MOTION_SEMI_PROJ_3D would map a point P={x,y,z,w} to a new point
+ P'={x',y',z',w'} using a motion model M such that P'= M.par * P.
+ Where M.par is thought of as elements of a 4x4 matrix ordered row
+ by row. The interpretation of all models except VP_MOTION_SEMI_PROJ_3D
+ is taken to be mapping of a 3d point P"={x",y",z"} which is obtained
+ from the normalization {x'/w',y'/w',z'/w'}. In the VP_MOTION_SEMI_PROJ_3D
+ the mapping to a point P"={x",y",z"} is obtained from the normalization
+ {x'/w',y'/w',z'}. All these motion models have the property that they
+ can be inverted using 4x4 matrices. Except for the VP_MOTION_SEMI_PROJ_3D all
+ other types can also be cascaded using 4x4 matrices.
+
+ Specific macros and functions have been provided to handle 2d instances
+ of these functions. As the parameter interpretations can change when adding
+ new motion models it is HIGHLY RECOMMENDED that you use the macros MXX,MXY..
+ ect. to interpret each motion component.
+#pre
+*/
+
+/*
+#endpre
+# ===================================================================
+#h 1 Typedef and Struct Declarations
+#pre
+*/
+
+#define VP_MAX_MOTION_PAR 16
+
+typedef double VP_PAR;
+typedef VP_PAR VP_TRS[VP_MAX_MOTION_PAR];
+
+/* Do not add any motion models before VP_MOTION_PROJECTIVE */
+/* The order is assumed in vp functions */
+enum VP_MOTION_MODEL {
+ VP_MOTION_NONE=0,
+ VP_MOTION_TRANSLATION=10,
+ VP_MOTION_SCALE=11,
+ VP_MOTION_ROTATE=12,
+ VP_MOTION_X_SHEAR=13,
+ VP_MOTION_Y_SHEAR=14,
+ VP_MOTION_SIMILARITY=15,
+ VP_MOTION_AFFINE=20,
+ VP_MOTION_PROJECTIVE=30,
+ VP_MOTION_PROJ_3D=40,
+ VP_MOTION_SEMI_PROJ_3D=80,
+ VP_SIMILARITY=100,
+ VP_VFE_AFFINE=120
+};
+
+#define VP_REFID -1 /* Default ID used for reference frame */
+
+typedef struct {
+ VP_TRS par; /* Contains the motion paramerers.
+ For the standard motion types this is
+ represented as 16 number that refer
+ to a 4x4 matrix */
+ enum VP_MOTION_MODEL type;
+ int refid; /* Reference frame ( takes a point in refid frame
+ and moves it by the par to get a point in insid
+ frame ) */
+ int insid; /* Inspection frame */
+} VP_MOTION;
+
+//typedef VP_LIST VP_MOTION_LIST;
+/*
+#endpre
+# ===================================================================
+#h 1 Constant Declarations
+*/
+
+/* Macros related to the 4x4 matrix parameters */
+#define MXX(m) (m).par[0]
+#define MXY(m) (m).par[1]
+#define MXZ(m) (m).par[2]
+#define MXW(m) (m).par[3]
+#define MYX(m) (m).par[4]
+#define MYY(m) (m).par[5]
+#define MYZ(m) (m).par[6]
+#define MYW(m) (m).par[7]
+#define MZX(m) (m).par[8]
+#define MZY(m) (m).par[9]
+#define MZZ(m) (m).par[10]
+#define MZW(m) (m).par[11]
+#define MWX(m) (m).par[12]
+#define MWY(m) (m).par[13]
+#define MWZ(m) (m).par[14]
+#define MWW(m) (m).par[15]
+
+/* The do {...} while (0) technique creates a statement that can be used legally
+ in an if-else statement. See "Swallowing the semicolon",
+ http://gcc.gnu.org/onlinedocs/gcc-2.95.3/cpp_1.html#SEC23 */
+/* Initialize the Motion to be Identity */
+#define VP_MOTION_ID(m) do {\
+ MXX(m)=MYY(m)=MZZ(m)=MWW(m)=(VP_PAR)1.0; \
+ MXY(m)=MXZ(m)=MXW(m)=(VP_PAR)0.0; \
+ MYX(m)=MYZ(m)=MYW(m)=(VP_PAR)0.0; \
+ MZX(m)=MZY(m)=MZW(m)=(VP_PAR)0.0; \
+ MWX(m)=MWY(m)=MWZ(m)=(VP_PAR)0.0; \
+(m).type = VP_MOTION_TRANSLATION; } while (0)
+
+/* Initialize without altering the translation components */
+#define VP_KEEP_TRANSLATION_3D(m) do {\
+ MXX(m)=MYY(m)=MZZ(m)=MWW(m)=(VP_PAR)1.0; \
+ MXY(m)=MXZ(m)=(VP_PAR)0.0; \
+ MYX(m)=MYZ(m)=(VP_PAR)0.0; \
+ MZX(m)=MZY(m)=(VP_PAR)0.0; \
+ MWX(m)=MWY(m)=MWZ(m)=(VP_PAR)0.0; \
+ (m).type = VP_MOTION_PROJ_3D; } while (0)
+
+/* Initialize without altering the 2d translation components */
+#define VP_KEEP_TRANSLATION_2D(m) do {\
+ VP_KEEP_TRANSLATION_3D(m); MZW(m)=(VP_PAR)0.0; (m).type= VP_MOTION_TRANSLATION;} while (0)
+
+/* Initialize without altering the affine & translation components */
+#define VP_KEEP_AFFINE_3D(m) do {\
+ MWX(m)=MWY(m)=MWZ(m)=(VP_PAR)0.0; MWW(m)=(VP_PAR)1.0; \
+ (m).type = VP_MOTION_PROJ_3D; } while (0)
+
+/* Initialize without altering the 2d affine & translation components */
+#define VP_KEEP_AFFINE_2D(m) do {\
+ VP_KEEP_AFFINE_3D(m); \
+ MXZ(m)=MYZ(m)=(VP_PAR)0.0; MZZ(m)=(VP_PAR)1.0; \
+ MZX(m)=MZY(m)=MZW(m)=(VP_PAR)0.0; \
+ (m).type = VP_MOTION_AFFINE; } while (0)
+
+/* Initialize without altering the 2d projective parameters */
+#define VP_KEEP_PROJECTIVE_2D(m) do {\
+ MXZ(m)=MYZ(m)=(VP_PAR)0.0; MZZ(m)=(VP_PAR)1.0; \
+ MZX(m)=MZY(m)=MZW(m)=MWZ(m)=(VP_PAR)0.0; \
+ (m).type = VP_MOTION_PROJECTIVE; } while (0)
+
+/* Warp a 2d point (assuming the z component is zero) */
+#define VP_WARP_POINT_2D(inx,iny,m,outx,outy) do {\
+ VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWW(m); \
+ outx = (MXX(m)*((VP_PAR)inx)+MXY(m)*((VP_PAR)iny)+MXW(m))/vpTmpWarpPnt___; \
+ outy = (MYX(m)*((VP_PAR)inx)+MYY(m)*((VP_PAR)iny)+MYW(m))/vpTmpWarpPnt___; } while (0)
+
+/* Warp a 3d point */
+#define VP_WARP_POINT_3D(inx,iny,inz,m,outx,outy,outz) do {\
+ VP_PAR vpTmpWarpPnt___= MWX(m)*(inx)+MWY(m)*(iny)+MWZ(m)*((VP_PAR)inz)+MWW(m); \
+ outx = (MXX(m)*((VP_PAR)inx)+MXY(m)*((VP_PAR)iny)+MXZ(m)*((VP_PAR)inz)+MXW(m))/vpTmpWarpPnt___; \
+ outy = (MYX(m)*((VP_PAR)inx)+MYY(m)*((VP_PAR)iny)+MYZ(m)*((VP_PAR)inz)+MYW(m))/vpTmpWarpPnt___; \
+ outz = MZX(m)*((VP_PAR)inx)+MZY(m)*((VP_PAR)iny)+MZZ(m)*((VP_PAR)inz)+MZW(m); \
+ if ((m).type==VP_MOTION_PROJ_3D) outz/=vpTmpWarpPnt___; } while (0)
+
+/* Projections of each component */
+#define VP_PROJW_3D(m,x,y,z,f) ( MWX(m)*(x)+MWY(m)*(y)+MWZ(m)*(z)+MWW(m) )
+#define VP_PROJX_3D(m,x,y,z,f,w) ((MXX(m)*(x)+MXY(m)*(y)+MXZ(m)*(z)+MXW(m))/(w))
+#define VP_PROJY_3D(m,x,y,z,f,w) ((MYX(m)*(x)+MYY(m)*(y)+MYZ(m)*(z)+MYW(m))/(w))
+#define VP_PROJZ_3D(m,x,y,z,f,w) ((MZX(m)*(x)+MZY(m)*(y)+MZZ(m)*(z)+MZW(m))/(w))
+
+/* Scale Down a matrix by Sfactor */
+#define VP_SCALEDOWN(m,Sfactor) do { \
+ MXW(m) /= (VP_PAR)Sfactor; MWX(m) *= (VP_PAR)Sfactor; \
+ MYW(m) /= (VP_PAR)Sfactor; MWY(m) *= (VP_PAR)Sfactor; \
+ MZW(m) /= (VP_PAR)Sfactor; MWZ(m) *= (VP_PAR)Sfactor; } while (0)
+
+/* Scale Up a matrix by Sfactor */
+#define VP_SCALEUP(m,Sfactor) do { \
+ MXW(m) *= (VP_PAR)Sfactor; MWX(m) /= (VP_PAR)Sfactor; \
+ MYW(m) *= (VP_PAR)Sfactor; MWY(m) /= (VP_PAR)Sfactor; \
+ MZW(m) *= (VP_PAR)Sfactor; MWZ(m) /= (VP_PAR)Sfactor; } while (0)
+
+/* Normalize the transformation matrix so that MWW is 1 */
+#define VP_NORMALIZE(m) if (MWW(m)!=(VP_PAR)0.0) do { \
+ MXX(m)/=MWW(m); MXY(m)/=MWW(m); MXZ(m)/=MWW(m); MXW(m)/= MWW(m); \
+ MYX(m)/=MWW(m); MYY(m)/=MWW(m); MYZ(m)/=MWW(m); MYW(m)/= MWW(m); \
+ MZX(m)/=MWW(m); MZY(m)/=MWW(m); MZZ(m)/=MWW(m); MZW(m)/= MWW(m); \
+ MWX(m)/=MWW(m); MWY(m)/=MWW(m); MWZ(m)/=MWW(m); MWW(m) = (VP_PAR)1.0; } while (0)
+
+#define VP_PRINT_TRANS(msg,b) do { \
+ fprintf(stderr, \
+ "%s\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n%f %f %f %f\n", \
+ msg, \
+ MXX(b),MXY(b),MXZ(b),MXW(b), \
+ MYX(b),MYY(b),MYZ(b),MYW(b), \
+ MZX(b),MZY(b),MZZ(b),MZW(b), \
+ MWX(b),MWY(b),MWZ(b),MWW(b)); \
+} while (0)
+
+/* w' projection given a point x,y,0,f */
+#define VP_PROJZ(m,x,y,f) ( \
+ MWX(m)*((VP_PAR)x)+MWY(m)*((VP_PAR)y)+MWW(m)*((VP_PAR)f))
+
+/* X Projection given a point x,y,0,f and w' */
+#define VP_PROJX(m,x,y,w,f) (\
+ (MXX(m)*((VP_PAR)x)+MXY(m)*((VP_PAR)y)+MXW(m)*((VP_PAR)f))/((VP_PAR)w))
+
+/* Y Projection given a point x,y,0,f and the w' */
+#define VP_PROJY(m,x,y,w,f) (\
+ (MYX(m)*((VP_PAR)x)+MYY(m)*((VP_PAR)y)+MYW(m)*((VP_PAR)f))/((VP_PAR)w))
+
+/* Set the reference id for a motion */
+#define VP_SET_REFID(m,id) do { (m).refid=id; } while (0)
+
+/* Set the inspection id for a motion */
+#define VP_SET_INSID(m,id) do { (m).insid=id; } while (0)
+
+void vp_copy_motion (const VP_MOTION *src, VP_MOTION *dst);
+int vp_invert_motion(const VP_MOTION* in,VP_MOTION* out);
+int vp_cascade_motion(const VP_MOTION* InAB, const VP_MOTION* InBC,VP_MOTION* OutAC);
+int vp_zoom_motion2d(VP_MOTION* in, VP_MOTION* out,
+ int n, int w, int h, double zoom);
+double vp_motion_cornerdiff(const VP_MOTION *mot_a, const VP_MOTION *mot_b,
+ int xo, int yo, int w, int h);
+
+#endif /* VP_MOTIONMODEL_H */
+/* =================================================================== */
+/* end vp_motionmodel.h */
diff --git a/jni/feature_stab/src/dbregtest/PgmImage.cpp b/jni/feature_stab/src/dbregtest/PgmImage.cpp
new file mode 100644
index 000000000..0891cfda6
--- /dev/null
+++ b/jni/feature_stab/src/dbregtest/PgmImage.cpp
@@ -0,0 +1,260 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include "PgmImage.h"
+#include <cassert>
+
+using namespace std;
+
+PgmImage::PgmImage(std::string filename) :
+m_w(0),m_h(0),m_colors(255),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
+{
+ if ( !ReadPGM(filename) )
+ return;
+}
+
+PgmImage::PgmImage(int w, int h, int format) :
+m_colors(255),m_w(w),m_h(h),m_format(format),m_over_allocation(256)
+{
+ SetFormat(format);
+}
+
+PgmImage::PgmImage(unsigned char *data, int w, int h) :
+m_colors(255),m_w(w),m_h(h),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
+{
+ SetData(data);
+}
+
+PgmImage::PgmImage(std::vector<unsigned char> &data, int w, int h) :
+m_colors(255),m_w(w),m_h(h),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
+{
+ if ( data.size() == w*h )
+ SetData(&data[0]);
+ else
+ //throw (std::exception("Size of data is not w*h."));
+ throw (std::exception());
+}
+
+PgmImage::PgmImage(const PgmImage &im) :
+m_colors(255),m_w(0),m_h(0),m_format(PGM_BINARY_GRAYMAP),m_over_allocation(256)
+{
+ DeepCopy(im, *this);
+}
+
+PgmImage& PgmImage::operator= (const PgmImage &im)
+{
+ if (this == &im) return *this;
+ DeepCopy(im, *this);
+ return *this;
+}
+
+void PgmImage::DeepCopy(const PgmImage& src, PgmImage& dst)
+{
+ dst.m_data = src.m_data;
+
+ // PGM data
+ dst.m_w = src.m_w;
+ dst.m_h = src.m_h;
+ dst.m_format = src.m_format;
+ dst.m_colors = src.m_colors;
+
+ dst.m_comment = src.m_comment;
+ SetupRowPointers();
+}
+
+PgmImage::~PgmImage()
+{
+
+}
+
+void PgmImage::SetFormat(int format)
+{
+ m_format = format;
+
+ switch (format)
+ {
+ case PGM_BINARY_GRAYMAP:
+ m_data.resize(m_w*m_h+m_over_allocation);
+ break;
+ case PGM_BINARY_PIXMAP:
+ m_data.resize(m_w*m_h*3+m_over_allocation);
+ break;
+ default:
+ return;
+ break;
+ }
+ SetupRowPointers();
+}
+
+void PgmImage::SetData(const unsigned char * data)
+{
+ m_data.resize(m_w*m_h+m_over_allocation);
+ memcpy(&m_data[0],data,m_w*m_h);
+ SetupRowPointers();
+}
+
+bool PgmImage::ReadPGM(const std::string filename)
+{
+ ifstream in(filename.c_str(),std::ios::in | std::ios::binary);
+ if ( !in.is_open() )
+ return false;
+
+ // read the header:
+ string format_header,size_header,colors_header;
+
+ getline(in,format_header);
+ stringstream s;
+ s << format_header;
+
+ s >> format_header >> m_w >> m_h >> m_colors;
+ s.clear();
+
+ if ( m_w == 0 )
+ {
+ while ( in.peek() == '#' )
+ getline(in,m_comment);
+
+ getline(in,size_header);
+
+ while ( in.peek() == '#' )
+ getline(in,m_comment);
+
+ m_colors = 0;
+
+ // parse header
+ s << size_header;
+ s >> m_w >> m_h >> m_colors;
+ s.clear();
+
+ if ( m_colors == 0 )
+ {
+ getline(in,colors_header);
+ s << colors_header;
+ s >> m_colors;
+ }
+ }
+
+ if ( format_header == "P5" )
+ m_format = PGM_BINARY_GRAYMAP;
+ else if (format_header == "P6" )
+ m_format = PGM_BINARY_PIXMAP;
+ else
+ m_format = PGM_FORMAT_INVALID;
+
+ switch(m_format)
+ {
+ case(PGM_BINARY_GRAYMAP):
+ m_data.resize(m_w*m_h+m_over_allocation);
+ in.read((char *)(&m_data[0]),m_data.size());
+ break;
+ case(PGM_BINARY_PIXMAP):
+ m_data.resize(m_w*m_h*3+m_over_allocation);
+ in.read((char *)(&m_data[0]),m_data.size());
+ break;
+ default:
+ return false;
+ break;
+ }
+ in.close();
+
+ SetupRowPointers();
+
+ return true;
+}
+
+bool PgmImage::WritePGM(const std::string filename, const std::string comment)
+{
+ string format_header;
+
+ switch(m_format)
+ {
+ case PGM_BINARY_GRAYMAP:
+ format_header = "P5\n";
+ break;
+ case PGM_BINARY_PIXMAP:
+ format_header = "P6\n";
+ break;
+ default:
+ return false;
+ break;
+ }
+
+ ofstream out(filename.c_str(),std::ios::out |ios::binary);
+ out << format_header << "# " << comment << '\n' << m_w << " " << m_h << '\n' << m_colors << '\n';
+
+ out.write((char *)(&m_data[0]), m_data.size());
+
+ out.close();
+
+ return true;
+}
+
+void PgmImage::SetupRowPointers()
+{
+ int i;
+ m_rows.resize(m_h);
+
+ switch (m_format)
+ {
+ case PGM_BINARY_GRAYMAP:
+ for(i=0;i<m_h;i++)
+ {
+ m_rows[i]=&m_data[m_w*i];
+ }
+ break;
+ case PGM_BINARY_PIXMAP:
+ for(i=0;i<m_h;i++)
+ {
+ m_rows[i]=&m_data[(m_w*3)*i];
+ }
+ break;
+ }
+}
+
+void PgmImage::ConvertToGray()
+{
+ if ( m_format != PGM_BINARY_PIXMAP ) return;
+
+ // Y = 0.3*R + 0.59*G + 0.11*B;
+ for ( int i = 0; i < m_w*m_h; ++i )
+ m_data[i] = (unsigned char)(0.3*m_data[3*i]+0.59*m_data[3*i+1]+0.11*m_data[3*i+2]);
+
+ m_data.resize(m_w*m_h+m_over_allocation);
+ m_format = PGM_BINARY_GRAYMAP;
+
+ SetupRowPointers();
+}
+
+std::ostream& operator<< (std::ostream& o, const PgmImage& im)
+{
+ o << "PGM Image Info:\n";
+ o << "Size: " << im.m_w << " x " << im.m_h << "\n";
+ o << "Comment: " << im.m_comment << "\n";
+ switch (im.m_format)
+ {
+ case PgmImage::PGM_BINARY_PIXMAP:
+ o << "Format: RGB binary pixmap";
+ break;
+ case PgmImage::PGM_BINARY_GRAYMAP:
+ o << "Format: PPM binary graymap";
+ break;
+ default:
+ o << "Format: Invalid";
+ break;
+ }
+ o << endl;
+ return o;
+}
diff --git a/jni/feature_stab/src/dbregtest/PgmImage.h b/jni/feature_stab/src/dbregtest/PgmImage.h
new file mode 100644
index 000000000..d4d1eebed
--- /dev/null
+++ b/jni/feature_stab/src/dbregtest/PgmImage.h
@@ -0,0 +1,95 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+#include <vector>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+#include <memory.h>
+
+/*!
+ * Simple class to manipulate PGM/PPM images. Not suitable for heavy lifting.
+ */
+class PgmImage
+{
+ friend std::ostream& operator<< (std::ostream& o, const PgmImage& im);
+public:
+ enum {PGM_BINARY_GRAYMAP,PGM_BINARY_PIXMAP,PGM_FORMAT_INVALID};
+ /*!
+ * Constructor from a PGM file name.
+ */
+ PgmImage(std::string filename);
+ /*!
+ * Constructor to allocate an image of given size and type.
+ */
+ PgmImage(int w, int h, int format = PGM_BINARY_GRAYMAP);
+ /*!
+ * Constructor to allocate an image of given size and copy the data in.
+ */
+ PgmImage(unsigned char *data, int w, int h);
+ /*!
+ * Constructor to allocate an image of given size and copy the data in.
+ */
+ PgmImage(std::vector<unsigned char> &data, int w, int h);
+
+ PgmImage(const PgmImage &im);
+
+ PgmImage& operator= (const PgmImage &im);
+ ~PgmImage();
+
+ int GetHeight() const { return m_h; }
+ int GetWidth() const { return m_w; }
+
+ //! Copy pixels from data pointer
+ void SetData(const unsigned char * data);
+
+ //! Get a data pointer to unaligned memory area
+ unsigned char * GetDataPointer() { if ( m_data.size() > 0 ) return &m_data[0]; else return NULL; }
+ unsigned char ** GetRowPointers() { if ( m_rows.size() == m_h ) return &m_rows[0]; else return NULL; }
+
+ //! Read a PGM file from disk
+ bool ReadPGM(const std::string filename);
+ //! Write a PGM file to disk
+ bool WritePGM(const std::string filename, const std::string comment="");
+
+ //! Get image format (returns PGM_BINARY_GRAYMAP, PGM_BINARY_PIXMAP or PGM_FORMAT_INVALID)
+ int GetFormat() const { return m_format; }
+
+ //! Set image format (returns PGM_BINARY_GRAYMAP, PGM_BINARY_PIXMAP). Image data becomes invalid.
+ void SetFormat(int format);
+
+ //! If the image is PGM_BINARY_PIXMAP, convert it to PGM_BINARY_GRAYMAP via Y = 0.3*R + 0.59*G + 0.11*B.
+ void ConvertToGray();
+protected:
+ // Generic functions:
+ void DeepCopy(const PgmImage& src, PgmImage& dst);
+ void SetupRowPointers();
+
+ // PGM data
+ int m_w;
+ int m_h;
+ int m_format;
+ int m_colors;
+ int m_over_allocation;
+ std::vector<unsigned char> m_data;
+ std::string m_comment;
+
+ std::vector<unsigned char *> m_rows;
+};
+
+std::ostream& operator<< (std::ostream& o, const PgmImage& im);
diff --git a/jni/feature_stab/src/dbregtest/dbregtest.cpp b/jni/feature_stab/src/dbregtest/dbregtest.cpp
new file mode 100644
index 000000000..508736218
--- /dev/null
+++ b/jni/feature_stab/src/dbregtest/dbregtest.cpp
@@ -0,0 +1,399 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// $Id: dbregtest.cpp,v 1.24 2011/06/17 14:04:33 mbansal Exp $
+#include "stdafx.h"
+#include "PgmImage.h"
+#include "../dbreg/dbreg.h"
+#include "../dbreg/dbstabsmooth.h"
+#include <db_utilities_camera.h>
+
+#include <iostream>
+#include <iomanip>
+
+#if PROFILE
+ #include <sys/time.h>
+#endif
+
+
+using namespace std;
+
+const int DEFAULT_NR_CORNERS=500;
+const double DEFAULT_MAX_DISPARITY=0.2;
+const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_AFFINE;
+//const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_R_T;
+//const int DEFAULT_MOTION_MODEL=DB_HOMOGRAPHY_TYPE_TRANSLATION;
+const bool DEFAULT_QUARTER_RESOLUTION=false;
+const unsigned int DEFAULT_REFERENCE_UPDATE_PERIOD=3;
+const bool DEFAULT_DO_MOTION_SMOOTHING = false;
+const double DEFAULT_MOTION_SMOOTHING_GAIN = 0.75;
+const bool DEFAULT_LINEAR_POLISH = false;
+const int DEFAULT_MAX_ITERATIONS = 10;
+
+void usage(string name) {
+
+ const char *helpmsg[] = {
+ "Function: point-based frame to reference registration.",
+ " -m [rt,a,p] : motion model, rt = rotation+translation, a = affine (default = affine).",
+ " -c <int> : number of corners (default 1000).",
+ " -d <double>: search disparity as portion of image size (default 0.1).",
+ " -q : quarter the image resolution (i.e. half of each dimension) (default on)",
+ " -r <int> : the period (in nr of frames) for reference frame updates (default = 5)",
+ " -s <0/1> : motion smoothing (1 activates motion smoothing, 0 turns it off - default value = 1)",
+ " -g <double>: motion smoothing gain, only used if smoothing is on (default value =0.75)",
+ NULL
+ };
+
+ cerr << "Usage: " << name << " [options] image_list.txt" << endl;
+
+ const char **p = helpmsg;
+
+ while (*p)
+ {
+ cerr << *p++ << endl;
+ }
+}
+
+void parse_cmd_line(stringstream& cmdline,
+ const int argc,
+ const string& progname,
+ string& image_list_file_name,
+ int& nr_corners,
+ double& max_disparity,
+ int& motion_model_type,
+ bool& quarter_resolution,
+ unsigned int& reference_update_period,
+ bool& do_motion_smoothing,
+ double& motion_smoothing_gain
+ );
+
+int main(int argc, char* argv[])
+{
+ int nr_corners = DEFAULT_NR_CORNERS;
+ double max_disparity = DEFAULT_MAX_DISPARITY;
+ int motion_model_type = DEFAULT_MOTION_MODEL;
+ bool quarter_resolution = DEFAULT_QUARTER_RESOLUTION;
+
+ unsigned int reference_update_period = DEFAULT_REFERENCE_UPDATE_PERIOD;
+
+ bool do_motion_smoothing = DEFAULT_DO_MOTION_SMOOTHING;
+ double motion_smoothing_gain = DEFAULT_MOTION_SMOOTHING_GAIN;
+ const bool DEFAULT_USE_SMALLER_MATCHING_WINDOW = true;
+
+ int default_nr_samples = DB_DEFAULT_NR_SAMPLES/5;
+
+ bool use_smaller_matching_window = DEFAULT_USE_SMALLER_MATCHING_WINDOW;
+
+
+ bool linear_polish = DEFAULT_LINEAR_POLISH;
+
+ if (argc < 2) {
+ usage(argv[0]);
+ exit(1);
+ }
+
+ stringstream cmdline;
+ string progname(argv[0]);
+ string image_list_file_name;
+
+#if PROFILE
+ timeval ts1, ts2, ts3, ts4;
+#endif
+
+ // put the options and image list file name into the cmdline stringstream
+ for (int c = 1; c < argc; c++)
+ {
+ cmdline << argv[c] << " ";
+ }
+
+ parse_cmd_line(cmdline, argc, progname, image_list_file_name, nr_corners, max_disparity, motion_model_type,quarter_resolution,reference_update_period,do_motion_smoothing,motion_smoothing_gain);
+
+ ifstream in(image_list_file_name.c_str(),ios::in);
+
+ if ( !in.is_open() )
+ {
+ cerr << "Could not open file " << image_list_file_name << ". Exiting" << endl;
+
+ return false;
+ }
+
+ // feature-based image registration class:
+ db_FrameToReferenceRegistration reg;
+// db_StabilizationSmoother stab_smoother;
+
+ // input file name:
+ string file_name;
+
+ // look-up tables for image warping:
+ float ** lut_x = NULL, **lut_y = NULL;
+
+ // if the images are color, the input is saved in color_ref:
+ PgmImage color_ref(0,0);
+
+ // image width, height:
+ int w,h;
+
+ int frame_number = 0;
+
+ while ( !in.eof() )
+ {
+ getline(in,file_name);
+
+ PgmImage ref(file_name);
+
+ if ( ref.GetDataPointer() == NULL )
+ {
+ cerr << "Could not open image" << file_name << ". Exiting." << endl;
+ return -1;
+ }
+
+ cout << ref << endl;
+
+ // color format:
+ int format = ref.GetFormat();
+
+ // is the input image color?:
+ bool color = format == PgmImage::PGM_BINARY_PIXMAP;
+
+ w = ref.GetWidth();
+ h = ref.GetHeight();
+
+ if ( !reg.Initialized() )
+ {
+ reg.Init(w,h,motion_model_type,DEFAULT_MAX_ITERATIONS,linear_polish,quarter_resolution,DB_POINT_STANDARDDEV,reference_update_period,do_motion_smoothing,motion_smoothing_gain,default_nr_samples,DB_DEFAULT_CHUNK_SIZE,nr_corners,max_disparity,use_smaller_matching_window);
+ lut_x = db_AllocImage_f(w,h);
+ lut_y = db_AllocImage_f(w,h);
+
+ }
+
+ if ( color )
+ {
+ // save the color image:
+ color_ref = ref;
+ }
+
+ // make a grayscale image:
+ ref.ConvertToGray();
+
+ // compute the homography:
+ double H[9],Hinv[9];
+ db_Identity3x3(Hinv);
+ db_Identity3x3(H);
+
+ bool force_reference = false;
+
+#if PROFILE
+ gettimeofday(&ts1, NULL);
+#endif
+
+ reg.AddFrame(ref.GetRowPointers(),H,false,false);
+ cout << reg.profile_string << std::endl;
+
+#if PROFILE
+ gettimeofday(&ts2, NULL);
+
+ double elapsedTime = (ts2.tv_sec - ts1.tv_sec)*1000.0; // sec to ms
+ elapsedTime += (ts2.tv_usec - ts1.tv_usec)/1000.0; // us to ms
+ cout <<"\nelapsedTime for Reg<< "<<elapsedTime<<" ms >>>>>>>>>>>>>\n";
+#endif
+
+ if (frame_number == 0)
+ {
+ reg.UpdateReference(ref.GetRowPointers());
+ }
+
+
+ //std::vector<int> &inlier_indices = reg.GetInliers();
+ int *inlier_indices = reg.GetInliers();
+ int num_inlier_indices = reg.GetNrInliers();
+ printf("[%d] #Inliers = %d\n",frame_number,num_inlier_indices);
+
+ reg.Get_H_dref_to_ins(H);
+
+ db_GenerateHomographyLut(lut_x,lut_y,w,h,H);
+
+ // create a new image and warp:
+ PgmImage warped(w,h,format);
+
+#if PROFILE
+ gettimeofday(&ts3, NULL);
+#endif
+
+ if ( color )
+ db_WarpImageLutBilinear_rgb(color_ref.GetRowPointers(),warped.GetRowPointers(),w,h,lut_x,lut_y);
+ else
+ db_WarpImageLut_u(ref.GetRowPointers(),warped.GetRowPointers(),w,h,lut_x,lut_y,DB_WARP_FAST);
+
+#if PROFILE
+ gettimeofday(&ts4, NULL);
+ elapsedTime = (ts4.tv_sec - ts3.tv_sec)*1000.0; // sec to ms
+ elapsedTime += (ts4.tv_usec - ts3.tv_usec)/1000.0; // us to ms
+ cout <<"\nelapsedTime for Warp <<"<<elapsedTime<<" ms >>>>>>>>>>>>>\n";
+#endif
+
+ // write aligned image: name is aligned_<corresponding input file name>
+ stringstream s;
+ s << "aligned_" << file_name;
+ warped.WritePGM(s.str());
+
+ /*
+ // Get the reference and inspection corners to write to file
+ double *ref_corners = reg.GetRefCorners();
+ double *ins_corners = reg.GetInsCorners();
+
+ // get the image file name (without extension), so we
+ // can generate the corresponding filenames for matches
+ // and inliers
+ string file_name_root(file_name.substr(0,file_name.rfind(".")));
+
+ // write matches to file
+ s.str(string(""));
+ s << "Matches_" << file_name_root << ".txt";
+
+ ofstream match_file(s.str().c_str());
+
+ for (int i = 0; i < reg.GetNrMatches(); i++)
+ {
+ match_file << ref_corners[3*i] << " " << ref_corners[3*i+1] << " " << ins_corners[3*i] << " " << ins_corners[3*i+1] << endl;
+ }
+
+ match_file.close();
+
+ // write the inlier matches to file
+ s.str(string(""));
+ s << "InlierMatches_" << file_name_root << ".txt";
+
+ ofstream inlier_match_file(s.str().c_str());
+
+ for(int i=0; i<num_inlier_indices; i++)
+ {
+ int k = inlier_indices[i];
+ inlier_match_file << ref_corners[3*k] << " "
+ << ref_corners[3*k+1] << " "
+ << ins_corners[3*k] << " "
+ << ins_corners[3*k+1] << endl;
+ }
+ inlier_match_file.close();
+ */
+
+ frame_number++;
+ }
+
+ if ( reg.Initialized() )
+ {
+ db_FreeImage_f(lut_x,h);
+ db_FreeImage_f(lut_y,h);
+ }
+
+ return 0;
+}
+
+void parse_cmd_line(stringstream& cmdline,
+ const int argc,
+ const string& progname,
+ string& image_list_file_name,
+ int& nr_corners,
+ double& max_disparity,
+ int& motion_model_type,
+ bool& quarter_resolution,
+ unsigned int& reference_update_period,
+ bool& do_motion_smoothing,
+ double& motion_smoothing_gain)
+{
+ // for counting down the parsed arguments.
+ int c = argc;
+
+ // a holder
+ string token;
+
+ while (cmdline >> token)
+ {
+ --c;
+
+ int pos = token.find("-");
+
+ if (pos == 0)
+ {
+ switch (token[1])
+ {
+ case 'm':
+ --c; cmdline >> token;
+ if (token.compare("rt") == 0)
+ {
+ motion_model_type = DB_HOMOGRAPHY_TYPE_R_T;
+ }
+ else if (token.compare("a") == 0)
+ {
+ motion_model_type = DB_HOMOGRAPHY_TYPE_AFFINE;
+ }
+ else if (token.compare("p") == 0)
+ {
+ motion_model_type = DB_HOMOGRAPHY_TYPE_PROJECTIVE;
+ }
+ else
+ {
+ usage(progname);
+ exit(1);
+ }
+ break;
+ case 'c':
+ --c; cmdline >> nr_corners;
+ break;
+ case 'd':
+ --c; cmdline >> max_disparity;
+ break;
+ case 'q':
+ quarter_resolution = true;
+ break;
+ case 'r':
+ --c; cmdline >> reference_update_period;
+ break;
+ case 's':
+ --c; cmdline >> do_motion_smoothing;
+ break;
+ case 'g':
+ --c; cmdline >> motion_smoothing_gain;
+ break;
+ default:
+ cerr << progname << "illegal option " << token << endl;
+ case 'h':
+ usage(progname);
+ exit(1);
+ break;
+ }
+ }
+ else
+ {
+ if (c != 1)
+ {
+ usage(progname);
+ exit(1);
+ }
+ else
+ {
+ --c;
+ image_list_file_name = token;
+ }
+ }
+ }
+
+ if (c != 0)
+ {
+ usage(progname);
+ exit(1);
+ }
+}
+
diff --git a/jni/feature_stab/src/dbregtest/stdafx.cpp b/jni/feature_stab/src/dbregtest/stdafx.cpp
new file mode 100644
index 000000000..0c703e2dc
--- /dev/null
+++ b/jni/feature_stab/src/dbregtest/stdafx.cpp
@@ -0,0 +1,24 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// stdafx.cpp : source file that includes just the standard includes
+// dbregtest.pch will be the pre-compiled header
+// stdafx.obj will contain the pre-compiled type information
+
+#include "stdafx.h"
+
+// TODO: reference any additional headers you need in STDAFX.H
+// and not in this file
diff --git a/jni/feature_stab/src/dbregtest/stdafx.h b/jni/feature_stab/src/dbregtest/stdafx.h
new file mode 100644
index 000000000..9bc06ea04
--- /dev/null
+++ b/jni/feature_stab/src/dbregtest/stdafx.h
@@ -0,0 +1,28 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+// stdafx.h : include file for standard system include files,
+// or project specific include files that are used frequently, but
+// are changed infrequently
+//
+
+#pragma once
+
+#include "targetver.h"
+
+#include <stdio.h>
+
+// TODO: reference additional headers your program requires here
diff --git a/jni/feature_stab/src/dbregtest/targetver.h b/jni/feature_stab/src/dbregtest/targetver.h
new file mode 100644
index 000000000..9272b0d6e
--- /dev/null
+++ b/jni/feature_stab/src/dbregtest/targetver.h
@@ -0,0 +1,29 @@
+/*
+ * Copyright (C) 2011 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#pragma once
+
+// The following macros define the minimum required platform. The minimum required platform
+// is the earliest version of Windows, Internet Explorer etc. that has the necessary features to run
+// your application. The macros work by enabling all features available on platform versions up to and
+// including the version specified.
+
+// Modify the following defines if you have to target a platform prior to the ones specified below.
+// Refer to MSDN for the latest info on corresponding values for different platforms.
+#ifndef _WIN32_WINNT // Specifies that the minimum required platform is Windows Vista.
+#define _WIN32_WINNT 0x0600 // Change this to the appropriate value to target other versions of Windows.
+#endif
+