00001
00002 #include "ptam/OpenGL.h"
00003 #include "ptam/Tracker.h"
00004 #include "ptam/MEstimator.h"
00005 #include "ptam/ShiTomasi.h"
00006 #include "ptam/SmallMatrixOpts.h"
00007 #include "ptam/PatchFinder.h"
00008 #include "ptam/TrackerData.h"
00009 #include <ptam/Params.h>
00010
00011 #include <cvd/utility.h>
00012 #include <cvd/gl_helpers.h>
00013 #include <cvd/fast_corner.h>
00014 #include <cvd/vision.h>
00015 #include <TooN/wls.h>
00016 #include <TooN/SVD.h>
00017 #include <gvars3/instances.h>
00018 #include <gvars3/GStringUtil.h>
00019
00020 #include <opencv/cv.h>
00021
00022 #include <fstream>
00023 #include <fcntl.h>
00024 #include <math.h>
00025 #include <vector>
00026
00027 using namespace CVD;
00028 using namespace std;
00029 using namespace GVars3;
00030
00031
00032
00033 Tracker::Tracker(ImageRef irVideoSize, const ATANCamera &c, Map &m, MapMaker &mm) :
00034 mMap(m),
00035 mMapMaker(mm),
00036 mCamera(c),
00037 mRelocaliser(mMap, mCamera),
00038 mirSize(irVideoSize)
00039 {
00040 mCurrentKF.reset(new KeyFrame);
00041 mCurrentKF->bFixed = false;
00042 GUI.RegisterCommand("Reset", GUICommandCallBack, this);
00043 GUI.RegisterCommand("KeyPress", GUICommandCallBack, this);
00044 GUI.RegisterCommand("PokeTracker", GUICommandCallBack, this);
00045 TrackerData::irImageSize = mirSize;
00046
00047
00048 mOldKF.reset(new KeyFrame);
00049 mOldKF->dSceneDepthMedian=1;
00050 mOldKF->se3CfromW = SE3<>::exp(TooN::makeVector(0,0,1,M_PI,0,0));
00051 mAutoreset=false;
00052
00053
00054 mpSBILastFrame = NULL;
00055 mpSBIThisFrame = NULL;
00056
00057
00058 Reset();
00059 }
00060
00061
00062
00063
00064 void Tracker::Reset()
00065 {
00066
00067
00068
00069
00070 mMapMaker.RequestReset();
00071 while(!mMapMaker.ResetDone())
00072 #ifndef WIN32
00073 usleep(10);
00074 #else
00075 Sleep(1);
00076 #endif
00077
00078 mbDidCoarse = false;
00079 mbUserPressedSpacebar = false;
00080 mTrackingQuality = GOOD;
00081 mnLostFrames = 0;
00082 mdMSDScaledVelocityMagnitude = 0;
00083 mCurrentKF->dSceneDepthMean = 1.0;
00084 mCurrentKF->dSceneDepthSigma = 1.0;
00085
00086 mCurrentKF->dSceneDepthMedian = 1.0;
00087
00088 mnInitialStage = TRAIL_TRACKING_NOT_STARTED;
00089 mlTrails.clear();
00090 mCamera.SetImageSize(mirSize);
00091 mCurrentKF->mMeasurements.clear();
00092 mnLastKeyFrameDropped = -20;
00093 mnFrame=0;
00094 mv6CameraVelocity = Zeros;
00095 mbJustRecoveredSoUseCoarse = false;
00096 }
00097
00098 void Tracker::TrackFrame(CVD::Image<CVD::byte> &imFrame, bool bDraw, const TooN::SO3<> & imu){
00099 mso3CurrentImu = imu;
00100 TrackFrame(imFrame, bDraw);
00101 mso3LastImu = mso3CurrentImu;
00102 }
00103
00104
00105
00106
00107
00108
00109 void Tracker::TrackFrame(Image<CVD::byte> &imFrame, bool bDraw)
00110 {
00111 mbDraw = bDraw;
00112 mMessageForUser.str("");
00113 mMapMaker.resetMessageForUser();
00114
00115
00116
00117
00118 mCurrentKF.reset(new KeyFrame);
00119
00120 mCurrentKF->mMeasurements.clear();
00121 mCurrentKF->MakeKeyFrame_Lite(imFrame);
00122
00123
00124
00125 const ptam::PtamParamsConfig& pPars = PtamParameters::varparams();
00126 double gvdSBIBlur = pPars.RotationEstimatorBlur;
00127 int gvnUseSBI = pPars.UseRotationEstimator;
00128
00129
00130
00131 mbUseSBIInit = gvnUseSBI;
00132 if(!mpSBIThisFrame)
00133 {
00134 mpSBIThisFrame = new SmallBlurryImage(*mCurrentKF, gvdSBIBlur);
00135 mpSBILastFrame = new SmallBlurryImage(*mCurrentKF, gvdSBIBlur);
00136 }
00137 else
00138 {
00139 delete mpSBILastFrame;
00140 mpSBILastFrame = mpSBIThisFrame;
00141 mpSBIThisFrame = new SmallBlurryImage(*mCurrentKF, gvdSBIBlur);
00142 }
00143
00144
00145 mnFrame++;
00146
00147 if(mbDraw)
00148 {
00149 glDrawPixels(mCurrentKF->aLevels[0].im);
00150 if(GV2.GetInt("Tracker.DrawFASTCorners",0, SILENT))
00151 {
00152 glColor3f(1,0,1); glPointSize(1); glBegin(GL_POINTS);
00153 for(unsigned int i=0; i<mCurrentKF->aLevels[0].vCorners.size(); i++)
00154 glVertex(mCurrentKF->aLevels[0].vCorners[i]);
00155 glEnd();
00156 }
00157 }
00158
00159
00160 if(mMap.IsGood())
00161 {
00162 if(mnLostFrames < 3)
00163 {
00164 if(mbUseSBIInit)
00165 CalcSBIRotation();
00166 ApplyMotionModel();
00167 TrackMap();
00168 UpdateMotionModel();
00169
00170 AssessTrackingQuality();
00171
00172 {
00173 mMessageForUser << "Tracking Map, quality ";
00174 if(mTrackingQuality == GOOD) mMessageForUser << "good.";
00175 if(mTrackingQuality == DODGY) mMessageForUser << "poor.";
00176 if(mTrackingQuality == BAD) mMessageForUser << "bad.";
00177 mMessageForUser << " Found:";
00178 for(int i=0; i<LEVELS; i++) mMessageForUser << " " << manMeasFound[i] << "/" << manMeasAttempted[i];
00179
00180 mMessageForUser << " Map: " << mMap.vpPoints.size() << "P, " << mMap.vpKeyFrames.size() << "KF";
00181 }
00182
00183
00184 if(mTrackingQuality == GOOD &&
00185 mMapMaker.NeedNewKeyFrame(mCurrentKF) &&
00186
00187 mMapMaker.QueueSize() < 5)
00188 {
00189 mMessageForUser << " Adding key-frame.";
00190 AddNewKeyFrame();
00191 };
00192
00193 }
00194 else
00195 {
00196 mMessageForUser << "** Attempting recovery **.";
00197 if(AttemptRecovery())
00198 {
00199 TrackMap();
00200 AssessTrackingQuality();
00201 }
00202
00203 }
00204 if(mbDraw)
00205 RenderGrid();
00206
00207
00208 if (mAutoreset)
00209 Reset();
00210
00211 }
00212 else
00213
00214 {
00215
00216 int level = PtamParameters::fixparams().InitLevel;
00217 const ptam::PtamParamsConfig& pPars = PtamParameters::varparams();
00218 if (pPars.AutoInit)
00219 {
00220 if(mnInitialStage == TRAIL_TRACKING_NOT_STARTED)
00221 mbUserPressedSpacebar=true;
00222 else if(mnInitialStage == TRAIL_TRACKING_STARTED)
00223 {
00224
00225 SmallBlurryImage* pSBIsecond = new SmallBlurryImage(*mCurrentKF);
00226 Vector<3> rotvec = CalcSBIRotation(mFirstKF->pSBI,pSBIsecond);
00227 SO3<> rotmat = SO3<>::exp(rotvec);
00228 std::vector<double> mediandistvec;
00229
00230 unsigned short k=0;
00231 std::vector<double> medianvec;
00232 medianvec.resize(mlTrails.size());
00233 for(list<Trail>::iterator i = mlTrails.begin(); i!=mlTrails.end();++i)
00234 {
00235 Trail &trail = *i;
00236
00237 Vector<2> firstvec = LevelZeroPos(trail.irInitialPos, level);
00238 Vector<2> z1vec = mCamera.UnProject(LevelZeroPos(trail.irCurrentPos, level));
00239 Vector<3> dirvec = makeVector(z1vec[0],z1vec[1],1);
00240 dirvec = rotmat.inverse()*dirvec;
00241 z1vec = mCamera.Project(makeVector(dirvec[0]/dirvec[2],dirvec[1]/dirvec[2]));
00242 mediandistvec.push_back(sqrt((z1vec[0]-firstvec[0])*(z1vec[0]-firstvec[0])+(z1vec[1]-firstvec[1])*(z1vec[1]-firstvec[1])));
00243 ++k;
00244 }
00245 delete pSBIsecond;
00246
00247 if(k>0)
00248 {
00249 std::vector<double>::iterator first = mediandistvec.begin();
00250 std::vector<double>::iterator last = mediandistvec.end();
00251 std::vector<double>::iterator middle = first + std::floor((last - first) / 2);
00252 std::nth_element(first, middle, last);
00253 double mediandist = *middle;
00254 if (mediandist>pPars.AutoInitPixel)
00255 mbUserPressedSpacebar=true;
00256 }
00257 }
00258 }
00259
00260 TrackForInitialMap();
00261 }
00262
00263
00264
00265 while(!mvQueuedCommands.empty())
00266 {
00267 GUICommandHandler(mvQueuedCommands.begin()->sCommand, mvQueuedCommands.begin()->sParams);
00268 mvQueuedCommands.erase(mvQueuedCommands.begin());
00269 }
00270 };
00271
00272
00273
00274 Vector<3> Tracker::CalcSBIRotation(SmallBlurryImage *SBI1, SmallBlurryImage *SBI2)
00275 {
00276 SBI1->MakeJacs();
00277 pair<SE2<>, double> result_pair;
00278 result_pair = SBI2->IteratePosRelToTarget(*SBI1, 6);
00279 SE3<> se3Adjust = SmallBlurryImage::SE3fromSE2(result_pair.first, mCamera);
00280 return se3Adjust.ln().slice<3,3>();
00281 }
00282
00283
00284
00285
00286
00287
00288
00289
00290
00291 bool Tracker::AttemptRecovery()
00292 {
00293 bool bRelocGood = mRelocaliser.AttemptRecovery(*mCurrentKF);
00294 if(!bRelocGood)
00295 return false;
00296
00297 SE3<> se3Best = mRelocaliser.BestPose();
00298 mse3CamFromWorld = mse3StartPos = se3Best;
00299 mv6CameraVelocity = Zeros;
00300 mbJustRecoveredSoUseCoarse = true;
00301 return true;
00302 }
00303
00304
00305 void Tracker::RenderGrid()
00306 {
00307
00308 ComputeGrid();
00309 int dim0 = mProjVertices.size().x;
00310 int dim1 = mProjVertices.size().y;
00311
00312
00313
00314 if(mbDidCoarse)
00315 glColor4f(.0, 0.5, .0, 0.6);
00316 else
00317 glColor4f(0,0,0,0.6);
00318
00319 glEnable(GL_LINE_SMOOTH);
00320 glEnable(GL_BLEND);
00321 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00322 glLineWidth(2);
00323 for(int i=0; i<dim0; i++)
00324 {
00325 glBegin(GL_LINE_STRIP);
00326 for(int j=0; j<dim1; j++)
00327 glVertex(mProjVertices[i][j]);
00328 glEnd();
00329
00330 glBegin(GL_LINE_STRIP);
00331 for(int j=0; j<dim1; j++)
00332 glVertex(mProjVertices[j][i]);
00333 glEnd();
00334 };
00335
00336 glLineWidth(1);
00337 glColor3f(1,0,0);
00338 }
00339
00340
00341 CVD::Image<TooN::Vector<2> > & Tracker::ComputeGrid()
00342 {
00343
00344
00345
00346 int nHalfCells = 8;
00347 int nTot = nHalfCells * 2 + 1;
00348
00349 mProjVertices.resize(ImageRef(nTot,nTot));
00350 for(int i=0; i<nTot; i++)
00351 for(int j=0; j<nTot; j++)
00352 {
00353 Vector<3> v3;
00354 v3[0] = (i - nHalfCells) * 0.1;
00355 v3[1] = (j - nHalfCells) * 0.1;
00356 v3[2] = 0.0;
00357 Vector<3> v3Cam = mse3CamFromWorld * v3;
00358 if(v3Cam[2] < 0.001)
00359 v3Cam[2] = 0.001;
00360 mProjVertices[i][j] = mCamera.Project(project(v3Cam));
00361 }
00362 return mProjVertices;
00363 }
00364
00365
00366
00367
00368 void Tracker::GUICommandCallBack(void* ptr, string sCommand, string sParams)
00369 {
00370 Command c;
00371 c.sCommand = sCommand;
00372 c.sParams = sParams;
00373 ((Tracker*) ptr)->mvQueuedCommands.push_back(c);
00374 }
00375
00376
00377 void Tracker::GUICommandHandler(string sCommand, string sParams)
00378 {
00379 if(sCommand=="Reset")
00380 {
00381 Reset();
00382 return;
00383 }
00384
00385
00386 if(sCommand=="KeyPress")
00387 {
00388 if(sParams == "Space")
00389 {
00390 mbUserPressedSpacebar = true;
00391 }
00392 else if(sParams == "r")
00393 {
00394 mAutoreset=false;
00395 ROS_WARN_STREAM("Forcing map reset because of user input! Autoreset set to " << mAutoreset);
00396 Reset();
00397 }
00398 else if(sParams == "a")
00399 {
00400 mAutoreset=true;
00401 ROS_WARN_STREAM("Forcing map reset because of user input! Autoreset set to " << mAutoreset);
00402 Reset();
00403 }
00404 else if(sParams == "q" || sParams == "Escape")
00405 {
00406 GUI.ParseLine("quit");
00407 }
00408 return;
00409 }
00410 if((sCommand=="PokeTracker"))
00411 {
00412 mbUserPressedSpacebar = true;
00413 return;
00414 }
00415
00416
00417 cout << "! Tracker::GUICommandHandler: unhandled command "<< sCommand << endl;
00418 exit(1);
00419 };
00420
00421
00422
00423
00424
00425
00426 void Tracker::TrackForInitialMap()
00427 {
00428
00429
00430
00431 const ptam::PtamParamsConfig& pPars = PtamParameters::varparams();
00432 int gvnMaxSSD = pPars.MiniPatchMaxSSD;
00433
00434 int level = PtamParameters::fixparams().InitLevel;
00435 ImageRef tmpInit, tmpCurr;
00436
00437 MiniPatch::mnMaxSSD = gvnMaxSSD;
00438
00439
00440 if(mnInitialStage == TRAIL_TRACKING_NOT_STARTED)
00441 {
00442 if(mbUserPressedSpacebar)
00443 {
00444 mbUserPressedSpacebar = false;
00445 TrailTracking_Start();
00446 mnInitialStage = TRAIL_TRACKING_STARTED;
00447 }
00448 else
00449 mMessageForUser << "Point camera at planar scene and press spacebar to start tracking for initial map." << endl;
00450 return;
00451 };
00452
00453 if(mnInitialStage == TRAIL_TRACKING_STARTED)
00454 {
00455 int nGoodTrails = TrailTracking_Advance();
00456 if(nGoodTrails < 10)
00457 {
00458 Reset();
00459 return;
00460 }
00461
00462
00463 if(mbUserPressedSpacebar)
00464 {
00465 mbUserPressedSpacebar = false;
00466 vector<pair<ImageRef, ImageRef> > vMatches;
00467 for(list<Trail>::iterator i = mlTrails.begin(); i!=mlTrails.end(); i++){
00468 tmpInit.x = LevelZeroPos(i->irInitialPos.x, level);
00469 tmpInit.y = LevelZeroPos(i->irInitialPos.y, level);
00470 tmpCurr.x = LevelZeroPos(i->irCurrentPos.x, level);
00471 tmpCurr.y = LevelZeroPos(i->irCurrentPos.y, level);
00472
00473 vMatches.push_back(pair<ImageRef, ImageRef>(tmpInit, tmpCurr));
00474 }
00475
00476
00477
00478
00479 bool initret=false;
00480 initret=mMapMaker.InitFromStereo(mFirstKF, mCurrentKF, vMatches, mse3CamFromWorld);
00481
00482 if(initret)
00483 {
00484 if (mAutoreset)
00485 {
00486 std::vector<double> medianvec1, medianvec2;
00487
00488
00489 for(unsigned int ip=0;ip<mMap.vpPoints.size();ip++)
00490 {
00491
00492 medianvec1.push_back((mMap.vpKeyFrames[0]->se3CfromW*mMap.vpPoints[ip]->v3WorldPos)[2]);
00493
00494 medianvec2.push_back((mMap.vpKeyFrames[1]->se3CfromW*mMap.vpPoints[ip]->v3WorldPos)[2]);
00495 }
00496 std::vector<double>::iterator first = medianvec1.begin();
00497 std::vector<double>::iterator last = medianvec1.end();
00498 std::vector<double>::iterator middle = first + std::floor((last - first) / 2);
00499 std::nth_element(first, middle, last);
00500 mMap.vpKeyFrames[0]->dSceneDepthMedian = *middle;
00501
00502 first = medianvec2.begin();
00503 last = medianvec2.end();
00504 middle = first + std::floor((last - first) / 2);
00505 std::nth_element(first, middle, last);
00506 mMap.vpKeyFrames[1]->dSceneDepthMedian = *middle;
00507
00508 double scale = mOldKF->dSceneDepthMedian/mMap.vpKeyFrames[0]->dSceneDepthMedian;
00509 mMapMaker.ApplyGlobalScaleToMap(scale);
00510 SE3<> transf = mOldKF->se3CfromW.inverse()*mMap.vpKeyFrames[0]->se3CfromW;
00511 mMapMaker.ApplyGlobalTransformationToMap(transf);
00512 mse3CamFromWorld.get_translation() = mse3CamFromWorld.get_translation()*scale;
00513 mse3CamFromWorld = mse3CamFromWorld*transf.inverse();
00514
00515 mAutoreset=false;
00516 }
00517 mnInitialStage = TRAIL_TRACKING_COMPLETE;
00518
00519 ROS_INFO_STREAM("Initialized map on level "<<level);
00520
00521 }
00522 else
00523 {
00524 Reset();
00525 return;
00526 }
00527
00528 }
00529 else
00530 mMessageForUser << "Translate the camera slowly sideways, and press spacebar again to perform stereo init." << endl;
00531 }
00532 }
00533
00534
00535 void Tracker::TrailTracking_Start()
00536 {
00537 mCurrentKF->MakeKeyFrame_Rest();
00538
00539 mFirstKF.reset(new KeyFrame);
00540 *mFirstKF = *mCurrentKF;
00541
00542 vector<pair<double,ImageRef> > vCornersAndSTScores;
00543
00544
00545 vCornersAndSTScores.reserve(1000);
00546 int level = PtamParameters::fixparams().InitLevel;
00547 for(unsigned int i=0; i<mCurrentKF->aLevels[level].vCandidates.size(); i++)
00548 {
00549 Candidate &c = mCurrentKF->aLevels[level].vCandidates[i];
00550 if(!mCurrentKF->aLevels[level].im.in_image_with_border(c.irLevelPos, MiniPatch::mnHalfPatchSize))
00551 continue;
00552 vCornersAndSTScores.push_back(pair<double,ImageRef>(-1.0 * c.dSTScore, c.irLevelPos));
00553 };
00554 sort(vCornersAndSTScores.begin(), vCornersAndSTScores.end());
00555 int nToAdd = GV2.GetInt("MaxInitialTrails", 1000, SILENT);
00556 for(unsigned int i = 0; i<vCornersAndSTScores.size() && nToAdd > 0; i++)
00557 {
00558 if(!mCurrentKF->aLevels[level].im.in_image_with_border(vCornersAndSTScores[i].second, MiniPatch::mnHalfPatchSize))
00559 continue;
00560 Trail t;
00561 t.mPatch.SampleFromImage(vCornersAndSTScores[i].second, mCurrentKF->aLevels[level].im);
00562 t.irInitialPos = vCornersAndSTScores[i].second;
00563 t.irCurrentPos = t.irInitialPos;
00564 mlTrails.push_back(t);
00565 nToAdd--;
00566 }
00567 mPreviousFrameKF.reset(new KeyFrame);
00568 *mPreviousFrameKF = *mFirstKF;
00569 }
00570
00571
00572 int Tracker::TrailTracking_Advance()
00573 {
00574 int nGoodTrails = 0;
00575 if(mbDraw)
00576 {
00577 glPointSize(5);
00578 glLineWidth(2);
00579 glEnable(GL_POINT_SMOOTH);
00580 glEnable(GL_LINE_SMOOTH);
00581 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00582 glEnable(GL_BLEND);
00583 glBegin(GL_LINES);
00584 }
00585
00586 int level = PtamParameters::fixparams().InitLevel;
00587 MiniPatch BackwardsPatch;
00588 Level &lCurrentFrame = mCurrentKF->aLevels[level];
00589 Level &lPreviousFrame = mPreviousFrameKF->aLevels[level];
00590
00591
00592 for(list<Trail>::iterator i = mlTrails.begin(); i!=mlTrails.end();)
00593 {
00594 list<Trail>::iterator next = i; next++;
00595
00596 Trail &trail = *i;
00597 ImageRef irStart = trail.irCurrentPos;
00598 ImageRef irEnd = irStart;
00599 bool bFound = trail.mPatch.FindPatch(irEnd, lCurrentFrame.im, 10, lCurrentFrame.vCorners);
00600 if(bFound)
00601 {
00602
00603 BackwardsPatch.SampleFromImage(irEnd, lCurrentFrame.im);
00604 ImageRef irBackWardsFound = irEnd;
00605 bFound = BackwardsPatch.FindPatch(irBackWardsFound, lPreviousFrame.im, 10, lPreviousFrame.vCorners);
00606 if((irBackWardsFound - irStart).mag_squared() > 2)
00607 bFound = false;
00608
00609 trail.irCurrentPos = irEnd;
00610 nGoodTrails++;
00611 }
00612 if(mbDraw)
00613 {
00614 if(!bFound)
00615 glColor3f(0,1,1);
00616 else
00617 glColor3f(1,1,0);
00618 glVertex(LevelZeroPos(trail.irInitialPos, level));
00619 if(bFound) glColor3f(1,0,0);
00620 glVertex(LevelZeroPos(trail.irCurrentPos, level));
00621 }
00622 if(!bFound)
00623 {
00624 mlTrails.erase(i);
00625 }
00626 i = next;
00627 }
00628 if(mbDraw)
00629 glEnd();
00630
00631 mPreviousFrameKF = mCurrentKF;
00632 return nGoodTrails;
00633 }
00634
00635
00636
00637
00638
00639
00640
00641
00642
00643
00644
00645 void Tracker::TrackMap()
00646 {
00647
00648 for(int i=0; i<LEVELS; i++)
00649 manMeasAttempted[i] = manMeasFound[i] = 0;
00650
00651
00652 vector<TrackerData*> avPVS[LEVELS];
00653 for(int i=0; i<LEVELS; i++)
00654 avPVS[i].reserve(500);
00655
00656
00657 #ifdef KF_REPROJ
00658
00659 vector<KeyFrame::Ptr> vpPVKeyFrames;
00660
00661 if(mTrackingQuality == GOOD){
00662 for(unsigned int k=0; k<mMap.vpKeyFrames.size(); k++)
00663 {
00664 int foundKFPoints = 0;
00665 if (!mMap.vpKeyFrames.at(k)->vpPoints.size()) continue;
00666
00667 for(unsigned int j=0; j<mMap.vpKeyFrames.at(k)->iBestPointsCount; j++)
00668 {
00669 if(mMap.vpKeyFrames.at(k)->apCurrentBestPoints[j]==NULL) continue;
00670 MapPoint::Ptr p = (mMap.vpKeyFrames.at(k)->apCurrentBestPoints[j]);
00671
00672 if(!p->pTData) p->pTData = new TrackerData(p);
00673 TrackerData &TData = *p->pTData;
00674
00675
00676 TData.Project(mse3CamFromWorld, mCamera);
00677 if(TData.bInImage)
00678 foundKFPoints++;
00679 };
00680
00681 if(foundKFPoints>1) vpPVKeyFrames.push_back(mMap.vpKeyFrames.at(k));
00682 };
00683 };
00684
00685
00686 if (vpPVKeyFrames.size() < 1) {
00687 for(unsigned int k=0; k<mMap.vpKeyFrames.size(); k++){
00688 vpPVKeyFrames.push_back(mMap.vpKeyFrames.at(k));
00689 }
00690 }
00691 for(unsigned int k=0; k<vpPVKeyFrames.size(); k++){
00692 for(unsigned int i=0; i<vpPVKeyFrames.at(k)->vpPoints.size(); i++)
00693 {
00694 MapPoint::Ptr p= (vpPVKeyFrames.at(k)->vpPoints.at(i));
00695 if(p->bAlreadyProjected) continue;
00696 p->bAlreadyProjected=true;
00697 if(!p->pTData)
00698 p->pTData = new TrackerData(p);
00699 TrackerData &TData = *p->pTData;
00700 TData.Project(mse3CamFromWorld, mCamera);
00701 if(!TData.bInImage)
00702 continue;
00703
00704 TData.GetDerivsUnsafe(mCamera);
00705
00706
00707
00708 TData.nSearchLevel = TData.Finder.CalcSearchLevelAndWarpMatrix(TData.Point, mse3CamFromWorld, TData.m2CamDerivs);
00709
00710 if(TData.nSearchLevel == -1)
00711 continue;
00712
00713
00714 TData.bSearched = false;
00715 TData.bFound = false;
00716 avPVS[TData.nSearchLevel].push_back(&TData);
00717 };
00718 };
00719
00720
00721 for(unsigned int k=0; k<vpPVKeyFrames.size(); k++)
00722 for(unsigned int i=0; i<vpPVKeyFrames.at(k)->vpPoints.size(); i++)
00723 vpPVKeyFrames.at(k)->vpPoints.at(i)->bAlreadyProjected = false;
00724 #else
00725
00726
00727 for(unsigned int i=0; i<mMap.vpPoints.size(); i++)
00728 {
00729 MapPoint &p= *(mMap.vpPoints[i]);
00730
00731 if(!p.pTData) p.pTData = new TrackerData(&p);
00732 TrackerData &TData = *p.pTData;
00733
00734
00735 TData.Project(mse3CamFromWorld, mCamera);
00736 if(!TData.bInImage)
00737 continue;
00738
00739
00740 TData.GetDerivsUnsafe(mCamera);
00741
00742
00743 TData.nSearchLevel = TData.Finder.CalcSearchLevelAndWarpMatrix(TData.Point, mse3CamFromWorld, TData.m2CamDerivs);
00744 if(TData.nSearchLevel == -1)
00745 continue;
00746
00747
00748 TData.bSearched = false;
00749 TData.bFound = false;
00750 avPVS[TData.nSearchLevel].push_back(&TData);
00751 };
00752
00753 #endif
00754
00755
00756
00757
00758 for(int i=0; i<LEVELS; i++)
00759 random_shuffle(avPVS[i].begin(), avPVS[i].end());
00760
00761
00762
00763 vector<TrackerData*> vNextToSearch;
00764 vector<TrackerData*> vIterationSet;
00765
00766
00767
00768
00769
00770 const ptam::PtamParamsConfig& pPars = PtamParameters::varparams();
00771 unsigned int gvnCoarseMin = pPars.CoarseMin;
00772 unsigned int gvnCoarseMax = pPars.CoarseMax;
00773 unsigned int gvnCoarseRange = pPars.CoarseRange;
00774 int gvnCoarseSubPixIts = pPars.CoarseSubPixIts;
00775 int gvnCoarseDisabled = pPars.DisableCoarse;
00776 double gvdCoarseMinVel = pPars.CoarseMinVelocity;
00777
00778
00779
00780
00781
00782
00783
00784 unsigned int nCoarseMax = gvnCoarseMax;
00785 unsigned int nCoarseRange = gvnCoarseRange;
00786
00787 mbDidCoarse = false;
00788
00789
00790 bool bTryCoarse = true;
00791 if(gvnCoarseDisabled ||
00792 mdMSDScaledVelocityMagnitude < gvdCoarseMinVel ||
00793 nCoarseMax == 0)
00794 bTryCoarse = false;
00795 if(mbJustRecoveredSoUseCoarse)
00796 {
00797 bTryCoarse = true;
00798 nCoarseMax *=2;
00799 nCoarseRange *=2;
00800 mbJustRecoveredSoUseCoarse = false;
00801 };
00802
00803
00804
00805
00806 if(bTryCoarse && avPVS[LEVELS-1].size() + avPVS[LEVELS-2].size() > gvnCoarseMin )
00807 {
00808
00809
00810
00811
00812 if(avPVS[LEVELS-1].size() <= nCoarseMax)
00813 {
00814 vNextToSearch = avPVS[LEVELS-1];
00815 avPVS[LEVELS-1].clear();
00816 }
00817 else
00818 {
00819 for(unsigned int i=0; i<nCoarseMax; i++)
00820 vNextToSearch.push_back(avPVS[LEVELS-1][i]);
00821 avPVS[LEVELS-1].erase(avPVS[LEVELS-1].begin(), avPVS[LEVELS-1].begin() + nCoarseMax);
00822 }
00823
00824
00825 if(vNextToSearch.size() < nCoarseMax)
00826 {
00827 unsigned int nMoreCoarseNeeded = nCoarseMax - vNextToSearch.size();
00828 if(avPVS[LEVELS-2].size() <= nMoreCoarseNeeded)
00829 {
00830 vNextToSearch = avPVS[LEVELS-2];
00831 avPVS[LEVELS-2].clear();
00832 }
00833 else
00834 {
00835 for(unsigned int i=0; i<nMoreCoarseNeeded; i++)
00836 vNextToSearch.push_back(avPVS[LEVELS-2][i]);
00837 avPVS[LEVELS-2].erase(avPVS[LEVELS-2].begin(), avPVS[LEVELS-2].begin() + nMoreCoarseNeeded);
00838 }
00839 }
00840
00841 unsigned int nFound = SearchForPoints(vNextToSearch, nCoarseRange, gvnCoarseSubPixIts);
00842 vIterationSet = vNextToSearch;
00843 if(nFound >= gvnCoarseMin)
00844 {
00845 mbDidCoarse = true;
00846 for(int iter = 0; iter<10; iter++)
00847 {
00848 if(iter != 0)
00849 {
00850 for(unsigned int i=0; i<vIterationSet.size(); i++)
00851 if(vIterationSet[i]->bFound)
00852 vIterationSet[i]->ProjectAndDerivs(mse3CamFromWorld, mCamera);
00853 }
00854 for(unsigned int i=0; i<vIterationSet.size(); i++)
00855 if(vIterationSet[i]->bFound)
00856 vIterationSet[i]->CalcJacobian();
00857 double dOverrideSigma = 0.0;
00858
00859
00860 if(iter > 5)
00861 dOverrideSigma = 1.0;
00862
00863
00864 Vector<6> v6Update =
00865 CalcPoseUpdate(vIterationSet, dOverrideSigma);
00866 mse3CamFromWorld = SE3<>::exp(v6Update) * mse3CamFromWorld;
00867 };
00868 }
00869 };
00870
00871
00872
00873
00874 int nFineRange = 10;
00875 if(mbDidCoarse)
00876 nFineRange = 5;
00877
00878
00879
00880 {
00881 int l = LEVELS - 1;
00882 for(unsigned int i=0; i<avPVS[l].size(); i++)
00883 avPVS[l][i]->ProjectAndDerivs(mse3CamFromWorld, mCamera);
00884 SearchForPoints(avPVS[l], nFineRange, 8);
00885 for(unsigned int i=0; i<avPVS[l].size(); i++)
00886 vIterationSet.push_back(avPVS[l][i]);
00887 };
00888
00889
00890 vNextToSearch.clear();
00891 for(int l=LEVELS - 2; l>=0; l--)
00892 for(unsigned int i=0; i<avPVS[l].size(); i++)
00893 vNextToSearch.push_back(avPVS[l][i]);
00894
00895
00896
00897
00898 int gvnMaxPatchesPerFrame = pPars.MaxPatchesPerFrame;
00899
00900
00901 int nFinePatchesToUse = gvnMaxPatchesPerFrame - vIterationSet.size();
00902 if(((int) vNextToSearch.size() > nFinePatchesToUse) && (nFinePatchesToUse>0))
00903 {
00904 random_shuffle(vNextToSearch.begin(), vNextToSearch.end());
00905 vNextToSearch.resize(nFinePatchesToUse);
00906 };
00907
00908
00909 if(mbDidCoarse)
00910 for(unsigned int i=0; i<vNextToSearch.size(); i++)
00911 vNextToSearch[i]->ProjectAndDerivs(mse3CamFromWorld, mCamera);
00912
00913
00914 SearchForPoints(vNextToSearch, nFineRange, 0);
00915
00916 for(unsigned int i=0; i<vNextToSearch.size(); i++)
00917 vIterationSet.push_back(vNextToSearch[i]);
00918
00919
00920 Vector<6> v6LastUpdate;
00921 v6LastUpdate = Zeros;
00922 for(int iter = 0; iter<10; iter++)
00923 {
00924 bool bNonLinearIteration;
00925
00926 if(iter == 0 || iter == 4 || iter == 9)
00927 bNonLinearIteration = true;
00928 else
00929 bNonLinearIteration = false;
00930
00931 if(iter != 0)
00932 {
00933 if(bNonLinearIteration)
00934 {
00935 for(unsigned int i=0; i<vIterationSet.size(); i++)
00936 if(vIterationSet[i]->bFound)
00937 vIterationSet[i]->ProjectAndDerivs(mse3CamFromWorld, mCamera);
00938 }
00939 else
00940 {
00941 for(unsigned int i=0; i<vIterationSet.size(); i++)
00942 if(vIterationSet[i]->bFound)
00943 vIterationSet[i]->LinearUpdate(v6LastUpdate);
00944 };
00945 }
00946
00947 if(bNonLinearIteration)
00948 for(unsigned int i=0; i<vIterationSet.size(); i++)
00949 if(vIterationSet[i]->bFound)
00950 vIterationSet[i]->CalcJacobian();
00951
00952
00953 double dOverrideSigma = 0.0;
00954 if(iter > 5)
00955 dOverrideSigma = 16.0;
00956
00957
00958 Vector<6> v6Update =
00959 CalcPoseUpdate(vIterationSet, dOverrideSigma, iter==9);
00960 mse3CamFromWorld = SE3<>::exp(v6Update) * mse3CamFromWorld;
00961 v6LastUpdate = v6Update;
00962 };
00963
00964 if(mbDraw)
00965 {
00966 glPointSize(6);
00967 glEnable(GL_BLEND);
00968 glEnable(GL_POINT_SMOOTH);
00969 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00970 glBegin(GL_POINTS);
00971 for(vector<TrackerData*>::reverse_iterator it = vIterationSet.rbegin();
00972 it!= vIterationSet.rend();
00973 it++)
00974 {
00975 if(! (*it)->bFound)
00976 continue;
00977 glColor(gavLevelColors[(*it)->nSearchLevel]);
00978 glVertex((*it)->v2Image);
00979 }
00980 glEnd();
00981 glDisable(GL_BLEND);
00982 }
00983
00984
00985
00986
00987
00988 mCurrentKF->se3CfromW = mse3CamFromWorld;
00989
00990
00991 mCurrentKF->mMeasurements.clear();
00992 for(vector<TrackerData*>::iterator it = vIterationSet.begin();
00993 it!= vIterationSet.end();
00994 it++)
00995 {
00996 if(! (*it)->bFound)
00997 continue;
00998 Measurement m;
00999 m.Source = Measurement::SRC_TRACKER;
01000 m.v2RootPos = (*it)->v2Found;
01001 m.nLevel = (*it)->nSearchLevel;
01002 m.bSubPix = (*it)->bDidSubPix;
01003 mCurrentKF->mMeasurements[((*it)->Point)] = m;
01004 }
01005
01006
01007 {
01008 double dSum = 0;
01009 double dSumSq = 0;
01010 int nNum = 0;
01011 std::vector<double> buffvec;
01012 for(vector<TrackerData*>::iterator it = vIterationSet.begin();
01013 it!= vIterationSet.end();
01014 it++)
01015 if((*it)->bFound)
01016 {
01017 double z = (*it)->v3Cam[2];
01018 dSum+= z;
01019 dSumSq+= z*z;
01020
01021 buffvec.push_back(z);
01022
01023 nNum++;
01024 };
01025 if(nNum > 20)
01026 {
01027 mCurrentKF->dSceneDepthMean = dSum/nNum;
01028 mCurrentKF->dSceneDepthSigma = sqrt((dSumSq / nNum) - (mCurrentKF->dSceneDepthMean) * (mCurrentKF->dSceneDepthMean));
01029
01030 std::vector<double>::iterator first = buffvec.begin();
01031 std::vector<double>::iterator last = buffvec.end();
01032 std::vector<double>::iterator middle = first + std::floor((last - first) / 2);
01033 std::nth_element(first, middle, last);
01034 mCurrentKF->dSceneDepthMedian = *middle;
01035
01036 }
01037 }
01038 }
01039
01040
01041 int Tracker::SearchForPoints(vector<TrackerData*> &vTD, int nRange, int nSubPixIts)
01042 {
01043 int nFound = 0;
01044 for(unsigned int i=0; i<vTD.size(); i++)
01045 {
01046
01047
01048 TrackerData &TD = *vTD[i];
01049 PatchFinder &Finder = TD.Finder;
01050 Finder.MakeTemplateCoarseCont(TD.Point);
01051 if(Finder.TemplateBad())
01052 {
01053 TD.bInImage = TD.bPotentiallyVisible = TD.bFound = false;
01054 continue;
01055 }
01056 manMeasAttempted[Finder.GetLevel()]++;
01057
01058 bool bFound =
01059 Finder.FindPatchCoarse(ir(TD.v2Image), mCurrentKF, nRange);
01060 TD.bSearched = true;
01061 if(!bFound)
01062 {
01063 TD.bFound = false;
01064 continue;
01065 }
01066
01067 TD.bFound = true;
01068 TD.dSqrtInvNoise = (1.0 / Finder.GetLevelScale());
01069
01070 nFound++;
01071 manMeasFound[Finder.GetLevel()]++;
01072
01073
01074 if(nSubPixIts > 0)
01075 {
01076 TD.bDidSubPix = true;
01077 Finder.MakeSubPixTemplate();
01078 bool bSubPixConverges=Finder.IterateSubPixToConvergence(*mCurrentKF, nSubPixIts);
01079 if(!bSubPixConverges)
01080 {
01081 TD.bFound = false;
01082 nFound--;
01083 manMeasFound[Finder.GetLevel()]--;
01084 continue;
01085 }
01086 TD.v2Found = Finder.GetSubPixPos();
01087 }
01088 else
01089 {
01090 TD.v2Found = Finder.GetCoarsePosAsVector();
01091 TD.bDidSubPix = false;
01092 }
01093 }
01094
01095 return nFound;
01096 };
01097
01098
01099
01100
01101
01102
01103
01104
01105 Vector<6> Tracker::CalcPoseUpdate(vector<TrackerData*> vTD, double dOverrideSigma, bool bMarkOutliers)
01106 {
01107
01108 int nEstimator = 0;
01109
01110
01111 const FixParams& pPars = PtamParameters::fixparams();
01112 static std::string gvsEstimator = pPars.TrackerMEstimator;
01113
01114 if(gvsEstimator == "Tukey")
01115 nEstimator = 0;
01116 else if(gvsEstimator == "Cauchy")
01117 nEstimator = 1;
01118 else if(gvsEstimator == "Huber")
01119 nEstimator = 2;
01120 else
01121 {
01122 cout << "Invalid TrackerMEstimator, choices are Tukey, Cauchy, Huber" << endl;
01123 nEstimator = 0;
01124 gvsEstimator = "Tukey";
01125 };
01126
01127
01128
01129 vector<double> vdErrorSquared;
01130 for(unsigned int f=0; f<vTD.size(); f++)
01131 {
01132 TrackerData &TD = *vTD[f];
01133 if(!TD.bFound)
01134 continue;
01135 TD.v2Error_CovScaled = TD.dSqrtInvNoise* (TD.v2Found - TD.v2Image);
01136 vdErrorSquared.push_back(static_cast<double>(TD.v2Error_CovScaled * TD.v2Error_CovScaled));
01137 };
01138
01139
01140 if(vdErrorSquared.size() == 0)
01141 return makeVector( 0,0,0,0,0,0);
01142
01143
01144 double dSigmaSquared;
01145 if(dOverrideSigma > 0)
01146 dSigmaSquared = dOverrideSigma;
01147 else
01148 {
01149 if (nEstimator == 0)
01150 dSigmaSquared = Tukey::FindSigmaSquared(vdErrorSquared);
01151 else if(nEstimator == 1)
01152 dSigmaSquared = Cauchy::FindSigmaSquared(vdErrorSquared);
01153 else
01154 dSigmaSquared = Huber::FindSigmaSquared(vdErrorSquared);
01155 }
01156
01157
01158
01159 WLS<6> wls;
01160 wls.add_prior(100.0);
01161 for(unsigned int f=0; f<vTD.size(); f++)
01162 {
01163 TrackerData &TD = *vTD[f];
01164 if(!TD.bFound)
01165 continue;
01166 Vector<2> &v2 = TD.v2Error_CovScaled;
01167 double dErrorSq = v2 * v2;
01168 double dWeight;
01169
01170 if(nEstimator == 0)
01171 dWeight= Tukey::Weight(dErrorSq, dSigmaSquared);
01172 else if(nEstimator == 1)
01173 dWeight= Cauchy::Weight(dErrorSq, dSigmaSquared);
01174 else
01175 dWeight= Huber::Weight(dErrorSq, dSigmaSquared);
01176
01177
01178 if(dWeight == 0.0)
01179 {
01180 if(bMarkOutliers)
01181 TD.Point->nMEstimatorOutlierCount++;
01182 continue;
01183 }
01184 else
01185 if(bMarkOutliers)
01186 TD.Point->nMEstimatorInlierCount++;
01187
01188 Matrix<2,6> &m26Jac = TD.m26Jacobian;
01189 wls.add_mJ(v2[0], TD.dSqrtInvNoise * m26Jac[0], dWeight);
01190 wls.add_mJ(v2[1], TD.dSqrtInvNoise * m26Jac[1], dWeight);
01191 }
01192
01193 wls.compute();
01194
01195 if (bMarkOutliers)
01196 mmCovariances=TooN::SVD<6>(wls.get_C_inv()).get_pinv();
01197
01198 return wls.get_mu();
01199 }
01200
01201
01202
01203
01204
01205
01206 void Tracker::ApplyMotionModel()
01207 {
01208 const VarParams& vp = PtamParameters::varparams();
01209 mse3StartPos = mse3CamFromWorld;
01210 Vector<6> v6Velocity = mv6CameraVelocity;
01211 if(mbUseSBIInit && vp.MotionModelSource == ptam::PtamParams_MM_CONSTANT)
01212 {
01213 v6Velocity.slice<3,3>() = mv6SBIRot.slice<3,3>();
01214 v6Velocity[0] = 0.0;
01215 v6Velocity[1] = 0.0;
01216 }
01217 else if(vp.MotionModelSource == ptam::PtamParams_MM_IMU)
01218 {
01219
01220 v6Velocity.slice<3,3>() = (mso3LastImu*mso3CurrentImu.inverse()).ln();
01221
01222
01223 }
01224
01225
01226
01227
01228
01229
01230 mse3CamFromWorld = SE3<>::exp(v6Velocity) * mse3StartPos;
01231 };
01232
01233
01234
01235
01236 void Tracker::UpdateMotionModel()
01237 {
01238 SE3<> se3NewFromOld = mse3CamFromWorld * mse3StartPos.inverse();
01239 Vector<6> v6Motion = SE3<>::ln(se3NewFromOld);
01240 Vector<6> v6OldVel = mv6CameraVelocity;
01241
01242 mv6CameraVelocity = 0.9 * (0.5 * v6Motion + 0.5 * v6OldVel);
01243 mdVelocityMagnitude = sqrt(mv6CameraVelocity * mv6CameraVelocity);
01244
01245
01246
01247
01248 Vector<6> v6 = mv6CameraVelocity;
01249 v6.slice<0,3>() *= 1.0 / mCurrentKF->dSceneDepthMean;
01250 mdMSDScaledVelocityMagnitude = sqrt(v6*v6);
01251 }
01252
01253
01254 void Tracker::AddNewKeyFrame()
01255 {
01256 mMapMaker.AddKeyFrame(mCurrentKF);
01257 mnLastKeyFrameDropped = mnFrame;
01258 }
01259
01260
01261
01262
01263 void Tracker::AssessTrackingQuality()
01264 {
01265 int nTotalAttempted = 0;
01266 int nTotalFound = 0;
01267 int nLargeAttempted = 0;
01268 int nLargeFound = 0;
01269
01270 for(int i=0; i<LEVELS; i++)
01271 {
01272 nTotalAttempted += manMeasAttempted[i];
01273 nTotalFound += manMeasFound[i];
01274 if(i>=2) nLargeAttempted += manMeasAttempted[i];
01275 if(i>=2) nLargeFound += manMeasFound[i];
01276 }
01277
01278
01279
01280 const ptam::PtamParamsConfig& pPars = PtamParameters::varparams();
01281 if(nTotalFound <= pPars.TrackingQualityFoundPixels || nTotalAttempted == 0)
01282 mTrackingQuality = BAD;
01283
01284 else
01285 {
01286 double dTotalFracFound = (double) nTotalFound / nTotalAttempted;
01287 double dLargeFracFound;
01288 if(nLargeAttempted > 10)
01289 dLargeFracFound = (double) nLargeFound / nLargeAttempted;
01290 else
01291 dLargeFracFound = dTotalFracFound;
01292
01293
01294 double gvdQualityGood = pPars.TrackingQualityGood;
01295 double gvdQualityLost = pPars.TrackingQualityLost;
01296
01297
01298
01299
01300 if(dTotalFracFound > gvdQualityGood)
01301 mTrackingQuality = GOOD;
01302 else if(dLargeFracFound < gvdQualityLost)
01303 mTrackingQuality = BAD;
01304 else
01305 mTrackingQuality = DODGY;
01306 }
01307
01308 if(mTrackingQuality == DODGY)
01309 {
01310
01311
01312 if(mMapMaker.IsDistanceToNearestKeyFrameExcessive(mCurrentKF))
01313 mTrackingQuality = BAD;
01314 }
01315
01316 if(mTrackingQuality==BAD)
01317 {
01318
01319
01320 const ptam::PtamParamsConfig& pPars = PtamParameters::varparams();
01321 if (pPars.AutoInit & mMap.IsGood())
01322 {
01323 mAutoreset=true;
01324 ROS_WARN_STREAM("Forcing map reset because of bad tracking! Autoreset set to " << mAutoreset);
01325 }
01326
01327 mnLostFrames++;
01328 }
01329 else
01330 {
01331 mnLostFrames = 0;
01332
01333 if(!mAutoreset){
01334 mOldKF.reset(new KeyFrame);
01335 *mOldKF = *mCurrentKF;
01336 }
01337
01338 }
01339 }
01340
01341 string Tracker::GetMessageForUser()
01342 {
01343 return mMessageForUser.str();
01344 }
01345
01346 void Tracker::CalcSBIRotation()
01347 {
01348 mpSBILastFrame->MakeJacs();
01349 pair<SE2<>, double> result_pair;
01350 result_pair = mpSBIThisFrame->IteratePosRelToTarget(*mpSBILastFrame, 6);
01351 SE3<> se3Adjust = SmallBlurryImage::SE3fromSE2(result_pair.first, mCamera);
01352 mv6SBIRot = se3Adjust.ln();
01353 }
01354
01355
01356 ImageRef TrackerData::irImageSize;
01357
01358
01359
01360 void Tracker::command(const std::string & cmd){
01361
01362 if(PtamParameters::fixparams().gui)
01363 this->GUICommandCallBack(this, "KeyPress", cmd);
01364 else
01365 this->GUICommandHandler("KeyPress", cmd);
01366 }
01367
01368
01369
01370
01371
01372
01373
01374
01375