SLAMflex SE  0.1.0
SLAMflex provides detection and tracking of dominant planes for smartphone devices. This plane can then be used to show AR content relative to the plane orientation. The detection of plane is performed in the field of view of the smartphone camera. In subsequent frames it is tracked. The interface returns the plane position and orientation.
PatchFinder.cpp
Go to the documentation of this file.
1 // Copyright 2008 Isis Innovation Limited
2 #include "PatchFinder.h"
3 #include "SmallMatrixOpts.h"
4 #include "KeyFrame.h"
5 
6 #include "vision.h"
7 #include "vector_image_ref.h"
8 #include "image_interpolate.h"
9 #include "Cholesky.h"
10 // tmmintrin.h contains SSE3<> instrinsics, used for the ZMSSD search at the bottom..
11 // If this causes problems, just do #define CVD_HAVE_XMMINTRIN 0
12 #if CVD_HAVE_XMMINTRIN
13 #include <tmmintrin.h>
14 #endif
15 
16 using namespace CVD;
17 using namespace std;
18 
19 PatchFinder::PatchFinder(int nPatchSize)
20  : mimTemplate(ImageRef(nPatchSize,nPatchSize))
21 {
22  mnPatchSize = nPatchSize;
23  mirCenter = ImageRef(nPatchSize/2, nPatchSize/2);
24  int nMaxSSDPerPixel = 500; // Pretty arbitrary... could make a GVar out of this.
26  // Populate the speed-up caches with bogus values:
27  mm2LastWarpMatrix = 9999.9 * Identity;
29 };
30 
31 
32 // Find the warping matrix and search level
34  SE3<> se3CFromW,
35  Matrix<2> &m2CamDerivs)
36 {
37  // Calc point pos in new view camera frame
38  // Slightly dumb that we re-calculate this here when the tracker's already done this!
39  Vector<3> v3Cam = se3CFromW * p.v3WorldPos;
40  double dOneOverCameraZ = 1.0 / v3Cam[2];
41  // Project the source keyframe's one-pixel-right and one-pixel-down vectors into the current view
42  Vector<3> v3MotionRight = se3CFromW.get_rotation() * p.v3PixelRight_W;
43  Vector<3> v3MotionDown = se3CFromW.get_rotation() * p.v3PixelDown_W;
44  // Calculate in-image derivatives of source image pixel motions:
45  mm2WarpInverse.T()[0] = m2CamDerivs * (v3MotionRight.slice<0,2>() - v3Cam.slice<0,2>() * v3MotionRight[2] * dOneOverCameraZ) * dOneOverCameraZ;
46  mm2WarpInverse.T()[1] = m2CamDerivs * (v3MotionDown.slice<0,2>() - v3Cam.slice<0,2>() * v3MotionDown[2] * dOneOverCameraZ) * dOneOverCameraZ;
47  double dDet = mm2WarpInverse[0][0] * mm2WarpInverse[1][1] - mm2WarpInverse[0][1] * mm2WarpInverse[1][0];
48  mnSearchLevel = 0;
49 
50  // This warp matrix is likely not appropriate for finding at level zero, which is
51  // the level at which it has been calculated. Vary the search level until the
52  // at that level would be appropriate (does not actually modify the matrix.)
53  while(dDet > 3 && mnSearchLevel < LEVELS-1)
54  {
55  mnSearchLevel++;
56  dDet *= 0.25;
57  };
58 
59  // Some warps are inappropriate, e.g. too near the camera, too far, or reflected,
60  // or zero area.. reject these!
61  if(dDet > 3 || dDet < 0.25)
62  {
63  mbTemplateBad = true;
64  return -1;
65  }
66  else
67  return mnSearchLevel;
68 }
69 
70 // This is just a convenience function wich caluclates the warp matrix and generates
71 // the template all in one call.
73  SE3<> se3CFromW,
74  Matrix<2> &m2CamDerivs)
75 {
76  CalcSearchLevelAndWarpMatrix(p, se3CFromW, m2CamDerivs);
78 };
79 
80 // This function generates the warped search template.
82 {
83  // Get the warping matrix appropriate for use with CVD::transform...
85  // m2 now represents the number of pixels in the source image for one
86  // pixel of template image
87 
88  // Optimisation: Don't re-gen the coarse template if it's going to be substantially the
89  // same as was made last time. This saves time when the camera is not moving. For this,
90  // check that (a) this patchfinder is still working on the same map point and (b) the
91  // warping matrix has not changed much.
92 
93  bool bNeedToRefreshTemplate = false;
94  if(&p != mpLastTemplateMapPoint)
95  bNeedToRefreshTemplate = true;
96  // Still the same map point? Then compare warping matrix..
97  for(int i=0; !bNeedToRefreshTemplate && i<2; i++)
98  {
99  Vector<2> v2Diff = m2.T()[i] - mm2LastWarpMatrix.T()[i];
100  const double dRefreshLimit = 0.07; // Sort of works out as half a pixel displacement in src img
101  if(v2Diff * v2Diff > dRefreshLimit * dRefreshLimit)
102  bNeedToRefreshTemplate = true;
103  }
104 
105  // Need to regen template? Then go ahead.
106  if(bNeedToRefreshTemplate)
107  {
108  int nOutside; // Use CVD::transform to warp the patch according the the warping matrix m2
109  // This returns the number of pixels outside the source image hit, which should be zero.
111  mimTemplate,
112  m2,
113  vec(p.irCenter),
114  vec(mirCenter));
115 
116  if(nOutside)
117  mbTemplateBad = true;
118  else
119  mbTemplateBad = false;
120 
122 
123  // Store the parameters which allow us to determine if we need to re-calculate
124  // the patch next time round.
126  mm2LastWarpMatrix = m2;
127  }
128 };
129 
130 // This makes a template without warping. Used for epipolar search, where we don't really know
131 // what the warping matrix should be. (Although to be fair, I should do rotation for epipolar,
132 // which we could approximate without knowing patch depth!)
134 {
135  mnSearchLevel = nLevel;
136  Image<byte> &im = k.aLevels[nLevel].im;
137  if(!im.in_image_with_border(irLevelPos, mnPatchSize / 2 + 1))
138  {
139  mbTemplateBad = true;
140  return;
141  }
142  mbTemplateBad = false;
143  copy(im,
144  mimTemplate,
145  mimTemplate.size(),
146  irLevelPos - mirCenter);
147 
149 }
150 
151 // Convenient wrapper for the above
153 {
155 };
156 
157 // Finds the sum, and sum-squared, of template pixels. These sums are used
158 // to calculate the ZMSSD.
160 {
161  int nSum = 0;
162  int nSumSq = 0;
163  ImageRef ir;
164  do
165  {
166  int b = mimTemplate[ir];
167  nSum += b;
168  nSumSq +=b * b;
169  }
170  while(ir.next(mimTemplate.size()));
171  mnTemplateSum = nSum;
172  mnTemplateSumSq = nSumSq;
173 }
174 
175 // One of the main functions of the class! Looks at the appropriate level of
176 // the target keyframe to try and find the template. Looks only at FAST corner points
177 // which are within radius nRange of the center. (Params are supplied in Level0
178 // coords.) Returns true on patch found.
179 bool PatchFinder::FindPatchCoarse(ImageRef irPos, KeyFrame &kf, unsigned int nRange)
180 {
181  mbFound = false;
182 
183  // Convert from L0 coords to search level quantities
184  int nLevelScale = LevelScale(mnSearchLevel);
185  mirPredictedPos = irPos;
186  irPos = irPos / nLevelScale;
187  nRange = (nRange + nLevelScale - 1) / nLevelScale;
188 
189  // Bounding box of search circle
190  int nTop = irPos.y - nRange;
191  int nBottomPlusOne = irPos.y + nRange + 1;
192  int nLeft = irPos.x - nRange;
193  int nRight = irPos.x + nRange;
194 
195  // Ref variable for the search level
196  Level &L = kf.aLevels[mnSearchLevel];
197 
198  // Some bounds checks on the bounding box..
199  if(nTop < 0)
200  nTop = 0;
201  if(nTop >= L.im.size().y)
202  return false;
203  if(nBottomPlusOne <= 0)
204  return false;
205 
206  // The next section finds all the FAST corners in the target level which
207  // are near enough the search center. It's a bit optimised to use
208  // a corner row look-up-table, since otherwise the routine
209  // would spend a long time trawling throught the whole list of FAST corners!
210  vector<ImageRef>::iterator i;
211  vector<ImageRef>::iterator i_end;
212 
213  i = L.vCorners.begin() + L.vCornerRowLUT[nTop];
214 
215  if(nBottomPlusOne >= L.im.size().y)
216  i_end = L.vCorners.end();
217  else
218  i_end = L.vCorners.begin() + L.vCornerRowLUT[nBottomPlusOne];
219 
220  ImageRef irBest; // Best match so far
221  int nBestSSD = mnMaxSSD + 1; // Best score so far is beyond the max allowed
222 
223  for(; i<i_end; i++) // For each corner ...
224  {
225  if( i->x < nLeft || i->x > nRight)
226  continue;
227  if((irPos - *i).mag_squared() > nRange * nRange)
228  continue; // ... reject all those not close enough..
229 
230  int nSSD; // .. and find the ZMSSD at those near enough.
231  nSSD = ZMSSDAtPoint(L.im, *i);
232  if(nSSD < nBestSSD) // Best yet?
233  {
234  irBest = *i;
235  nBestSSD = nSSD;
236  }
237  } // done looping over corners
238 
239  if(nBestSSD < mnMaxSSD) // Found a valid match?
240  {
242  mbFound = true;
243  }
244  else
245  mbFound = false;
246  return mbFound;
247 }
248 
249 // Makes an inverse composition template out of the coarse template.
250 // Includes calculating image of derivatives (gradients.) The inverse composition
251 // used here operates on three variables: x offet, y offset, and difference in patch
252 // means; hence things like mm3HInv are dim 3, but the trivial mean jacobian
253 // (always unity, for each pixel) is not stored.
255 {
257  Matrix<3> m3H = Zeros; // This stores jTj.
258  ImageRef ir;
259  for(ir.x = 1; ir.x < mnPatchSize - 1; ir.x++)
260  for(ir.y = 1; ir.y < mnPatchSize - 1; ir.y++)
261  {
262  Vector<2> v2Grad;
263  v2Grad[0] = 0.5 * (mimTemplate[ir + ImageRef(1,0)] - mimTemplate[ir - ImageRef(1,0)]);
264  v2Grad[1] = 0.5 * (mimTemplate[ir + ImageRef(0,1)] - mimTemplate[ir - ImageRef(0,1)]);
265  mimJacs[ir-ImageRef(1,1)].first = v2Grad[0];
266  mimJacs[ir-ImageRef(1,1)].second = v2Grad[1];
267  Vector<3> v3Grad = unproject(v2Grad); // This adds the mean-difference jacobian..
268  m3H += v3Grad.as_col() * v3Grad.as_row(); // Populate JTJ.
269  }
270 
271  // Invert JTJ..
272  Cholesky<3> chol(m3H);
273  mm3HInv = chol.get_inverse();
274  // TOON2 Does not have a get_rank for cholesky
275  // int nRank = chol.get_rank();
276  // if(nRank < 3)
277  // cout << "BAD RANK IN MAKESUBPIXELTEMPLATE!!!!" << endl; // This does not happen often (almost never!)
278 
279  mv2SubPixPos = mv2CoarsePos; // Start the sub-pixel search at the result of the coarse search..
280  mdMeanDiff = 0.0;
281 }
282 
283 // Iterate inverse composition until convergence. Since it should never have
284 // to travel more than a pixel's distance, set a max number of iterations;
285 // if this is exceeded, consider the IC to have failed.
287 {
288  const double dConvLimit = 0.03;
289  bool bConverged = false;
290  int nIts;
291  for(nIts = 0; nIts < nMaxIts && !bConverged; nIts++)
292  {
293  double dUpdateSquared = IterateSubPix(kf);
294  if(dUpdateSquared < 0) // went off edge of image
295  return false;
296  if(dUpdateSquared < dConvLimit*dConvLimit)
297  return true;
298  }
299  return false;
300 }
301 
302 // Single iteration of inverse composition. This compares integral image positions in the
303 // template image to floating point positions in the target keyframe. Interpolation is
304 // bilinear, and performed manually (rather than using CVD::image_interpolate) since
305 // this is a special case where the mixing fractions for each pixel are identical.
307 {
308  // Search level pos of patch center
311  if(!im.in_image_with_border(ir_rounded(v2Center), mnPatchSize / 2 + 1))
312  return -1.0; // Negative return value indicates off edge of image
313 
314  // Position of top-left corner of patch in search level
315  Vector<2> v2Base = v2Center - vec(mirCenter);
316 
317  // I.C. JT*d accumulator
318  Vector<3> v3Accum = Zeros;
319 
320  ImageRef ir;
321 
322  byte* pTopLeftPixel;
323 
324  // Each template pixel will be compared to an interpolated target pixel
325  // The target value is made using bilinear interpolation as the weighted sum
326  // of four target image pixels. Calculate mixing fractions:
327  double dX = v2Base[0]-floor(v2Base[0]); // Distances from pixel center of TL pixel
328  double dY = v2Base[1]-floor(v2Base[1]);
329  float fMixTL = (1.0 - dX) * (1.0 - dY);
330  float fMixTR = (dX) * (1.0 - dY);
331  float fMixBL = (1.0 - dX) * (dY);
332  float fMixBR = (dX) * (dY);
333 
334  // Loop over template image
335  unsigned long nRowOffset = &kf.aLevels[mnSearchLevel].im[ImageRef(0,1)] - &kf.aLevels[mnSearchLevel].im[ImageRef(0,0)];
336  for(ir.y = 1; ir.y < mnPatchSize - 1; ir.y++)
337  {
338  pTopLeftPixel = &im[::ir(v2Base) + ImageRef(1,ir.y)]; // n.b. the x=1 offset, as with y
339  for(ir.x = 1; ir.x < mnPatchSize - 1; ir.x++)
340  {
341  float fPixel = // Calc target interpolated pixel
342  fMixTL * pTopLeftPixel[0] + fMixTR * pTopLeftPixel[1] +
343  fMixBL * pTopLeftPixel[nRowOffset] + fMixBR * pTopLeftPixel[nRowOffset + 1];
344  pTopLeftPixel++;
345  double dDiff = fPixel - mimTemplate[ir] + mdMeanDiff;
346  v3Accum[0] += dDiff * mimJacs[ir - ImageRef(1,1)].first;
347  v3Accum[1] += dDiff * mimJacs[ir - ImageRef(1,1)].second;
348  v3Accum[2] += dDiff; // Update JT*d
349  };
350  }
351 
352  // All done looping over image - find JTJ^-1 * JTd:
353  Vector<3> v3Update = mm3HInv * v3Accum;
354  mv2SubPixPos -= v3Update.slice<0,2>() * LevelScale(mnSearchLevel);
355  mdMeanDiff -= v3Update[2];
356 
357  double dPixelUpdateSquared = v3Update.slice<0,2>() * v3Update.slice<0,2>();
358  return dPixelUpdateSquared;
359 }
360 
363 //
364 //
365 // ZMSSDatpoint, which is SSE optimised, follows
366 //
367 // The top version is the SSE version for 8x8 patches. It is compiled
368 // only if CVD_HAVE_XMMINTRIN is true, also you need to give your
369 // compiler the appropriate flags (e.g. -march=core2 -msse3 for g++.)
370 // The standard c++ version, which is about half as quick (not a disaster
371 // by any means) is below.
372 //
373 // The 8x8 SSE version looks long because it has been unrolled,
374 // it just does the same thing eight times. Both versions are one-pass
375 // and need pre-calculated template sums and sum-squares.
376 //
379 
380 #if CVD_HAVE_XMMINTRIN
381 // Horizontal sum of uint16s stored in an XMM register
382 inline int SumXMM_16(__m128i &target)
383 {
384  unsigned short int sums_store[8];
385  _mm_storeu_si128((__m128i*)sums_store, target);
386  return sums_store[0] + sums_store[1] + sums_store[2] + sums_store[3] +
387  sums_store[4] + sums_store[5] + sums_store[6] + sums_store[7];
388 }
389 // Horizontal sum of uint32s stored in an XMM register
390 inline int SumXMM_32(__m128i &target)
391 {
392  unsigned int sums_store[4];
393  _mm_storeu_si128((__m128i*)sums_store, target);
394  return sums_store[0] + sums_store[1] + sums_store[2] + sums_store[3];
395 }
396 #endif
397 
398 // Calculate the Zero-mean SSD of the coarse patch and a target imate at a specific
399 // point.
401 {
402  if(!im.in_image_with_border(ir, mirCenter[0]))
403  return mnMaxSSD + 1;
404 
405  ImageRef irImgBase = ir - mirCenter;
406  byte *imagepointer;
407  byte *templatepointer;
408 
409  int nImageSumSq = 0;
410  int nImageSum = 0;
411  int nCrossSum = 0;
412 
413 #if CVD_HAVE_XMMINTRIN
414  if(mnPatchSize == 8)
415  {
416  long unsigned int imagepointerincrement;
417 
418  __m128i xImageAsEightBytes;
419  __m128i xImageAsWords;
420  __m128i xTemplateAsEightBytes;
421  __m128i xTemplateAsWords;
422  __m128i xZero;
423  __m128i xImageSums; // These sums are 8xuint16
424  __m128i xImageSqSums; // These sums are 4xint32
425  __m128i xCrossSums; // These sums are 4xint32
426  __m128i xProduct;
427 
428 
429  xImageSums = _mm_setzero_si128();
430  xImageSqSums = _mm_setzero_si128();
431  xCrossSums = _mm_setzero_si128();
432  xZero = _mm_setzero_si128();
433 
434  imagepointer = &im[irImgBase + ImageRef(0,0)];
435  templatepointer = &mimTemplate[ImageRef(0,0)];
436  imagepointerincrement = &im[irImgBase + ImageRef(0,1)] - imagepointer;
437 
438  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
439  imagepointer += imagepointerincrement;
440  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
441  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
442  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
443  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
444  xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer);
445  templatepointer += 16;
446  xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero);
447  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
448  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
449  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
450  imagepointer += imagepointerincrement;
451  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
452  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
453  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
454  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
455  xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero);
456  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
457  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
458 
459  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
460  imagepointer += imagepointerincrement;
461  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
462  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
463  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
464  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
465  xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer);
466  templatepointer += 16;
467  xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero);
468  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
469  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
470  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
471  imagepointer += imagepointerincrement;
472  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
473  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
474  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
475  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
476  xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero);
477  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
478  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
479 
480  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
481  imagepointer += imagepointerincrement;
482  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
483  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
484  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
485  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
486  xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer);
487  templatepointer += 16;
488  xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero);
489  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
490  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
491  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
492  imagepointer += imagepointerincrement;
493  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
494  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
495  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
496  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
497  xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero);
498  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
499  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
500 
501  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
502  imagepointer += imagepointerincrement;
503  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
504  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
505  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
506  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
507  xTemplateAsEightBytes=_mm_load_si128((__m128i*) templatepointer);
508  templatepointer += 16;
509  xTemplateAsWords = _mm_unpacklo_epi8(xTemplateAsEightBytes,xZero);
510  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
511  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
512  xImageAsEightBytes=_mm_loadl_epi64((__m128i*) imagepointer);
513  xImageAsWords = _mm_unpacklo_epi8(xImageAsEightBytes,xZero);
514  xImageSums = _mm_adds_epu16(xImageAsWords,xImageSums);
515  xProduct = _mm_madd_epi16(xImageAsWords, xImageAsWords);
516  xImageSqSums = _mm_add_epi32(xProduct, xImageSqSums);
517  xTemplateAsWords = _mm_unpackhi_epi8(xTemplateAsEightBytes,xZero);
518  xProduct = _mm_madd_epi16(xImageAsWords, xTemplateAsWords);
519  xCrossSums = _mm_add_epi32(xProduct, xCrossSums);
520 
521  nImageSum = SumXMM_16(xImageSums);
522  nCrossSum = SumXMM_32(xCrossSums);
523  nImageSumSq = SumXMM_32(xImageSqSums);
524  }
525  else
526 #endif
527  {
528  for(int nRow = 0; nRow < mnPatchSize; nRow++)
529  {
530  imagepointer = &im[irImgBase + ImageRef(0,nRow)];
531  templatepointer = &mimTemplate[ImageRef(0,nRow)];
532  for(int nCol = 0; nCol < mnPatchSize; nCol++)
533  {
534  int n = imagepointer[nCol];
535  nImageSum += n;
536  nImageSumSq += n*n;
537  nCrossSum += n * templatepointer[nCol];
538  };
539  }
540  };
541 
542  int SA = mnTemplateSum;
543  int SB = nImageSum;
544 
545  int N = mnPatchSize * mnPatchSize;
546  return ((2*SA*SB - SA*SA - SB*SB)/N + nImageSumSq + mnTemplateSumSq - 2*nCrossSum);
547 }
548 
549 
550 
551 
552 
553 
Vector< 3 > v3PixelRight_W
Definition: MapPoint.h:60
Vector< 2 > mv2SubPixPos
Definition: PatchFinder.h:122
Matrix< 2 > mm2LastWarpMatrix
Definition: PatchFinder.h:133
int y
The y co-ordinate.
Definition: image_ref.h:180
int x
The x co-ordinate.
Definition: image_ref.h:179
int LevelScale(int nLevel)
Definition: LevelHelpers.h:20
double LevelNPos(double dRootPos, int nLevel)
Definition: LevelHelpers.h:48
double IterateSubPix(KeyFrame &kf)
bool FindPatchCoarse(CVD::ImageRef ir, KeyFrame &kf, unsigned int nRange)
SO3< Precision > & get_rotation()
Returns the rotation part of the transformation as a SO3.
Definition: se3.h:64
static Operator< Internal::Identity< Internal::One > > Identity
Definition: objects.h:748
CVD::ImageRef mirPredictedPos
Definition: PatchFinder.h:125
void resize(const ImageRef &size)
Definition: image.h:749
int mnTemplateSum
Definition: PatchFinder.h:112
#define LEVELS
Definition: KeyFrame.h:33
Vector< 2 > mv2CoarsePos
Definition: PatchFinder.h:126
const int nMaxSSDPerPixel
Definition: globals.h:44
double mdMeanDiff
Definition: PatchFinder.h:123
void MakeTemplateCoarseNoWarp(MapPoint &p)
TooN::Vector< 2 > vec(const ImageRef &ir)
CVD::Image< CVD::byte > im
Definition: KeyFrame.h:59
ImageRef ir_rounded(const TooN::Vector< 2 > &v)
void MakeSubPixTemplate()
CVD::Image< std::pair< float, float > > mimJacs
Definition: PatchFinder.h:117
Vector<(Size==Dynamic?Dynamic:Size+1), Precision > unproject(const Vector< Size, Precision, Base > &v)
Definition: helpers.h:166
Matrix< 3 > mm3HInv
Definition: PatchFinder.h:121
int CalcSearchLevelAndWarpMatrix(MapPoint &p, SE3<> se3CFromW, Matrix< 2 > &m2CamDerivs)
Definition: PatchFinder.cpp:33
Definition: abs.h:24
void copy(const BasicImage< S > &in, BasicImage< T > &out, ImageRef size=ImageRef(-1,-1), ImageRef begin=ImageRef(), ImageRef dst=ImageRef())
Definition: utility.h:26
PatchFinder(int nPatchSize=8)
Definition: PatchFinder.cpp:19
CVD::ImageRef mirCenter
Definition: PatchFinder.h:127
Matrix< Size, Size, Precision > get_inverse()
Definition: Cholesky.h:196
bool IterateSubPixToConvergence(KeyFrame &kf, int nMaxIts)
bool next(const ImageRef &max)
Definition: image_ref.h:220
Level aLevels[LEVELS]
Definition: KeyFrame.h:84
int nSourceLevel
Definition: MapPoint.h:47
CVD::ImageRef irCenter
Definition: MapPoint.h:48
Vector< 3 > v3PixelDown_W
Definition: MapPoint.h:59
std::vector< CVD::ImageRef > vCorners
Definition: KeyFrame.h:62
Matrix< 2 > M2Inverse(const Matrix< 2 > &m)
Definition: se3.h:50
int transform(const BasicImage< S > &in, BasicImage< T > &out, const TooN::Matrix< 2 > &M, const TooN::Vector< 2 > &inOrig, const TooN::Vector< 2 > &outOrig, const T defaultValue=T())
Definition: vision.h:304
CVD::Image< CVD::byte > mimTemplate
Definition: PatchFinder.h:116
int mnSearchLevel
Definition: PatchFinder.h:120
Vector< 3 > v3WorldPos
Definition: MapPoint.h:38
Definition: KeyFrame.h:54
ImageRef size() const
What is the size of this image?
Definition: image.h:370
bool in_image_with_border(const ImageRef &ir, int border) const
Definition: image.h:271
Matrix< 2 > mm2WarpInverse
Definition: PatchFinder.h:119
bool mbTemplateBad
Definition: PatchFinder.h:129
ImageRef ir(const TooN::Vector< 2 > &v)
std::vector< int > vCornerRowLUT
Definition: KeyFrame.h:63
int ZMSSDAtPoint(CVD::BasicImage< CVD::byte > &im, const CVD::ImageRef &ir)
unsigned char byte
Definition: byte.h:28
KeyFrame * pPatchSourceKF
Definition: MapPoint.h:46
void MakeTemplateSums()
MapPoint * mpLastTemplateMapPoint
Definition: PatchFinder.h:132
void MakeTemplateCoarse(MapPoint &p, SE3<> se3CFromW, Matrix< 2 > &m2CamDerivs)
Definition: PatchFinder.cpp:72
double LevelZeroPos(double dLevelPos, int nLevel)
Definition: LevelHelpers.h:26
void MakeTemplateCoarseCont(MapPoint &p)
Definition: PatchFinder.cpp:81
static Operator< Internal::Zero > Zeros
Definition: objects.h:727
int mnTemplateSumSq
Definition: PatchFinder.h:113