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

📄 mapmaker.cc

📁 this is software for visual SLAM
💻 CC
📖 第 1 页 / 共 3 页
字号:
// Copyright 2008 Isis Innovation Limited#include "MapMaker.h"#include "MapPoint.h"#include "Bundle.h"#include "PatchFinder.h"#include "SmallMatrixOpts.h"#include "HomographyInit.h"#include <cvd/vector_image_ref.h>#include <cvd/vision.h>#include <cvd/image_interpolate.h>#include <TooN/SVD.h>#include <TooN/SymEigen.h>#include <gvars3/instances.h>#include <fstream>#ifdef WIN32#define WIN32_LEAN_AND_MEAN#include <windows.h>#endifusing namespace CVD;using namespace std;using namespace GVars3;// Constructor sets up internal reference variable to Map.// Most of the intialisation is done by Reset()..MapMaker::MapMaker(Map& m, const ATANCamera &cam)  : mMap(m), mCamera(cam){  mbResetRequested = false;  Reset();  start(); // This CVD::thread func starts the map-maker thread with function run()  GUI.RegisterCommand("SaveMap", GUICommandCallBack, this);};void MapMaker::Reset(){  // This is only called from within the mapmaker thread...  mMap.Reset();  mvFailureQueue.clear();  while(!mqNewQueue.empty()) mqNewQueue.pop();  mMap.vpKeyFrames.clear(); // TODO: actually erase old keyframes  mvpKeyFrameQueue.clear(); // TODO: actually erase old keyframes  mbBundleRunning = false;  mbBundleConverged_Full = true;  mbBundleConverged_Recent = true;  mbResetDone = true;  mbResetRequested = false;  mbBundleAbortRequested = false;  mdWiggleScale = GV2.GetDouble("MapMaker.WiggleScale", 0.1, SILENT); // Default to 10cm between first two key-frames}// CHECK_RESET is a handy macro which makes the mapmaker thread stop// what it's doing and reset, if required.#define CHECK_RESET if(mbResetRequested) {Reset(); continue;};void MapMaker::run(){
#ifdef WIN32
  // For some reason, I get tracker thread starvation on Win32 when
  // adding key-frames. Perhaps this will help:
  SetThreadPriority(GetCurrentThread(), THREAD_PRIORITY_LOWEST);
#endif
  while(!shouldStop())  // ShouldStop is a CVD::Thread func which return true if the thread is told to exit.    {      CHECK_RESET;      sleep(5); // Sleep not really necessary, especially if mapmaker is busy      CHECK_RESET;            // Handle any GUI commands encountered..      while(!mvQueuedCommands.empty())	{	  GUICommandHandler(mvQueuedCommands.begin()->sCommand, mvQueuedCommands.begin()->sParams);	  mvQueuedCommands.erase(mvQueuedCommands.begin());	}            if(!mMap.IsGood())  // Nothing to do if there is no map yet!	continue;            // From here on, mapmaker does various map-maintenance jobs in a certain priority      // Hierarchy. For example, if there's a new key-frame to be added (QueueSize() is >0)      // then that takes high priority.            CHECK_RESET;      // Should we run local bundle adjustment?      if(!mbBundleConverged_Recent && QueueSize() == 0)  	BundleAdjustRecent();               CHECK_RESET;      // Are there any newly-made map points which need more measurements from older key-frames?      if(mbBundleConverged_Recent && QueueSize() == 0)	ReFindNewlyMade();              CHECK_RESET;      // Run global bundle adjustment?      if(mbBundleConverged_Recent && !mbBundleConverged_Full && QueueSize() == 0)	BundleAdjustAll();            CHECK_RESET;      // Very low priorty: re-find measurements marked as outliers      if(mbBundleConverged_Recent && mbBundleConverged_Full && rand()%20 == 0 && QueueSize() == 0)	ReFindFromFailureQueue();            CHECK_RESET;      HandleBadPoints();            CHECK_RESET;      // Any new key-frames to be added?      if(QueueSize() > 0)	AddKeyFrameFromTopOfQueue(); // Integrate into map data struct, and process    }}// Tracker calls this to demand a resetvoid MapMaker::RequestReset(){  mbResetDone = false;  mbResetRequested = true;}bool MapMaker::ResetDone(){  return mbResetDone;}// HandleBadPoints() Does some heuristic checks on all points in the map to see if // they should be flagged as bad, based on tracker feedback.void MapMaker::HandleBadPoints(){  // Did the tracker see this point as an outlier more often than as an inlier?  for(unsigned int i=0; i<mMap.vpPoints.size(); i++)    {      MapPoint &p = *mMap.vpPoints[i];      if(p.nMEstimatorOutlierCount > 20 && p.nMEstimatorOutlierCount > p.nMEstimatorInlierCount)	p.bBad = true;    }    // All points marked as bad will be erased - erase all records of them  // from keyframes in which they might have been measured.  for(unsigned int i=0; i<mMap.vpPoints.size(); i++)    if(mMap.vpPoints[i]->bBad)      {	MapPoint *p = mMap.vpPoints[i];	for(unsigned int j=0; j<mMap.vpKeyFrames.size(); j++)	  {	    KeyFrame &k = *mMap.vpKeyFrames[j];	    if(k.mMeasurements.count(p))	      k.mMeasurements.erase(p);	  }      }  // Move bad points to the trash list.  mMap.MoveBadPointsToTrash();}MapMaker::~MapMaker(){  mbBundleAbortRequested = true;  stop(); // makes shouldStop() return true  cout << "Waiting for mapmaker to die.." << endl;  join();  cout << " .. mapmaker has died." << endl;}// Finds 3d coords of point in reference frame B from two z=1 plane projectionsVector<3> MapMaker::ReprojectPoint(SE3 se3AfromB, const Vector<2> &v2A, const Vector<2> &v2B){  Matrix<3,4> PDash;  PDash.slice<0,0,3,3>() = se3AfromB.get_rotation().get_matrix();  PDash.slice<0,3,3,1>() = se3AfromB.get_translation().as_col();    Matrix<4> A;  A[0][0] = -1.0; A[0][1] =  0.0; A[0][2] = v2B[0]; A[0][3] = 0.0;  A[1][0] =  0.0; A[1][1] = -1.0; A[1][2] = v2B[1]; A[1][3] = 0.0;  A[2] = v2A[0] * PDash[2] - PDash[0];  A[3] = v2A[1] * PDash[2] - PDash[1];  HV_SVD<4,4,Vertical> svd(A);  Vector<4> v4Smallest = svd.get_VT()[3];  if(v4Smallest[3] == 0.0)    v4Smallest[3] = 0.00001;  return project(v4Smallest);}// InitFromStereo() generates the initial match from two keyframes// and a vector of image correspondences. Uses the bool MapMaker::InitFromStereo(KeyFrame &kF,			      KeyFrame &kS,			      vector<pair<ImageRef, ImageRef> > &vTrailMatches,			      SE3 &se3TrackerPose){  mCamera.SetImageSize(kF.aLevels[0].im.size());    vector<HomographyMatch> vMatches;  for(unsigned int i=0; i<vTrailMatches.size(); i++)    {      HomographyMatch m;      m.v2CamPlaneFirst = mCamera.UnProject(vTrailMatches[i].first);      m.v2CamPlaneSecond = mCamera.UnProject(vTrailMatches[i].second);      m.m2PixelProjectionJac = mCamera.GetProjectionDerivs();      vMatches.push_back(m);    }  SE3 se3;  bool bGood;  HomographyInit HomographyInit;  bGood = HomographyInit.Compute(vMatches, 5.0, se3);  if(!bGood)    {      cout << "  Could not init from stereo pair, try again." << endl;      return false;    }    KeyFrame *pkFirst = new KeyFrame();  KeyFrame *pkSecond = new KeyFrame();  *pkFirst = kF;  *pkSecond = kS;    pkFirst->bFixed = true;  pkFirst->se3CfromW = SE3();    pkSecond->bFixed = false;  pkSecond->se3CfromW = se3;  double dTransMagn = pkSecond->se3CfromW.get_translation() * pkSecond->se3CfromW.get_translation();  if(dTransMagn == 0)    {      cout << "  Estimated zero baseline from stereo pair, try again." << endl;      return false;    }  else    {  // change the scale of the map so the second camera is wiggleScale away from the first      double dInv = mdWiggleScale / dTransMagn;      ApplyGlobalScaleToMap(dInv);    }    // Construct map from the stereo matches.  PatchFinder finder;  for(unsigned int i=0; i<vMatches.size(); i++)    {      MapPoint *p = new MapPoint();            // Patch source stuff:      p->pPatchSourceKF = pkFirst;      p->nSourceLevel = 0;      p->v3Normal_NC = (make_Vector, 0,0,-1);      p->irCenter = vTrailMatches[i].first;      p->v3Center_NC = unproject(mCamera.UnProject(p->irCenter));      p->v3OneDownFromCenter_NC = unproject(mCamera.UnProject(p->irCenter + ImageRef(0,1)));      p->v3OneRightFromCenter_NC = unproject(mCamera.UnProject(p->irCenter + ImageRef(1,0)));      normalize(p->v3Center_NC);      normalize(p->v3OneDownFromCenter_NC);      normalize(p->v3OneRightFromCenter_NC);      p->RefreshPixelVectors();      // Do sub-pixel alignment on the second image      finder.MakeTemplateCoarseNoWarp(*p);      finder.MakeSubPixTemplate();      finder.SetSubPixPos(vec(vTrailMatches[i].second));      bool bGood = finder.IterateSubPixToConvergence(*pkSecond,10);      if(!bGood)	{ 	  delete p; continue;	}            // Triangulate point:      Vector<2> v2SecondPos = finder.GetSubPixPos();      p->v3WorldPos = ReprojectPoint(se3, mCamera.UnProject(v2SecondPos), vMatches[i].v2CamPlaneFirst);      if(p->v3WorldPos[2] < 0.0)       	{ 	  delete p; continue; 	}            // Not behind map? Good, then add to map.      p->pMMData = new MapMakerData();      mMap.vpPoints.push_back(p);            // Construct first two measurements and insert into relevant DBs:      Measurement mFirst;      mFirst.nLevel = 0;      mFirst.Source = Measurement::SRC_ROOT;      mFirst.v2RootPos = vec(vTrailMatches[i].first);      mFirst.bSubPix = true;      pkFirst->mMeasurements[p] = mFirst;      p->pMMData->sMeasurementKFs.insert(pkFirst);            Measurement mSecond;      mSecond.nLevel = 0;      mSecond.Source = Measurement::SRC_TRAIL;      mSecond.v2RootPos = finder.GetSubPixPos();      mSecond.bSubPix = true;      pkSecond->mMeasurements[p] = mSecond;      p->pMMData->sMeasurementKFs.insert(pkSecond);    }    pkFirst->dSceneDepthMean = 1.0;  // Hacks..   pkSecond->dSceneDepthMean = 1.0;  pkFirst->dSceneDepthSigma = 1.0;  pkSecond->dSceneDepthSigma = 1.0;    mMap.vpKeyFrames.push_back(pkFirst);  mMap.vpKeyFrames.push_back(pkSecond);  pkFirst->MakeKeyFrame_Rest();  pkSecond->MakeKeyFrame_Rest();    for(int i=0; i<5; i++)    BundleAdjustAll();    AddSomeMapPoints(0);  AddSomeMapPoints(3);  AddSomeMapPoints(1);  AddSomeMapPoints(2);    mbBundleConverged_Full = false;  mbBundleConverged_Recent = false;    while(!mbBundleConverged_Full)    {      BundleAdjustAll();      if(mbResetRequested)	return false;    }    // Rotate and translate the map so the dominant plane is at z=0:  ApplyGlobalTransformationToMap(CalcPlaneAligner());  mMap.bGood = true;  se3TrackerPose = pkSecond->se3CfromW;    cout << "  MapMaker: made initial map with " << mMap.vpPoints.size() << " points." << endl;  return true; }// ThinCandidates() Thins out a key-frame's candidate list.// Candidates are those salient corners where the mapmaker will attempt // to make a new map point by epipolar search. We don't want to make new points// where there are already existing map points, this routine erases such candidates.// Operates on a single level of a keyframe.void MapMaker::ThinCandidates(KeyFrame &k, int nLevel){  vector<Candidate> &vCSrc = k.aLevels[nLevel].vCandidates;  vector<Candidate> vCGood;  vector<ImageRef> irBusyLevelPos;  // Make a list of `busy' image locations, which already have features at the same level  // or at one level higher.  for(meas_it it = k.mMeasurements.begin(); it!=k.mMeasurements.end(); it++)    {      if(!(it->second.nLevel == nLevel || it->second.nLevel == nLevel + 1))	continue;      irBusyLevelPos.push_back(ir_rounded(it->second.v2RootPos / LevelScale(nLevel)));    }    // Only keep those candidates further than 10 pixels away from busy positions.  unsigned int nMinMagSquared = 10*10;  for(unsigned int i=0; i<vCSrc.size(); i++)    {      ImageRef irC = vCSrc[i].irLevelPos;      bool bGood = true;      for(unsigned int j=0; j<irBusyLevelPos.size(); j++)	{	  ImageRef irB = irBusyLevelPos[j];	  if((irB - irC).mag_squared() < nMinMagSquared)	    {	      bGood = false;	      break;	    }	}      if(bGood)	vCGood.push_back(vCSrc[i]);    }   vCSrc = vCGood;}// Adds map points by epipolar search to the last-added key-frame, at a single// specified pyramid level. Does epipolar search in the target keyframe as closest by// the ClosestKeyFrame function.void MapMaker::AddSomeMapPoints(int nLevel){  KeyFrame &kSrc = *(mMap.vpKeyFrames[mMap.vpKeyFrames.size() - 1]); // The new keyframe  KeyFrame &kTarget = *(ClosestKeyFrame(kSrc));     Level &l = kSrc.aLevels[nLevel];  ThinCandidates(kSrc, nLevel);    for(unsigned int i = 0; i<l.vCandidates.size(); i++)    AddPointEpipolar(kSrc, kTarget, nLevel, i);

⌨️ 快捷键说明

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