Advertisement

ORB-SLAM2源码解读(1):系统入口System

阅读量:
image

先要拿大名鼎鼎的ORB-SLAM系统框图镇楼,看着这张图能够完美的串起来整个流程。

ORB-SLAM分三个线程,分别是Tracking、LocalMapping和LoopClosing。

(1)Tracking:在主线程上,输入视频流,输出相机位姿并跟踪局部地图。提取ORB特征子,根据上一帧进行位姿估计或全局重定位,然后跟踪局部地图优化位姿,确定新的关键帧。

(2)LocalMapping:维护优化局部地图。输入关键帧,输出修正的关键帧和地图点。插入关键帧,生成新的地图点,使用BA优化,去除冗余的关键帧

(3)LoopClosing:闭环检测和闭环矫正。BOW检测,再用Sim3计算相似变换;闭环融合与优化Essential Graph的图优化。
è¿éåå¾çæè¿°


复制代码
 #ifndef SYSTEM_H

    
 #define SYSTEM_H
    
  
    
 #include<string>
    
 #include<thread>
    
 #include<opencv2/core/core.hpp>
    
  
    
 #include "Tracking.h"
    
 #include "FrameDrawer.h"
    
 #include "MapDrawer.h"
    
 #include "Map.h"
    
 #include "LocalMapping.h"
    
 #include "LoopClosing.h"
    
 #include "KeyFrameDatabase.h"
    
 #include "ORBVocabulary.h"
    
 #include "Viewer.h"
    
  
    
 namespace ORB_SLAM2
    
 {
    
  
    
 class Viewer;
    
 class FrameDrawer;
    
 class Map;
    
 class Tracking;
    
 class LocalMapping;
    
 class LoopClosing;
    
  
    
 class System
    
 {
    
 public:
    
     // 三种传感器选择
    
     enum eSensor{
    
     MONOCULAR=0,
    
     STEREO=1,
    
     RGBD=2
    
     };
    
 	//成员函数
    
 public:
    
     // 声明
    
     System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor, const bool bUseViewer = true);
    
  
    
     // Tracking函数:输出相机位姿
    
     cv::Mat TrackStereo(const cv::Mat &imLeft, const cv::Mat &imRight, const double &timestamp);
    
     cv::Mat TrackRGBD(const cv::Mat &im, const cv::Mat &depthmap, const double &timestamp);
    
     cv::Mat TrackMonocular(const cv::Mat &im, const double &timestamp);
    
  
    
     // 激活定位模块;停止Local Mapping,只相机追踪???
    
     void ActivateLocalizationMode();
    
     // 失效定位模块;恢复Local Mapping,再次执行SLAM???
    
     void DeactivateLocalizationMode();
    
     // 清空地图,重启系统
    
     void Reset();
    
     // 保存轨迹之前执行
    
     void Shutdown();
    
     // 保存相机轨迹 Only stereo and RGB-D. 
    
     // Call first Shutdown()
    
     // See format details at: http://vision.in.tum.de/data/datasets/rgbd-dataset
    
     void SaveTrajectoryTUM(const string &filename);
    
 	// See format details at: http://www.cvlibs.net/datasets/kitti/eval_odometry.php
    
 	void SaveTrajectoryKITTI(const string &filename);
    
     // 保存关键帧位姿 
    
     // Call first Shutdown()
    
     // See format details at: http://vision.in.tum.de/data/datasets/rgbd-dataset
    
     void SaveKeyFrameTrajectoryTUM(const string &filename);
    
  
    
 	//成员变量
    
 private:
    
     // Input sensor
    
     eSensor mSensor;
    
  
    
     // ORB词汇表用于场景识别和特征匹配
    
     ORBVocabulary* mpVocabulary;
    
  
    
     // 关键帧数据库用于位置识别 (重定位和回环检测).
    
     KeyFrameDatabase* mpKeyFrameDatabase;
    
  
    
     // 存储关键帧和地图特征子
    
     Map* mpMap;
    
  
    
     // Tracker. 接受帧计算相机位姿
    
     // 决定何时插入新的关键帧,创建新的地图特征子
    
     // 重定位
    
     Tracking* mpTracker;
    
     // Local Mapper.管理本地地图,执行BA
    
     LocalMapping* mpLocalMapper;
    
     // Loop Closer. 搜索每个新的关键帧的循环
    
     LoopClosing* mpLoopCloser;
    
     // Pangolin.绘制地图和当前相机位姿
    
     Viewer* mpViewer;
    
 	// 画图用的
    
     FrameDrawer* mpFrameDrawer;
    
     MapDrawer* mpMapDrawer;
    
  
    
     // 3个线程: Local Mapping, Loop Closing, Viewer.
    
     // Tracking线程在System主程序线程中
    
     std::thread* mptLocalMapping;
    
     std::thread* mptLoopClosing;
    
     std::thread* mptViewer;
    
  
    
     // 重置Flag???
    
     std::mutex mMutexReset;
    
     bool mbReset;
    
  
    
     //更改模型flags
    
     std::mutex mMutexMode;
    
     bool mbActivateLocalizationMode;
    
     bool mbDeactivateLocalizationMode;
    
 };
    
  
    
 }// namespace ORB_SLAM
    
  
    
 #endif // SYSTEM_H

复制代码
 #include "System.h"

    
 #include "Converter.h"
    
 #include <thread>
    
 #include <pangolin/pangolin.h>
    
 #include <iostream>     // std::cout, std::fixed
    
 #include <iomanip>		// std::setprecision
    
 bool has_suffix(const std::string &str, const std::string &suffix) {
    
   std::size_t index = str.find(suffix, str.size() - suffix.size());
    
   return (index != std::string::npos);
    
 }
    
  
    
 namespace ORB_SLAM2
    
 {
    
 	//列表初始化构造函数:词袋文件、参数文件、传感器类型、是否用Viewer
    
 System::System(const string &strVocFile, const string &strSettingsFile, const eSensor sensor,
    
            const bool bUseViewer):mSensor(sensor),mbReset(false),mbActivateLocalizationMode(false),
    
            mbDeactivateLocalizationMode(false)
    
 {
    
     // Output welcome message
    
     cout << endl <<
    
     "ORB-SLAM2 Copyright (C) 2014-2016 Raul Mur-Artal, University of Zaragoza." << endl <<
    
     "This program comes with ABSOLUTELY NO WARRANTY;" << endl  <<
    
     "This is free software, and you are welcome to redistribute it" << endl <<
    
     "under certain conditions. See LICENSE.txt." << endl << endl;
    
  
    
     cout << "Input sensor was set to: ";
    
  
    
     if(mSensor==MONOCULAR)
    
     cout << "Monocular" << endl;
    
     else if(mSensor==STEREO)
    
     cout << "Stereo" << endl;
    
     else if(mSensor==RGBD)
    
     cout << "RGB-D" << endl;
    
  
    
     //1.读取参数文件,内参、帧率、基线、深度, XXX.yaml
    
     cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);
    
     if(!fsSettings.isOpened())
    
     {
    
    cerr << "Failed to open settings file at: " << strSettingsFile << endl;
    
    exit(-1);
    
     }
    
  
    
     //2.下载ORB词袋  .txt
    
     cout << endl << "Loading ORB Vocabulary. This could take a while..." << endl;
    
     mpVocabulary = new ORBVocabulary();//这个词袋类在哪里定义的???
    
     bool bVocLoad = false; // 基于扩展名加载
    
     if (has_suffix(strVocFile, ".txt"))
    
 	  bVocLoad = mpVocabulary->loadFromTextFile(strVocFile);
    
 	else if(has_suffix(strVocFile, ".bin"))
    
 	  bVocLoad = mpVocabulary->loadFromBinaryFile(strVocFile);
    
 	else
    
 	  bVocLoad = false;
    
     if(!bVocLoad)
    
     {
    
     cerr << "Wrong path to vocabulary. " << endl;
    
     cerr << "Failed to open at: " << strVocFile << endl;
    
     exit(-1);
    
     }
    
     cout << "Vocabulary loaded!" << endl << endl;
    
  
    
     //3.创建关键帧数据库
    
     mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);
    
  
    
     //4.创建地图
    
     mpMap = new Map();
    
  
    
     //Create Drawers.
    
     mpFrameDrawer = new FrameDrawer(mpMap);
    
     mpMapDrawer = new MapDrawer(mpMap, strSettingsFile);
    
  
    
     //5.1初始化 Tracking 
    
     //(it will live in the main thread of execution, the one that called this constructor)
    
     mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer,
    
                          mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);
    
  
    
     //5.2初始化并发布 Local Mapping 线程
    
     mpLocalMapper = new LocalMapping(mpMap, mSensor==MONOCULAR);
    
     mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run,mpLocalMapper);
    
  
    
     //5.3初始化并发布 Loop Closing 线程
    
     mpLoopCloser = new LoopClosing(mpMap, mpKeyFrameDatabase, mpVocabulary, mSensor!=MONOCULAR);
    
     mptLoopClosing = new thread(&ORB_SLAM2::LoopClosing::Run, mpLoopCloser);
    
  
    
     //5.4初始化并发布 Viewer 线程
    
     mpViewer = new Viewer(this, mpFrameDrawer,mpMapDrawer,mpTracker,strSettingsFile);
    
     if(bUseViewer)
    
     mptViewer = new thread(&Viewer::Run, mpViewer);
    
  
    
     mpTracker->SetViewer(mpViewer);
    
  
    
     //5.5线程之间相互设置指针???
    
     mpTracker->SetLocalMapper(mpLocalMapper);
    
     mpTracker->SetLoopClosing(mpLoopCloser);
    
  
    
     mpLocalMapper->SetTracker(mpTracker);
    
     mpLocalMapper->SetLoopCloser(mpLoopCloser);
    
  
    
     mpLoopCloser->SetTracker(mpTracker);
    
     mpLoopCloser->SetLocalMapper(mpLocalMapper);
    
 }
    
  
    
 cv::Mat System::TrackStereo(const cv::Mat &imLeft, const cv::Mat &imRight, const double &timestamp)
    
 {
    
     if(mSensor!=STEREO)
    
     {
    
     cerr << "ERROR: you called TrackStereo but input sensor was not set to STEREO." << endl;
    
     exit(-1);
    
     }   
    
  
    
     // Check mode change
    
     {
    
     unique_lock<mutex> lock(mMutexMode);
    
     if(mbActivateLocalizationMode)
    
     {
    
         mpLocalMapper->RequestStop();
    
  
    
         // Wait until Local Mapping has effectively stopped
    
         while(!mpLocalMapper->isStopped())
    
         {
    
             //usleep(1000);
    
 				std::this_thread::sleep_for(std::chrono::milliseconds(1));
    
         }
    
  
    
         mpTracker->InformOnlyTracking(true);// 定位时,只跟踪
    
         mbActivateLocalizationMode = false;
    
     }
    
     if(mbDeactivateLocalizationMode)
    
     {
    
         mpTracker->InformOnlyTracking(false);
    
         mpLocalMapper->Release();
    
         mbDeactivateLocalizationMode = false;
    
     }
    
     }
    
  
    
     // Check reset
    
     {
    
     unique_lock<mutex> lock(mMutexReset);
    
     if(mbReset)
    
     {
    
     mpTracker->Reset();
    
     mbReset = false;
    
     }
    
     }
    
  
    
     return mpTracker->GrabImageStereo(imLeft,imRight,timestamp);
    
 }
    
  
    
 cv::Mat System::TrackRGBD(const cv::Mat &im, const cv::Mat &depthmap, const double &timestamp)
    
 {
    
     if(mSensor!=RGBD)
    
     {
    
     cerr << "ERROR: you called TrackRGBD but input sensor was not set to RGBD." << endl;
    
     exit(-1);
    
     }    
    
  
    
     // Check mode change
    
     {
    
     unique_lock<mutex> lock(mMutexMode);
    
     if(mbActivateLocalizationMode)
    
     {
    
         mpLocalMapper->RequestStop();
    
  
    
         // Wait until Local Mapping has effectively stopped
    
         while(!mpLocalMapper->isStopped())
    
         {
    
             //usleep(1000);
    
 				std::this_thread::sleep_for(std::chrono::milliseconds(1));
    
 			}
    
  
    
         mpTracker->InformOnlyTracking(true);// 定位时,只跟踪
    
         mbActivateLocalizationMode = false;
    
     }
    
     if(mbDeactivateLocalizationMode)
    
     {
    
         mpTracker->InformOnlyTracking(false);
    
         mpLocalMapper->Release();
    
         mbDeactivateLocalizationMode = false;
    
     }
    
     }
    
  
    
     // Check reset
    
     {
    
     unique_lock<mutex> lock(mMutexReset);
    
     if(mbReset)
    
     {
    
     mpTracker->Reset();
    
     mbReset = false;
    
     }
    
     }
    
  
    
     return mpTracker->GrabImageRGBD(im,depthmap,timestamp);
    
 }
    
 //定义跟踪单目函数
    
 cv::Mat System::TrackMonocular(const cv::Mat &im, const double &timestamp)
    
 {
    
     if(mSensor!=MONOCULAR)
    
     {
    
     cerr << "ERROR: you called TrackMonocular but input sensor was not set to Monocular." << endl;
    
     exit(-1);
    
     }
    
  
    
     // 检查模型
    
     {
    
     unique_lock<mutex> lock(mMutexMode);
    
 		//如果激活定位模块,休眠1000ms直到停止建图
    
     if(mbActivateLocalizationMode)
    
     {
    
         mpLocalMapper->RequestStop();
    
         // Wait until Local Mapping has effectively stopped
    
         while(!mpLocalMapper->isStopped())
    
         {
    
             //usleep(1000);
    
             std::this_thread::sleep_for(std::chrono::milliseconds(1));
    
         }
    
  
    
         mpTracker->InformOnlyTracking(true);// 定位时,只跟踪
    
         mbActivateLocalizationMode = false;// 防止重复执行
    
     }
    
 		//如果定位模块失效,重启建图
    
     if(mbDeactivateLocalizationMode)
    
     {
    
         mpTracker->InformOnlyTracking(false);
    
         mpLocalMapper->Release();
    
         mbDeactivateLocalizationMode = false;// 防止重复执行
    
     }
    
     }
    
  
    
     // 检查重启
    
     {
    
     unique_lock<mutex> lock(mMutexReset);
    
     if(mbReset)
    
     {
    
         mpTracker->Reset();
    
         mbReset = false;
    
     }
    
     }
    
 	//这个Grab函数哪里来的???
    
     return mpTracker->GrabImageMonocular(im,timestamp);
    
 }
    
 //激活定位模块
    
 void System::ActivateLocalizationMode()
    
 {
    
     unique_lock<mutex> lock(mMutexMode);
    
     mbActivateLocalizationMode = true;
    
 }
    
 //失效定位模块
    
 void System::DeactivateLocalizationMode()
    
 {
    
 	//加锁
    
     unique_lock<mutex> lock(mMutexMode);
    
     mbDeactivateLocalizationMode = true;
    
 }
    
 //重置系统
    
 void System::Reset()
    
 {
    
     unique_lock<mutex> lock(mMutexReset);
    
     mbReset = true;
    
 }
    
 //关闭整个系统
    
 void System::Shutdown()
    
 {
    
     mpLocalMapper->RequestFinish();
    
     mpLoopCloser->RequestFinish();
    
     if(mpViewer)
    
     {
    
     mpViewer->RequestFinish();
    
     while(!mpViewer->isFinished())
    
         std::this_thread::sleep_for(std::chrono::milliseconds(5));
    
     }
    
  
    
     // Wait until all thread have effectively stopped
    
     while(!mpLocalMapper->isFinished() || !mpLoopCloser->isFinished() || mpLoopCloser->isRunningGBA())
    
     {
    
     //usleep(5000);
    
 		std::this_thread::sleep_for(std::chrono::milliseconds(5));
    
 	}
    
  
    
     if(mpViewer)
    
     pangolin::BindToContext("ORB-SLAM2: Map Viewer");
    
 }
    
 //保存轨迹
    
 void System::SaveTrajectoryTUM(const string &filename)
    
 {
    
     cout << endl << "Saving camera trajectory to " << filename << " ..." << endl;
    
     if(mSensor==MONOCULAR)
    
     {
    
     cerr << "ERROR: SaveTrajectoryTUM cannot be used for monocular." << endl;
    
     return;
    
     }
    
 	//得到所有关键帧,重新排序第一帧位于原点
    
     vector<KeyFrame*> vpKFs = mpMap->GetAllKeyFrames();
    
     sort(vpKFs.begin(),vpKFs.end(),KeyFrame::lId);
    
     cv::Mat Two = vpKFs[0]->GetPoseInverse();
    
  
    
     ofstream f;
    
     f.open(filename.c_str());
    
     f << fixed;
    
  
    
     // 先获得关键帧,当前帧相对于关键帧
    
 	//每一帧都有引用关键帧、时间戳和标志
    
     list<ORB_SLAM2::KeyFrame*>::iterator lRit = mpTracker->mlpReferences.begin();
    
     list<double>::iterator lT = mpTracker->mlFrameTimes.begin();
    
     list<bool>::iterator lbL = mpTracker->mlbLost.begin();
    
     for(list<cv::Mat>::iterator lit=mpTracker->mlRelativeFramePoses.begin(),
    
     lend=mpTracker->mlRelativeFramePoses.end();lit!=lend;lit++, lRit++, lT++, lbL++)
    
     {
    
     if(*lbL)
    
         continue;
    
  
    
     KeyFrame* pKF = *lRit;
    
  
    
     cv::Mat Trw = cv::Mat::eye(4,4,CV_32F);
    
  
    
     // 如果参考关键帧被剔除,遍历生成树获得合适关键帧
    
     while(pKF->isBad())
    
     {
    
         Trw = Trw*pKF->mTcp;
    
         pKF = pKF->GetParent();
    
     }
    
  
    
     Trw = Trw*pKF->GetPose()*Two;
    
  
    
     cv::Mat Tcw = (*lit)*Trw;
    
     cv::Mat Rwc = Tcw.rowRange(0,3).colRange(0,3).t();
    
     cv::Mat twc = -Rwc*Tcw.rowRange(0,3).col(3);
    
  
    
     vector<float> q = Converter::toQuaternion(Rwc);
    
  
    
     f << setprecision(6) << *lT << " " <<  setprecision(9) << twc.at<float>(0) << " " << twc.at<float>(1) << " " << twc.at<float>(2) << " " << q[0] << " " << q[1] << " " << q[2] << " " << q[3] << endl;
    
     }
    
     f.close();
    
     cout << endl << "trajectory saved!" << endl;
    
 }
    
  
    
  
    
 void System::SaveKeyFrameTrajectoryTUM(const string &filename)
    
 {
    
     cout << endl << "Saving keyframe trajectory to " << filename << " ..." << endl;
    
  
    
     vector<KeyFrame*> vpKFs = mpMap->GetAllKeyFrames();
    
     sort(vpKFs.begin(),vpKFs.end(),KeyFrame::lId);
    
  
    
     // Transform all keyframes so that the first keyframe is at the origin.
    
     // After a loop closure the first keyframe might not be at the origin.
    
     //cv::Mat Two = vpKFs[0]->GetPoseInverse();
    
  
    
     ofstream f;
    
     f.open(filename.c_str());
    
     f << fixed;
    
  
    
     for(size_t i=0; i<vpKFs.size(); i++)
    
     {
    
     KeyFrame* pKF = vpKFs[i];
    
  
    
    // pKF->SetPose(pKF->GetPose()*Two);
    
  
    
     if(pKF->isBad())
    
         continue;
    
  
    
     cv::Mat R = pKF->GetRotation().t();
    
     vector<float> q = Converter::toQuaternion(R);
    
     cv::Mat t = pKF->GetCameraCenter();
    
     f << setprecision(6) << pKF->mTimeStamp << setprecision(7) << " " << t.at<float>(0) << " " << t.at<float>(1) << " " << t.at<float>(2)
    
       << " " << q[0] << " " << q[1] << " " << q[2] << " " << q[3] << endl;
    
  
    
     }
    
  
    
     f.close();
    
     cout << endl << "trajectory saved!" << endl;
    
 }
    
  
    
 void System::SaveTrajectoryKITTI(const string &filename)
    
 {
    
     cout << endl << "Saving camera trajectory to " << filename << " ..." << endl;
    
     if(mSensor==MONOCULAR)
    
     {
    
     cerr << "ERROR: SaveTrajectoryKITTI cannot be used for monocular." << endl;
    
     return;
    
     }
    
  
    
     vector<KeyFrame*> vpKFs = mpMap->GetAllKeyFrames();
    
     sort(vpKFs.begin(),vpKFs.end(),KeyFrame::lId);
    
  
    
     // Transform all keyframes so that the first keyframe is at the origin.
    
     // After a loop closure the first keyframe might not be at the origin.
    
     cv::Mat Two = vpKFs[0]->GetPoseInverse();
    
  
    
     ofstream f;
    
     f.open(filename.c_str());
    
     f << fixed;
    
  
    
     // Frame pose is stored relative to its reference keyframe (which is optimized by BA and pose graph).
    
     // We need to get first the keyframe pose and then concatenate the relative transformation.
    
     // Frames not localized (tracking failure) are not saved.
    
  
    
     // For each frame we have a reference keyframe (lRit), the timestamp (lT) and a flag
    
     // which is true when tracking failed (lbL).
    
     list<ORB_SLAM2::KeyFrame*>::iterator lRit = mpTracker->mlpReferences.begin();
    
     list<double>::iterator lT = mpTracker->mlFrameTimes.begin();
    
     for(list<cv::Mat>::iterator lit=mpTracker->mlRelativeFramePoses.begin(), lend=mpTracker->mlRelativeFramePoses.end();lit!=lend;lit++, lRit++, lT++)
    
     {
    
     ORB_SLAM2::KeyFrame* pKF = *lRit;
    
  
    
     cv::Mat Trw = cv::Mat::eye(4,4,CV_32F);
    
  
    
     while(pKF->isBad())
    
     {
    
       //  cout << "bad parent" << endl;
    
         Trw = Trw*pKF->mTcp;
    
         pKF = pKF->GetParent();
    
     }
    
  
    
     Trw = Trw*pKF->GetPose()*Two;
    
  
    
     cv::Mat Tcw = (*lit)*Trw;
    
     cv::Mat Rwc = Tcw.rowRange(0,3).colRange(0,3).t();
    
     cv::Mat twc = -Rwc*Tcw.rowRange(0,3).col(3);
    
  
    
     f << setprecision(9) << Rwc.at<float>(0,0) << " " << Rwc.at<float>(0,1)  << " " << Rwc.at<float>(0,2) << " "  << twc.at<float>(0) << " " <<
    
          Rwc.at<float>(1,0) << " " << Rwc.at<float>(1,1)  << " " << Rwc.at<float>(1,2) << " "  << twc.at<float>(1) << " " <<
    
          Rwc.at<float>(2,0) << " " << Rwc.at<float>(2,1)  << " " << Rwc.at<float>(2,2) << " "  << twc.at<float>(2) << endl;
    
     }
    
     f.close();
    
     cout << endl << "trajectory saved!" << endl;
    
 }
    
  
    
 } //namespace ORB_SLAM

总结:

è¿éåå¾çæè¿°

我们可以看到在这个对象的实例化过程中,我们创建了以下对象:
(1)创建了ORB词袋的对象
(2)创建了关键帧的数据库
(3)创建地图对象
(4)创建两个显示窗口
(5)初始化Tracking对象
(6)初始化Local Mapping对象,并开启线程运行
(7)初始化Loop Closing对象,并开启线程运行
(8)初始化窗口,开启线程显示图像和地图点

全部评论 (0)

还没有任何评论哟~