⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 patchfinder.cc

📁 this is software for visual SLAM
💻 CC
📖 第 1 页 / 共 2 页
字号:
// Copyright 2008 Isis Innovation Limited#include "PatchFinder.h"#include "SmallMatrixOpts.h"#include "KeyFrame.h"#include <cvd/vision.h>#include <cvd/vector_image_ref.h>#include <cvd/image_interpolate.h>#include <TooN/Cholesky.h>// tmmintrin.h contains SSE3 instrinsics, used for the ZMSSD search at the bottom..// If this causes problems, just do #define CVD_HAVE_XMMINTRIN 0#if CVD_HAVE_XMMINTRIN#include <tmmintrin.h>#endifusing namespace CVD;using namespace std;PatchFinder::PatchFinder(int nPatchSize)  : mimTemplate(ImageRef(nPatchSize,nPatchSize)){  mnPatchSize = nPatchSize;  mirCenter = ImageRef(nPatchSize/2, nPatchSize/2);  int nMaxSSDPerPixel = 500; // Pretty arbitrary... could make a GVar out of this.  mnMaxSSD = mnPatchSize * mnPatchSize * nMaxSSDPerPixel;  // Populate the speed-up caches with bogus values:  Identity(mm2LastWarpMatrix,9999.9);  mpLastTemplateMapPoint = NULL;};// Find the warping matrix and search levelint PatchFinder::CalcSearchLevelAndWarpMatrix(MapPoint &p,					      SE3 se3CFromW,					      Matrix<2> &m2CamDerivs){  // Calc point pos in new view camera frame  // Slightly dumb that we re-calculate this here when the tracker's already done this!  Vector<3> v3Cam = se3CFromW * p.v3WorldPos;  double dOneOverCameraZ = 1.0 / v3Cam[2];  // Project the source keyframe's one-pixel-right and one-pixel-down vectors into the current view  Vector<3> v3MotionRight = se3CFromW.get_rotation() * p.v3PixelRight_W;  Vector<3> v3MotionDown = se3CFromW.get_rotation() * p.v3PixelDown_W;  // Calculate in-image derivatives of source image pixel motions:  mm2WarpInverse.T()[0] = m2CamDerivs * (v3MotionRight.slice<0,2>() - v3Cam.slice<0,2>() * v3MotionRight[2] * dOneOverCameraZ) * dOneOverCameraZ;  mm2WarpInverse.T()[1] = m2CamDerivs * (v3MotionDown.slice<0,2>() - v3Cam.slice<0,2>() * v3MotionDown[2] * dOneOverCameraZ) * dOneOverCameraZ;  double dDet = mm2WarpInverse[0][0] * mm2WarpInverse[1][1] - mm2WarpInverse[0][1] * mm2WarpInverse[1][0];  mnSearchLevel = 0;    // This warp matrix is likely not appropriate for finding at level zero, which is   // the level at which it has been calculated. Vary the search level until the   // at that level would be appropriate (does not actually modify the matrix.)  while(dDet > 3 && mnSearchLevel < LEVELS-1)    {      mnSearchLevel++;      dDet *= 0.25;    };    // Some warps are inappropriate, e.g. too near the camera, too far, or reflected,   // or zero area.. reject these!  if(dDet > 3 || dDet < 0.25)    {      mbTemplateBad = true;      return -1;    }  else    return mnSearchLevel;}// This is just a convenience function wich caluclates the warp matrix and generates// the template all in one call.void PatchFinder::MakeTemplateCoarse(MapPoint &p,				     SE3 se3CFromW,				     Matrix<2> &m2CamDerivs){  CalcSearchLevelAndWarpMatrix(p, se3CFromW, m2CamDerivs);  MakeTemplateCoarseCont(p);};// This function generates the warped search template.void PatchFinder::MakeTemplateCoarseCont(MapPoint &p){  // Get the warping matrix appropriate for use with CVD::transform...  Matrix<2> m2 = M2Inverse(mm2WarpInverse) * LevelScale(mnSearchLevel);   // m2 now represents the number of pixels in the source image for one   // pixel of template image    // Optimisation: Don't re-gen the coarse template if it's going to be substantially the   // same as was made last time. This saves time when the camera is not moving. For this,   // check that (a) this patchfinder is still working on the same map point and (b) the   // warping matrix has not changed much.    bool bNeedToRefreshTemplate = false;  if(&p != mpLastTemplateMapPoint)    bNeedToRefreshTemplate = true;  // Still the same map point? Then compare warping matrix..  for(int i=0; !bNeedToRefreshTemplate && i<2; i++)    {      Vector<2> v2Diff = m2.T()[i] - mm2LastWarpMatrix.T()[i];      const double dRefreshLimit = 0.07;  // Sort of works out as half a pixel displacement in src img      if(v2Diff * v2Diff > dRefreshLimit * dRefreshLimit)	bNeedToRefreshTemplate = true;    }    // Need to regen template? Then go ahead.  if(bNeedToRefreshTemplate)    {      int nOutside;  // Use CVD::transform to warp the patch according the the warping matrix m2                     // This returns the number of pixels outside the source image hit, which should be zero.      nOutside = CVD::transform(p.pPatchSourceKF->aLevels[p.nSourceLevel].im, 				mimTemplate, 				m2,				vec(p.irCenter),				vec(mirCenter));             if(nOutside)	mbTemplateBad = true;      else	mbTemplateBad = false;            MakeTemplateSums();            // Store the parameters which allow us to determine if we need to re-calculate      // the patch next time round.      mpLastTemplateMapPoint = &p;      mm2LastWarpMatrix = m2;    }};// This makes a template without warping. Used for epipolar search, where we don't really know // what the warping matrix should be. (Although to be fair, I should do rotation for epipolar,// which we could approximate without knowing patch depth!)void PatchFinder::MakeTemplateCoarseNoWarp(KeyFrame &k, int nLevel, ImageRef irLevelPos){  mnSearchLevel = nLevel;  Image<byte> &im = k.aLevels[nLevel].im;  if(!im.in_image_with_border(irLevelPos, mnPatchSize / 2 + 1))    {      mbTemplateBad = true;      return;    }  mbTemplateBad = false;  copy(im,       mimTemplate,       mimTemplate.size(),       irLevelPos - mirCenter);    MakeTemplateSums();}// Convenient wrapper for the abovevoid PatchFinder::MakeTemplateCoarseNoWarp(MapPoint &p){  MakeTemplateCoarseNoWarp(*p.pPatchSourceKF, p.nSourceLevel,  p.irCenter);};// Finds the sum, and sum-squared, of template pixels. These sums are used// to calculate the ZMSSD.inline void PatchFinder::MakeTemplateSums(){  int nSum = 0;  int nSumSq = 0;  ImageRef ir;  do    {      int b = mimTemplate[ir];      nSum += b;      nSumSq +=b * b;    }        while(ir.next(mimTemplate.size()));  mnTemplateSum = nSum;  mnTemplateSumSq = nSumSq;}// One of the main functions of the class! Looks at the appropriate level of // the target keyframe to try and find the template. Looks only at FAST corner points// which are within radius nRange of the center. (Params are supplied in Level0// coords.) Returns true on patch found.bool PatchFinder::FindPatchCoarse(ImageRef irPos, KeyFrame &kf, unsigned int nRange){  mbFound = false;    // Convert from L0 coords to search level quantities  int nLevelScale = LevelScale(mnSearchLevel);  mirPredictedPos = irPos;  irPos = irPos / nLevelScale;  nRange = (nRange + nLevelScale - 1) / nLevelScale;    // Bounding box of search circle  int nTop = irPos.y - nRange;  int nBottomPlusOne = irPos.y + nRange + 1;  int nLeft = irPos.x - nRange;  int nRight = irPos.x + nRange;    // Ref variable for the search level  Level &L = kf.aLevels[mnSearchLevel];    // Some bounds checks on the bounding box..  if(nTop < 0)    nTop = 0;  if(nTop >= L.im.size().y)    return false;  if(nBottomPlusOne <= 0)    return false;    // The next section finds all the FAST corners in the target level which   // are near enough the search center. It's a bit optimised to use   // a corner row look-up-table, since otherwise the routine  // would spend a long time trawling throught the whole list of FAST corners!  vector<ImageRef>::iterator i;  vector<ImageRef>::iterator i_end;    i = L.vCorners.begin() + L.vCornerRowLUT[nTop];    if(nBottomPlusOne >= L.im.size().y)    i_end = L.vCorners.end();  else     i_end = L.vCorners.begin() + L.vCornerRowLUT[nBottomPlusOne];    ImageRef irBest;             // Best match so far  int nBestSSD = mnMaxSSD + 1; // Best score so far is beyond the max allowed    for(; i<i_end; i++)          // For each corner ...    {                               if( i->x < nLeft || i->x > nRight)        continue;      if((irPos - *i).mag_squared() > nRange * nRange)	continue;              // ... reject all those not close enough..      int nSSD;                // .. and find the ZMSSD at those near enough.      nSSD = ZMSSDAtPoint(L.im, *i);      if(nSSD < nBestSSD)      // Best yet?	{	  irBest = *i;	  nBestSSD = nSSD;	}    } // done looping over corners    if(nBestSSD < mnMaxSSD)      // Found a valid match?    {      mv2CoarsePos= LevelZeroPos(irBest, mnSearchLevel);      mbFound = true;    }  else    mbFound = false;  return mbFound;}// Makes an inverse composition template out of the coarse template.// Includes calculating image of derivatives (gradients.) The inverse composition// used here operates on three variables: x offet, y offset, and difference in patch// means; hence things like mm3HInv are dim 3, but the trivial mean jacobian // (always unity, for each pixel) is not stored.void PatchFinder::MakeSubPixTemplate(){  mimJacs.resize(mimTemplate.size() - ImageRef(2,2));  Matrix<3> m3H; // This stores jTj.  Zero(m3H);  ImageRef ir;  for(ir.x = 1; ir.x < mnPatchSize - 1; ir.x++)    for(ir.y = 1; ir.y < mnPatchSize - 1; ir.y++)      {	Vector<2> v2Grad;	v2Grad[0] = mimTemplate[ir + ImageRef(1,0)] - mimTemplate[ir - ImageRef(1,0)];	v2Grad[1] = mimTemplate[ir + ImageRef(0,1)] - mimTemplate[ir - ImageRef(0,1)];	mimJacs[ir-ImageRef(1,1)].first = v2Grad[0];	mimJacs[ir-ImageRef(1,1)].second = v2Grad[1];	Vector<3> v3Grad = unproject(v2Grad); // This adds the mean-difference jacobian..	m3H += v3Grad.as_col() * v3Grad.as_row(); // Populate JTJ.      }    // Invert JTJ..  Cholesky<3> chol(m3H);  mm3HInv = chol.get_inverse();  int nRank = chol.get_rank();  if(nRank < 3)    cout << "BAD RANK IN MAKESUBPIXELTEMPLATE!!!!" << endl; // This does not happen often (almost never!)  

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -