OdometryORBSLAM2.cpp
Go to the documentation of this file.
1 /*
2 Copyright (c) 2010-2016, Mathieu Labbe - IntRoLab - Universite de Sherbrooke
3 All rights reserved.
4 
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions are met:
7  * Redistributions of source code must retain the above copyright
8  notice, this list of conditions and the following disclaimer.
9  * Redistributions in binary form must reproduce the above copyright
10  notice, this list of conditions and the following disclaimer in the
11  documentation and/or other materials provided with the distribution.
12  * Neither the name of the Universite de Sherbrooke nor the
13  names of its contributors may be used to endorse or promote products
14  derived from this software without specific prior written permission.
15 
16 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
17 ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
18 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
19 DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY
20 DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
21 (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
22 LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
23 ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
25 SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
26 */
27 
30 #include "rtabmap/core/util2d.h"
33 #include "rtabmap/utilite/UTimer.h"
34 #include "rtabmap/utilite/UStl.h"
36 #include <pcl/common/transforms.h>
37 #include <opencv2/imgproc/types_c.h>
38 
39 #ifdef RTABMAP_ORB_SLAM2
40 #include <System.h>
41 #include <thread>
42 
43 using namespace std;
44 
45 namespace ORB_SLAM2 {
46 // Override original Tracking object to comment all rendering stuff
47 class Tracker: public Tracking
48 {
49 public:
50  Tracker(System* pSys, ORBVocabulary* pVoc, FrameDrawer* pFrameDrawer, MapDrawer* pMapDrawer, Map* pMap,
51  KeyFrameDatabase* pKFDB, const std::string &strSettingPath, const int sensor, long unsigned int maxFeatureMapSize) :
52  Tracking(pSys, pVoc, pFrameDrawer, pMapDrawer, pMap, pKFDB, strSettingPath, sensor),
53  maxFeatureMapSize_(maxFeatureMapSize)
54  {
55 
56  }
57 private:
58  long unsigned int maxFeatureMapSize_;
59 
60 protected:
61  void Track()
62  {
63  if(mState==NO_IMAGES_YET)
64  {
65  mState = NOT_INITIALIZED;
66  }
67 
68  mLastProcessedState=mState;
69 
70  // Get Map Mutex -> Map cannot be changed
71  unique_lock<mutex> lock(mpMap->mMutexMapUpdate);
72 
73  if(mState==NOT_INITIALIZED)
74  {
75  // if(mSensor==System::STEREO || mSensor==System::RGBD)
76  StereoInitialization();
77  //else
78  // MonocularInitialization();
79 
80  //mpFrameDrawer->Update(this);
81 
82  if(mState!=OK)
83  return;
84  }
85  else
86  {
87  // System is initialized. Track Frame.
88  bool bOK;
89 
90  // Initial camera pose estimation using motion model or relocalization (if tracking is lost)
91  if(!mbOnlyTracking)
92  {
93  // Local Mapping is activated. This is the normal behaviour, unless
94  // you explicitly activate the "only tracking" mode.
95 
96  if(mState==OK || mState==LOST)
97  {
98  // Local Mapping might have changed some MapPoints tracked in last frame
99  CheckReplacedInLastFrame();
100 
101  if(mVelocity.empty() || mCurrentFrame.mnId<mnLastRelocFrameId+2)
102  {
103  bOK = TrackReferenceKeyFrame();
104  }
105  else
106  {
107  bOK = TrackWithMotionModel();
108  if(!bOK)
109  bOK = TrackReferenceKeyFrame();
110  }
111  if(bOK)
112  {
113  mState=OK;
114  }
115  }
116  else
117  {
118  bOK = Relocalization();
119  }
120  }
121  else
122  {
123  // Localization Mode: Local Mapping is deactivated
124 
125  if(mState==LOST)
126  {
127  bOK = Relocalization();
128  }
129  else
130  {
131  if(!mbVO)
132  {
133  // In last frame we tracked enough MapPoints in the map
134 
135  if(!mVelocity.empty())
136  {
137  bOK = TrackWithMotionModel();
138  }
139  else
140  {
141  bOK = TrackReferenceKeyFrame();
142  }
143  }
144  else
145  {
146  // In last frame we tracked mainly "visual odometry" points.
147 
148  // We compute two camera poses, one from motion model and one doing relocalization.
149  // If relocalization is sucessfull we choose that solution, otherwise we retain
150  // the "visual odometry" solution.
151 
152  bool bOKMM = false;
153  bool bOKReloc = false;
154  std::vector<MapPoint*> vpMPsMM;
155  std::vector<bool> vbOutMM;
156  cv::Mat TcwMM;
157  if(!mVelocity.empty())
158  {
159  bOKMM = TrackWithMotionModel();
160  vpMPsMM = mCurrentFrame.mvpMapPoints;
161  vbOutMM = mCurrentFrame.mvbOutlier;
162  TcwMM = mCurrentFrame.mTcw.clone();
163  }
164  bOKReloc = Relocalization();
165 
166  if(bOKMM && !bOKReloc)
167  {
168  mCurrentFrame.SetPose(TcwMM);
169  mCurrentFrame.mvpMapPoints = vpMPsMM;
170  mCurrentFrame.mvbOutlier = vbOutMM;
171 
172  if(mbVO)
173  {
174  for(int i =0; i<mCurrentFrame.N; i++)
175  {
176  if(mCurrentFrame.mvpMapPoints[i] && !mCurrentFrame.mvbOutlier[i])
177  {
178  mCurrentFrame.mvpMapPoints[i]->IncreaseFound();
179  }
180  }
181  }
182  }
183  else if(bOKReloc)
184  {
185  mbVO = false;
186  }
187 
188  bOK = bOKReloc || bOKMM;
189  }
190  }
191  }
192 
193  mCurrentFrame.mpReferenceKF = mpReferenceKF;
194 
195  // If we have an initial estimation of the camera pose and matching. Track the local map.
196  if(!mbOnlyTracking)
197  {
198  if(bOK)
199  bOK = TrackLocalMap();
200  }
201  else
202  {
203  // mbVO true means that there are few matches to MapPoints in the map. We cannot retrieve
204  // a local map and therefore we do not perform TrackLocalMap(). Once the system relocalizes
205  // the camera we will use the local map again.
206  if(bOK && !mbVO)
207  bOK = TrackLocalMap();
208  }
209 
210  if(bOK)
211  mState = OK;
212  else
213  mState=LOST;
214 
215  // Update drawer
216  //mpFrameDrawer->Update(this);
217 
218  // If tracking were good, check if we insert a keyframe
219  if(bOK)
220  {
221  // Update motion model
222  if(!mLastFrame.mTcw.empty())
223  {
224  cv::Mat LastTwc = cv::Mat::eye(4,4,CV_32F);
225  mLastFrame.GetRotationInverse().copyTo(LastTwc.rowRange(0,3).colRange(0,3));
226  mLastFrame.GetCameraCenter().copyTo(LastTwc.rowRange(0,3).col(3));
227  mVelocity = mCurrentFrame.mTcw*LastTwc;
228  }
229  else
230  mVelocity = cv::Mat();
231 
232  //mpMapDrawer->SetCurrentCameraPose(mCurrentFrame.mTcw);
233 
234  // Clean VO matches
235  for(int i=0; i<mCurrentFrame.N; i++)
236  {
237  MapPoint* pMP = mCurrentFrame.mvpMapPoints[i];
238  if(pMP)
239  if(pMP->Observations()<1)
240  {
241  mCurrentFrame.mvbOutlier[i] = false;
242  mCurrentFrame.mvpMapPoints[i]=static_cast<MapPoint*>(NULL);
243  }
244  }
245 
246  // Delete temporal MapPoints
247  for(list<MapPoint*>::iterator lit = mlpTemporalPoints.begin(), lend = mlpTemporalPoints.end(); lit!=lend; lit++)
248  {
249  MapPoint* pMP = *lit;
250  delete pMP;
251  }
252  mlpTemporalPoints.clear();
253 
254  // Check if we need to insert a new keyframe
255  if(NeedNewKeyFrame())
256  {
257  CreateNewKeyFrame();
258  }
259 
260  if(maxFeatureMapSize_ > 0)
261  {
262  //limit size of the feature map, keep last X recent ones
263  if(mpMap->KeyFramesInMap()>1 && mpMap->MapPointsInMap()>maxFeatureMapSize_)
264  {
265  std::vector<KeyFrame*> kfs = mpMap->GetAllKeyFrames();
266  std::map<long unsigned int, KeyFrame*> kfsSorted;
267  for(unsigned int i=1; i<kfs.size(); ++i)
268  {
269  kfsSorted.insert(std::make_pair(kfs[i]->mnId, kfs[i]));
270  }
271  KeyFrame * lastFrame = kfsSorted.rbegin()->second;
272  std::vector<MapPoint*> mapPoints = mpMap->GetAllMapPoints();
273  std::map<long unsigned int, MapPoint*> mapPointsSorted;
274  for(unsigned int i=0; i<mapPoints.size(); ++i)
275  {
276  mapPointsSorted.insert(std::make_pair(mapPoints[i]->mnId, mapPoints[i]));
277  }
278 
279  for(std::map<long unsigned int, MapPoint*>::iterator iter=mapPointsSorted.begin();
280  iter != mapPointsSorted.end() && mpMap->MapPointsInMap()>maxFeatureMapSize_;
281  ++iter)
282  {
283  if(!iter->second->IsInKeyFrame(lastFrame))
284  {
285  // FIXME: Memory leak: ORB_SLAM2 doesn't delete after removing from the map...
286  // Not sure when it is safe to delete it, as if I delete just
287  // after setting the bad flag, the app crashes.
288  iter->second->SetBadFlag();
289  }
290  }
291  // remove kfs without observations
292  for(std::map<long unsigned int, KeyFrame*>::iterator iter=kfsSorted.begin();
293  iter != kfsSorted.end();
294  ++iter)
295  {
296  if(iter->second!=lastFrame && iter->second->GetMapPoints().size()==0)
297  {
298  // FIXME: Memory leak: ORB_SLAM2 doesn't delete after removing from the map...
299  // Not sure when it is safe to delete it, as if I delete just
300  // after setting the bad flag, the app crashes.
301  iter->second->SetErase();
302  }
303  else
304  {
305  break;
306  }
307  }
308  }
309  }
310 
311  // We allow points with high innovation (considererd outliers by the Huber Function)
312  // pass to the new keyframe, so that bundle adjustment will finally decide
313  // if they are outliers or not. We don't want next frame to estimate its position
314  // with those points so we discard them in the frame.
315  for(int i=0; i<mCurrentFrame.N;i++)
316  {
317  if(mCurrentFrame.mvpMapPoints[i] && mCurrentFrame.mvbOutlier[i])
318  mCurrentFrame.mvpMapPoints[i]=static_cast<MapPoint*>(NULL);
319  }
320  }
321 
322  // Reset if the camera get lost soon after initialization
323  if(mState==LOST)
324  {
325  //if(mpMap->KeyFramesInMap()<=5)
326  {
327  UWARN("Track lost...");
328  return;
329 
330  }
331  }
332 
333  if(!mCurrentFrame.mpReferenceKF)
334  mCurrentFrame.mpReferenceKF = mpReferenceKF;
335 
336  mLastFrame = Frame(mCurrentFrame);
337  }
338 
339  // Store frame pose information to retrieve the complete camera trajectory afterwards.
340  if(!mCurrentFrame.mTcw.empty())
341  {
342  cv::Mat Tcr = mCurrentFrame.mTcw*mCurrentFrame.mpReferenceKF->GetPoseInverse();
343  mlRelativeFramePoses.push_back(Tcr);
344  mlpReferences.push_back(mpReferenceKF);
345  mlFrameTimes.push_back(mCurrentFrame.mTimeStamp);
346  mlbLost.push_back(mState==LOST);
347  }
348  else
349  {
350  // This can happen if tracking is lost
351  mlRelativeFramePoses.push_back(mlRelativeFramePoses.back());
352  mlpReferences.push_back(mlpReferences.back());
353  mlFrameTimes.push_back(mlFrameTimes.back());
354  mlbLost.push_back(mState==LOST);
355  }
356  }
357 
358  void StereoInitialization()
359  {
360  if(mCurrentFrame.N>500)
361  {
362  // Set Frame pose to the origin
363  mCurrentFrame.SetPose(cv::Mat::eye(4,4,CV_32F));
364 
365  // Create KeyFrame
366  KeyFrame* pKFini = new KeyFrame(mCurrentFrame,mpMap,mpKeyFrameDB);
367 
368  // Insert KeyFrame in the map
369  mpMap->AddKeyFrame(pKFini);
370 
371  // Create MapPoints and asscoiate to KeyFrame
372  for(int i=0; i<mCurrentFrame.N;i++)
373  {
374  float z = mCurrentFrame.mvDepth[i];
375  if(z>0)
376  {
377  cv::Mat x3D = mCurrentFrame.UnprojectStereo(i);
378  MapPoint* pNewMP = new MapPoint(x3D,pKFini,mpMap);
379  pNewMP->AddObservation(pKFini,i);
380  pKFini->AddMapPoint(pNewMP,i);
381  pNewMP->ComputeDistinctiveDescriptors();
382  pNewMP->UpdateNormalAndDepth();
383  mpMap->AddMapPoint(pNewMP);
384 
385  mCurrentFrame.mvpMapPoints[i]=pNewMP;
386  }
387  }
388 
389  cout << "New map created with " << mpMap->MapPointsInMap() << " points" << endl;
390 
391  mpLocalMapper->InsertKeyFrame(pKFini);
392 
393  mLastFrame = Frame(mCurrentFrame);
394  mnLastKeyFrameId=mCurrentFrame.mnId;
395  mpLastKeyFrame = pKFini;
396 
397  mvpLocalKeyFrames.push_back(pKFini);
398  mvpLocalMapPoints=mpMap->GetAllMapPoints();
399  mpReferenceKF = pKFini;
400  mCurrentFrame.mpReferenceKF = pKFini;
401 
402  mpMap->SetReferenceMapPoints(mvpLocalMapPoints);
403 
404  mpMap->mvpKeyFrameOrigins.push_back(pKFini);
405 
406  //mpMapDrawer->SetCurrentCameraPose(mCurrentFrame.mTcw);
407 
408  mState=OK;
409  }
410  }
411 
412 public:
413  cv::Mat GrabImageStereo(const cv::Mat &imRectLeft, const cv::Mat &imRectRight, const double &timestamp)
414  {
415  mImGray = imRectLeft;
416  cv::Mat imGrayRight = imRectRight;
417 
418  if(mImGray.channels()==3)
419  {
420  if(mbRGB)
421  {
422  cvtColor(mImGray,mImGray,CV_RGB2GRAY);
423  }
424  else
425  {
426  cvtColor(mImGray,mImGray,CV_BGR2GRAY);
427  }
428  }
429  else if(mImGray.channels()==4)
430  {
431  if(mbRGB)
432  {
433  cvtColor(mImGray,mImGray,CV_RGBA2GRAY);
434  }
435  else
436  {
437  cvtColor(mImGray,mImGray,CV_BGRA2GRAY);
438  }
439  }
440  if(imGrayRight.channels()==3)
441  {
442  if(mbRGB)
443  {
444  cvtColor(imGrayRight,imGrayRight,CV_RGB2GRAY);
445  }
446  else
447  {
448  cvtColor(imGrayRight,imGrayRight,CV_BGR2GRAY);
449  }
450  }
451  else if(imGrayRight.channels()==4)
452  {
453  if(mbRGB)
454  {
455  cvtColor(imGrayRight,imGrayRight,CV_RGBA2GRAY);
456  }
457  else
458  {
459  cvtColor(imGrayRight,imGrayRight,CV_BGRA2GRAY);
460  }
461  }
462 
463  mCurrentFrame = Frame(mImGray,imGrayRight,timestamp,mpORBextractorLeft,mpORBextractorRight,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth);
464 
465  Track();
466 
467  return mCurrentFrame.mTcw.clone();
468  }
469 
470  cv::Mat GrabImageRGBD(const cv::Mat &imRGB,const cv::Mat &imD, const double &timestamp)
471  {
472  mImGray = imRGB;
473  cv::Mat imDepth = imD;
474 
475  if(mImGray.channels()==3)
476  {
477  if(mbRGB)
478  cvtColor(mImGray,mImGray,CV_RGB2GRAY);
479  else
480  cvtColor(mImGray,mImGray,CV_BGR2GRAY);
481  }
482  else if(mImGray.channels()==4)
483  {
484  if(mbRGB)
485  cvtColor(mImGray,mImGray,CV_RGBA2GRAY);
486  else
487  cvtColor(mImGray,mImGray,CV_BGRA2GRAY);
488  }
489 
490  UASSERT(imDepth.type()==CV_32F);
491 
492  mCurrentFrame = Frame(mImGray,imDepth,timestamp,mpORBextractorLeft,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth);
493 
494  Track();
495 
496  return mCurrentFrame.mTcw.clone();
497  }
498 };
499 
500 // Hack to disable loop closing
501 class LoopCloser: public LoopClosing
502 {
503 public:
504  LoopCloser(Map* pMap, KeyFrameDatabase* pDB, ORBVocabulary* pVoc,const bool bFixScale) :
505  LoopClosing(pMap, pDB, pVoc, bFixScale)
506  {
507  }
508 
509 public:
510  void RunNoLoop()
511  {
512  mbFinished =false;
513 
514  while(1)
515  {
516  // just clear the buffer
517  {
518  unique_lock<mutex> lock(mMutexLoopQueue);
519  mlpLoopKeyFrameQueue.clear();
520  }
521 
522  ResetIfRequested();
523 
524  if(CheckFinish())
525  break;
526 
527  usleep(1000000); // 1 sec
528  }
529 
530  SetFinish();
531  }
532 };
533 
534 } // namespace ORB_SLAM2
535 
536 class ORBSLAM2System
537 {
538 public:
539  ORBSLAM2System(const rtabmap::ParametersMap & parameters) :
540  mpVocabulary(0),
541  mpKeyFrameDatabase(0),
542  mpMap(0),
543  mpTracker(0),
544  mpLocalMapper(0),
545  mpLoopCloser(0),
546  mptLocalMapping(0),
547  mptLoopClosing(0),
548  parameters_(parameters)
549  {
550  std::string vocabularyPath;
551  rtabmap::Parameters::parse(parameters, rtabmap::Parameters::kOdomORBSLAM2VocPath(), vocabularyPath);
552 
553  if(!vocabularyPath.empty())
554  {
555  //Load ORB Vocabulary
556  vocabularyPath = uReplaceChar(vocabularyPath, '~', UDirectory::homeDir());
557  UWARN("Loading ORB Vocabulary: \"%s\". This could take a while...", vocabularyPath.c_str());
558  mpVocabulary = new ORB_SLAM2::ORBVocabulary();
559  bool bVocLoad = mpVocabulary->loadFromTextFile(vocabularyPath);
560  if(!bVocLoad)
561  {
562  UERROR("Failed to open vocabulary at %s", vocabularyPath.c_str());
563  delete mpVocabulary;
564  mpVocabulary = 0;
565  }
566  else
567  {
568  UWARN("Vocabulary loaded!");
569  }
570  }
571  else
572  {
573  UERROR("ORBSLAM2 vocabulary path should be set! (Parameter name=\"%s\")", rtabmap::Parameters::kOdomORBSLAM2VocPath().c_str());
574  }
575  }
576 
577  bool init(const rtabmap::CameraModel & model, bool stereo, double baseline)
578  {
579  if(!mpVocabulary)
580  {
581  UERROR("Vocabulary not loaded!");
582  return false;
583  }
584 
585  this->shutdown();
586 
587  // Create configuration file
588  std::string workingDir;
589  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kRtabmapWorkingDirectory(), workingDir);
590  if(workingDir.empty())
591  {
592  workingDir = ".";
593  }
594  std::string configPath = workingDir+"/rtabmap_orbslam2.yaml";
595  std::ofstream ofs (configPath, std::ofstream::out);
596  ofs << "%YAML:1.0" << std::endl;
597  ofs << std::endl;
598 
599  //# Camera calibration and distortion parameters (OpenCV)
600  ofs << "Camera.fx: " << model.fx() << std::endl;
601  ofs << "Camera.fy: " << model.fy() << std::endl;
602  ofs << "Camera.cx: " << model.cx() << std::endl;
603  ofs << "Camera.cy: " << model.cy() << std::endl;
604  ofs << std::endl;
605 
606  if(model.D().cols < 4)
607  {
608  ofs << "Camera.k1: " << 0 << std::endl;
609  ofs << "Camera.k2: " << 0 << std::endl;
610  ofs << "Camera.p1: " << 0 << std::endl;
611  ofs << "Camera.p2: " << 0 << std::endl;
612  if(!stereo)
613  {
614  ofs << "Camera.k3: " << 0 << std::endl;
615  }
616  }
617  if(model.D().cols >= 4)
618  {
619  ofs << "Camera.k1: " << model.D().at<double>(0,0) << std::endl;
620  ofs << "Camera.k2: " << model.D().at<double>(0,1) << std::endl;
621  ofs << "Camera.p1: " << model.D().at<double>(0,2) << std::endl;
622  ofs << "Camera.p2: " << model.D().at<double>(0,3) << std::endl;
623  }
624  if(model.D().cols >= 5)
625  {
626  ofs << "Camera.k3: " << model.D().at<double>(0,4) << std::endl;
627  }
628  if(model.D().cols > 5)
629  {
630  UWARN("Unhandled camera distortion size %d, only 5 first coefficients used", model.D().cols);
631  }
632  ofs << std::endl;
633 
634  ofs << "Camera.width: " << model.imageWidth() << std::endl;
635  ofs << "Camera.height: " << model.imageHeight() << std::endl;
636  ofs << std::endl;
637 
638  //# IR projector baseline times fx (aprox.)
639  if(baseline <= 0.0)
640  {
641  baseline = rtabmap::Parameters::defaultOdomORBSLAM2Bf();
642  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAM2Bf(), baseline);
643  }
644  ofs << "Camera.bf: " << model.fx()*baseline << std::endl;
645  ofs << std::endl;
646 
647  //# Color order of the images (0: BGR, 1: RGB. It is ignored if images are grayscale)
648  //Camera.RGB: 1
649  ofs << "Camera.RGB: 1" << std::endl;
650  ofs << std::endl;
651 
652  float fps = rtabmap::Parameters::defaultOdomORBSLAM2Fps();
653  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAM2Fps(), fps);
654  ofs << "Camera.fps: " << fps << std::endl;
655  ofs << std::endl;
656 
657  //# Close/Far threshold. Baseline times.
658  double thDepth = rtabmap::Parameters::defaultOdomORBSLAM2ThDepth();
659  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAM2ThDepth(), thDepth);
660  ofs << "ThDepth: " << thDepth << std::endl;
661  ofs << std::endl;
662 
663  //# Deptmap values factor
664  ofs << "DepthMapFactor: " << 1000.0 << std::endl;
665  ofs << std::endl;
666 
667  //#--------------------------------------------------------------------------------------------
668  //# ORB Parameters
669  //#--------------------------------------------------------------------------------------------
670  //# ORB Extractor: Number of features per image
671  int features = rtabmap::Parameters::defaultOdomORBSLAM2MaxFeatures();
672  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAM2MaxFeatures(), features);
673  ofs << "ORBextractor.nFeatures: " << features << std::endl;
674  ofs << std::endl;
675 
676  //# ORB Extractor: Scale factor between levels in the scale pyramid
677  double scaleFactor = rtabmap::Parameters::defaultORBScaleFactor();
678  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kORBScaleFactor(), scaleFactor);
679  ofs << "ORBextractor.scaleFactor: " << scaleFactor << std::endl;
680  ofs << std::endl;
681 
682  //# ORB Extractor: Number of levels in the scale pyramid
683  int levels = rtabmap::Parameters::defaultORBNLevels();
684  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kORBNLevels(), levels);
685  ofs << "ORBextractor.nLevels: " << levels << std::endl;
686  ofs << std::endl;
687 
688  //# ORB Extractor: Fast threshold
689  //# Image is divided in a grid. At each cell FAST are extracted imposing a minimum response.
690  //# Firstly we impose iniThFAST. If no corners are detected we impose a lower value minThFAST
691  //# You can lower these values if your images have low contrast
692  int iniThFAST = rtabmap::Parameters::defaultFASTThreshold();
693  int minThFAST = rtabmap::Parameters::defaultFASTMinThreshold();
694  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kFASTThreshold(), iniThFAST);
695  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kFASTMinThreshold(), minThFAST);
696  ofs << "ORBextractor.iniThFAST: " << iniThFAST << std::endl;
697  ofs << "ORBextractor.minThFAST: " << minThFAST << std::endl;
698  ofs << std::endl;
699 
700  int maxFeatureMapSize = rtabmap::Parameters::defaultOdomORBSLAM2MapSize();
701  rtabmap::Parameters::parse(parameters_, rtabmap::Parameters::kOdomORBSLAM2MapSize(), maxFeatureMapSize);
702 
703  ofs.close();
704 
705  //Create KeyFrame Database
706  mpKeyFrameDatabase = new ORB_SLAM2::KeyFrameDatabase(*mpVocabulary);
707 
708  //Create the Map
709  mpMap = new ORB_SLAM2::Map();
710 
711  //Initialize the Tracking thread
712  //(it will live in the main thread of execution, the one that called this constructor)
713  mpTracker = new ORB_SLAM2::Tracker(0, mpVocabulary, 0, 0, mpMap, mpKeyFrameDatabase, configPath, stereo?ORB_SLAM2::System::STEREO:ORB_SLAM2::System::RGBD, maxFeatureMapSize);
714 
715  //Initialize the Local Mapping thread and launch
716  mpLocalMapper = new ORB_SLAM2::LocalMapping(mpMap, false);
717 
718  //Initialize the Loop Closing thread and launch
719  mpLoopCloser = new ORB_SLAM2::LoopCloser(mpMap, mpKeyFrameDatabase, mpVocabulary, true);
720 
721  mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run, mpLocalMapper);
722  mptLoopClosing = new thread(&ORB_SLAM2::LoopCloser::RunNoLoop, mpLoopCloser);
723 
724  //Set pointers between threads
725  mpTracker->SetLocalMapper(mpLocalMapper);
726  mpTracker->SetLoopClosing(mpLoopCloser);
727  mpTracker->SetViewer(0);
728 
729  mpLocalMapper->SetTracker(mpTracker);
730  mpLocalMapper->SetLoopCloser(mpLoopCloser);
731 
732  mpLoopCloser->SetTracker(mpTracker);
733  mpLoopCloser->SetLocalMapper(mpLocalMapper);
734 
735  return true;
736  }
737 
738  virtual ~ORBSLAM2System()
739  {
740  shutdown();
741  delete mpVocabulary;
742  }
743 
744  void shutdown()
745  {
746  if(mpMap)
747  {
748  mpLocalMapper->RequestFinish();
749  mpLoopCloser->RequestFinish();
750 
751  // Wait until all thread have effectively stopped
752  while(!mpLocalMapper->isFinished() || !mpLoopCloser->isFinished() || mpLoopCloser->isRunningGBA())
753  {
754  usleep(5000);
755  }
756 
757  //cleanup!
758  mptLoopClosing->join();
759  delete mptLoopClosing;
760  mptLoopClosing = 0;
761  mptLocalMapping->join();
762  delete mptLocalMapping;
763  mptLocalMapping = 0;
764  delete mpLoopCloser;
765  mpLoopCloser=0;
766  delete mpLocalMapper;
767  mpLocalMapper=0;
768  delete mpTracker;
769  mpTracker=0;
770  delete mpMap;
771  mpMap=0;
772  delete mpKeyFrameDatabase;
773  mpKeyFrameDatabase=0;
774  }
775  }
776 
777 public:
778  // ORB vocabulary used for place recognition and feature matching.
779  ORB_SLAM2::ORBVocabulary* mpVocabulary;
780 
781  // KeyFrame database for place recognition (relocalization and loop detection).
782  ORB_SLAM2::KeyFrameDatabase* mpKeyFrameDatabase;
783 
784  // Map structure that stores the pointers to all KeyFrames and MapPoints.
785  ORB_SLAM2::Map* mpMap;
786 
787  // Tracker. It receives a frame and computes the associated camera pose.
788  // It also decides when to insert a new keyframe, create some new MapPoints and
789  // performs relocalization if tracking fails.
790  ORB_SLAM2::Tracker* mpTracker;
791 
792  // Local Mapper. It manages the local map and performs local bundle adjustment.
793  ORB_SLAM2::LocalMapping* mpLocalMapper;
794 
795  // Loop Closer. It searches loops with every new keyframe. If there is a loop it performs
796  // a pose graph optimization and full bundle adjustment (in a new thread) afterwards.
797  ORB_SLAM2::LoopCloser* mpLoopCloser;
798 
799  // System threads: Local Mapping, Loop Closing, Viewer.
800  // The Tracking thread "lives" in the main execution thread that creates the System object.
801  std::thread* mptLocalMapping;
802  std::thread* mptLoopClosing;
803 
804  rtabmap::ParametersMap parameters_;
805 };
806 #endif
807 
808 namespace rtabmap {
809 
810 OdometryORBSLAM2::OdometryORBSLAM2(const ParametersMap & parameters) :
811  Odometry(parameters)
812 #ifdef RTABMAP_ORB_SLAM2
813  ,
814  orbslam2_(0),
815  firstFrame_(true),
816  previousPose_(Transform::getIdentity())
817 #endif
818 {
819 #ifdef RTABMAP_ORB_SLAM2
820  orbslam2_ = new ORBSLAM2System(parameters);
821 #endif
822 }
823 
825 {
826 #ifdef RTABMAP_ORB_SLAM2
827  if(orbslam2_)
828  {
829  delete orbslam2_;
830  }
831 #endif
832 }
833 
834 void OdometryORBSLAM2::reset(const Transform & initialPose)
835 {
836  Odometry::reset(initialPose);
837 #ifdef RTABMAP_ORB_SLAM2
838  if(orbslam2_)
839  {
840  orbslam2_->shutdown();
841  }
842  firstFrame_ = true;
843  originLocalTransform_.setNull();
844  previousPose_.setIdentity();
845 #endif
846 }
847 
848 // return not null transform if odometry is correctly computed
850  SensorData & data,
851  const Transform & guess,
852  OdometryInfo * info)
853 {
854  Transform t;
855 
856 #ifdef RTABMAP_ORB_SLAM2
857  UTimer timer;
858 
859  if(data.imageRaw().empty() ||
860  data.imageRaw().rows != data.depthOrRightRaw().rows ||
861  data.imageRaw().cols != data.depthOrRightRaw().cols)
862  {
863  UERROR("Not supported input! RGB (%dx%d) and depth (%dx%d) should have the same size.",
864  data.imageRaw().cols, data.imageRaw().rows, data.depthOrRightRaw().cols, data.depthOrRightRaw().rows);
865  return t;
866  }
867 
868  if(!((data.cameraModels().size() == 1 &&
869  data.cameraModels()[0].isValidForReprojection()) ||
873  {
874  UERROR("Invalid camera model!");
875  return t;
876  }
877 
878  bool stereo = data.cameraModels().size() == 0;
879 
880  cv::Mat covariance;
881  if(orbslam2_->mpTracker == 0)
882  {
883  CameraModel model = data.cameraModels().size()==1?data.cameraModels()[0]:data.stereoCameraModel().left();
884  if(!orbslam2_->init(model, stereo, data.stereoCameraModel().baseline()))
885  {
886  return t;
887  }
888  }
889 
890  cv::Mat Tcw;
891  Transform localTransform;
892  if(stereo)
893  {
894  localTransform = data.stereoCameraModel().localTransform();
895  Tcw = ((ORB_SLAM2::Tracker*)orbslam2_->mpTracker)->GrabImageStereo(data.imageRaw(), data.rightRaw(), data.stamp());
896  }
897  else
898  {
899  localTransform = data.cameraModels()[0].localTransform();
900  cv::Mat depth;
901  if(data.depthRaw().type() == CV_32FC1)
902  {
903  depth = data.depthRaw();
904  }
905  else if(data.depthRaw().type() == CV_16UC1)
906  {
907  depth = util2d::cvtDepthToFloat(data.depthRaw());
908  }
909  Tcw = ((ORB_SLAM2::Tracker*)orbslam2_->mpTracker)->GrabImageRGBD(data.imageRaw(), depth, data.stamp());
910  }
911 
912  Transform previousPoseInv = previousPose_.inverse();
913  if(orbslam2_->mpTracker->mState == ORB_SLAM2::Tracking::LOST)
914  {
915  covariance = cv::Mat::eye(6,6,CV_64FC1)*9999.0f;
916  }
917  else if(Tcw.cols == 4 && Tcw.rows == 4)
918  {
919  Transform p = Transform(cv::Mat(Tcw, cv::Range(0,3), cv::Range(0,4)));
920 
921  if(!p.isNull())
922  {
923  if(!localTransform.isNull())
924  {
925  if(originLocalTransform_.isNull())
926  {
927  originLocalTransform_ = localTransform;
928  }
929  // transform in base frame
930  p = originLocalTransform_ * p.inverse() * localTransform.inverse();
931  }
932  t = previousPoseInv*p;
933  }
934  previousPose_ = p;
935 
936  if(firstFrame_)
937  {
938  // just recovered of being lost, set high covariance
939  covariance = cv::Mat::eye(6,6,CV_64FC1)*9999.0f;
940  firstFrame_ = false;
941  }
942  else
943  {
944  float baseline = data.stereoCameraModel().baseline();
945  if(baseline <= 0.0f)
946  {
947  baseline = rtabmap::Parameters::defaultOdomORBSLAM2Bf();
948  rtabmap::Parameters::parse(orbslam2_->parameters_, rtabmap::Parameters::kOdomORBSLAM2Bf(), baseline);
949  }
950  double linearVar = 0.0001;
951  if(baseline > 0.0f)
952  {
953  linearVar = baseline/8.0;
954  linearVar *= linearVar;
955  }
956 
957  covariance = cv::Mat::eye(6,6, CV_64FC1);
958  covariance.at<double>(0,0) = linearVar;
959  covariance.at<double>(1,1) = linearVar;
960  covariance.at<double>(2,2) = linearVar;
961  covariance.at<double>(3,3) = 0.0001;
962  covariance.at<double>(4,4) = 0.0001;
963  covariance.at<double>(5,5) = 0.0001;
964  }
965  }
966 
967  int totalMapPoints= 0;
968  int totalKfs= 0;
969  if(orbslam2_->mpMap)
970  {
971  totalMapPoints = orbslam2_->mpMap->MapPointsInMap();
972  totalKfs = orbslam2_->mpMap->KeyFramesInMap();
973  }
974 
975  if(info)
976  {
977  info->lost = t.isNull();
978  info->type = (int)kTypeORBSLAM2;
979  info->reg.covariance = covariance;
980  info->localMapSize = totalMapPoints;
981  info->localKeyFrames = totalKfs;
982 
983  if(this->isInfoDataFilled() && orbslam2_->mpTracker && orbslam2_->mpMap)
984  {
985  const std::vector<cv::KeyPoint> & kpts = orbslam2_->mpTracker->mCurrentFrame.mvKeys;
986  info->reg.matchesIDs.resize(kpts.size());
987  info->reg.inliersIDs.resize(kpts.size());
988  int oi = 0;
989  for (unsigned int i = 0; i < kpts.size(); ++i)
990  {
991  int wordId;
992  if(orbslam2_->mpTracker->mCurrentFrame.mvpMapPoints[i] != 0)
993  {
994  wordId = orbslam2_->mpTracker->mCurrentFrame.mvpMapPoints[i]->mnId;
995  }
996  else
997  {
998  wordId = -(i+1);
999  }
1000  info->words.insert(std::make_pair(wordId, kpts[i]));
1001  if(orbslam2_->mpTracker->mCurrentFrame.mvpMapPoints[i] != 0)
1002  {
1003  info->reg.matchesIDs[oi] = wordId;
1004  info->reg.inliersIDs[oi] = wordId;
1005  ++oi;
1006  }
1007  }
1008  info->reg.matchesIDs.resize(oi);
1009  info->reg.inliersIDs.resize(oi);
1010  info->reg.inliers = oi;
1011  info->reg.matches = oi;
1012 
1013  std::vector<ORB_SLAM2::MapPoint*> mapPoints = orbslam2_->mpMap->GetAllMapPoints();
1014  Eigen::Affine3f fixRot = (this->getPose()*previousPoseInv*originLocalTransform_).toEigen3f();
1015  for (unsigned int i = 0; i < mapPoints.size(); ++i)
1016  {
1017  cv::Point3f pt(mapPoints[i]->GetWorldPos());
1018  pcl::PointXYZ ptt = pcl::transformPoint(pcl::PointXYZ(pt.x, pt.y, pt.z), fixRot);
1019  info->localMap.insert(std::make_pair(mapPoints[i]->mnId, cv::Point3f(ptt.x, ptt.y, ptt.z)));
1020  }
1021  }
1022  }
1023 
1024  UINFO("Odom update time = %fs, map points=%d, keyframes=%d, lost=%s", timer.elapsed(), totalMapPoints, totalKfs, t.isNull()?"true":"false");
1025 
1026 #else
1027  UERROR("RTAB-Map is not built with ORB_SLAM2 support! Select another visual odometry approach.");
1028 #endif
1029  return t;
1030 }
1031 
1032 } // namespace rtabmap
static std::string homeDir()
Definition: UDirectory.cpp:355
#define NULL
int imageWidth() const
Definition: CameraModel.h:120
static bool parse(const ParametersMap &parameters, const std::string &key, bool &value)
Definition: Parameters.cpp:476
Definition: UTimer.h:46
cv::Mat RTABMAP_EXP cvtDepthToFloat(const cv::Mat &depth16U)
Definition: util2d.cpp:928
cv::Point3f RTABMAP_EXP transformPoint(const cv::Point3f &pt, const Transform &transform)
double elapsed()
Definition: UTimer.h:75
f
bool isInfoDataFilled() const
Definition: Odometry.h:74
virtual void reset(const Transform &initialPose=Transform::getIdentity())
Definition: Odometry.cpp:191
virtual void reset(const Transform &initialPose=Transform::getIdentity())
def init(descriptorDim, matchThreshold, iterations, cuda, model_path)
std::map< int, cv::Point3f > localMap
Definition: OdometryInfo.h:124
std::map< std::string, std::string > ParametersMap
Definition: Parameters.h:43
const Transform & getPose() const
Definition: Odometry.h:73
std::vector< int > inliersIDs
const cv::Mat & imageRaw() const
Definition: SensorData.h:164
cv::Mat rightRaw() const
Definition: SensorData.h:190
cv::Mat D() const
Definition: CameraModel.h:111
#define UASSERT(condition)
Wrappers of STL for convenient functions.
const CameraModel & left() const
double cx() const
Definition: CameraModel.h:104
#define true
Definition: ConvertUTF.c:57
bool isNull() const
Definition: Transform.cpp:107
CvImagePtr cvtColor(const CvImageConstPtr &source, const std::string &encoding)
double fy() const
Definition: CameraModel.h:103
std::string UTILITE_EXP uReplaceChar(const std::string &str, char before, char after)
Definition: UConversion.cpp:32
const cv::Mat & depthOrRightRaw() const
Definition: SensorData.h:165
bool isValidForReprojection() const
Definition: CameraModel.h:88
double stamp() const
Definition: SensorData.h:157
double cy() const
Definition: CameraModel.h:105
const std::vector< CameraModel > & cameraModels() const
Definition: SensorData.h:215
double fx() const
Definition: CameraModel.h:102
std::multimap< int, cv::KeyPoint > words
Definition: OdometryInfo.h:123
const CameraModel & right() const
ROSCONSOLE_DECL void shutdown()
#define UERROR(...)
ULogger class and convenient macros.
const StereoCameraModel & stereoCameraModel() const
Definition: SensorData.h:216
#define UWARN(...)
std::vector< int > matchesIDs
virtual Transform computeTransform(SensorData &image, const Transform &guess=Transform(), OdometryInfo *info=0)
RegistrationInfo reg
Definition: OdometryInfo.h:96
Transform inverse() const
Definition: Transform.cpp:178
const Transform & localTransform() const
int imageHeight() const
Definition: CameraModel.h:121
cv::Mat depthRaw() const
Definition: SensorData.h:189
#define UINFO(...)


rtabmap
Author(s): Mathieu Labbe
autogenerated on Mon Dec 14 2020 03:34:59