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