代码解读主要是自己梳理代码过程中的记录,和网上各位大神的解读水平比不了。
ORB SLAM的大名和介绍就不需要在这里多介绍了,直接进入代码解读环节吧。
一、系统代码结构
ORB SLAM的代码结构非常清晰,直接看下面这张图就可以
这张图里可以看出orb一共有三个线程,分别负责跟踪(TRACKING)、局部建图(LOCAL MAPPING)和闭环(LOOP CLOSING)功能,同时又增加了重定位(PLACE RECOGNITION)功能。
二、 系统流程
系统流程的入口在http://system.cc文件中,这个文件中一共有四个函数:
1) System
2) TrackStereo
3) TrackRGBD
4) TrackMonocular
其中System是SLAM系统的构造函数,包括所有功能模块和所有线程的初始化,而TrackStereo、TrackRGBD和TrackMonocular分别是双目、RGBD和单目的数据入口,使用过程中,先调用System函数生成SLAM系统的对象,然后根据传感器类型,调用相应的入口函数,就可以执行SLAM的流程了。
下面对各个函数分别做介绍
1. 构造函数(System)
先上一张图,看一下构造函数内部的内容
构造函数中和流程相关的一共有四个参数,分别是
1) strVocFile: ORB词袋数据。词袋是在做闭环检测和重定位时候做检索用的,从历史关键帧中检索出和当前帧最相似的一帧,以进行位姿匹配。
2) strSettingsFile: 配置文件的路径。配置文件中存放了相机参数和用户显示界面的设置
3) sensor: 传感器类型,这是一个枚举变量,一共有三种,分别是MONOCULAR、STEREO和RGBD,分别代表单目、双目和RGBD。
4) bUseViewer: true代表启动显示界面,false代表不显示
构造函数中一共初始化了以下内容:
1) 初始化词袋模型
mpVocabulary = new ORBVocabulary(); //初始化词袋对象mpVocabulary->loadFromTextFile(strVocFile); //从词袋数据文件中读取数据
词袋是在做闭环检测和重定位时候做检索用的,从历史关键帧中检索出和当前帧最相似的一帧,以进行位姿匹配。关于词袋更详细的解释,可以参考文章:为何要加载orb vocabulary?他的作用是啥?www.zhihu.com
2) 初始化关键帧数据集
mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary); //使用词袋数据创建数据集对象
如果此处只是加载数据就没意思了,前面提到,这个数据主要用来做闭环检测和重定位,所以这个模块除了加载数据以外,还实现了闭环检测和重定位检测。对应的函数分别是
DetectLoopCandidates(KeyFrame* pKF, float minScore) //检测闭环向量DetectRelocalizationCandidates(Frame *F) //检测重定位向量
这两个函数内部的内容会在讲解闭环模块时再详细讲解。
3) 初始化地图
mpMap = new Map();
地图中主要存放关键帧和特征点。
4) 初始化用户显示界面,并打开对应的线程
mpFrameDrawer = new FrameDrawer(mpMap); //画关键帧mpMapDrawer = new MapDrawer(mpMap, strSettingsFile); //画地图if (bUseViewer) { //根据标志位判断是否需要显示 mpViewer = new Viewer(this, mpFrameDrawer,mpMapDrawer,mpTracker,strSettingsFile); //显示界面 mptViewer = new thread(&Viewer::Run, mpViewer);
mpTracker->SetViewer(mpViewer); //打开显示对应的线程}
5) 初始化局部地图,并打开对应的线程
mpLocalMapper = new LocalMapping(mpMap, mSensor==MONOCULAR); //初始化局部地图mptLocalMapping = new thread(&ORB_SLAM2::LocalMapping::Run,mpLocalMapper); //打开局部地图对应的线程
6) 初始化闭环流程,并打开对应的线程
mpLoopCloser = new LoopClosing(mpMap, mpKeyFrameDatabase, mpVocabulary, mSensor!=MONOCULAR); //初始化闭环检测mptLoopClosing = new thread(&ORB_SLAM2::LoopClosing::Run, mpLoopCloser); //打开对应的线程
7) 给各个线程之间建立关联
mpTracker->SetLocalMapper(mpLocalMapper);
mpTracker->SetLoopClosing(mpLoopCloser);
mpLocalMapper->SetTracker(mpTracker);
mpLocalMapper->SetLoopCloser(mpLoopCloser);
mpLoopCloser->SetTracker(mpTracker);
mpLoopCloser->SetLocalMapper(mpLocalMapper);
2. 双目相机入口(TrackStereo)
该函数主要功能和流程列在下图中
从途中可以看出,每次输入数据以后,会执行三种操作:
1) 判断是否需要进入或者退出纯定位模式,如果需要则执行
2) 判断是否需要重启tracking,如果需要则执行
3) 执行双目的跟踪程序。GrabImageStereo共有三个参数,分别是左目、右目和时间戳
3. RGBD相机入口(TrackRGBD)
整体流程和双目一样,唯一的区别是此处调用的入口是RGB函数的入口,它的三个参数分别是像素图、深度图和时间戳
4. 单目相机入口(TrackMonocular)
整体流程仍然和双目一样,区别是入口变成了单目的入口,它的两个参数分别是像素图和时间戳。