ORB-SLAM2主要由以下三个线程组成:
(1)跟踪(Tracking)线程: 计算每帧图像的ORB特征并进行匹配,利用Motion-Only BA估计相机初始位姿,跟踪局部地图,并判断当前图像帧是否为关键帧。当跟踪失败时,利用场景识别(Place Recognition)模块恢复对环境地图点的跟踪。
(2)局部建图(Local Mapping)线程: 获取跟踪线程的候选关键帧,管理局部地图中的关键帧和局部地图点,执行局部BA,得到准确度更高的定位和建图精度,最后对候选关键帧进行筛选。
(3)闭环(Loop Closing)线程: 进行闭环检测,当检测成功时利用位姿图优化减小相机运动漂移。而后执行全局BA,得到全局一致性更好的环境地图和相机运动轨迹。
ORB-SLAM2适用于单目相机、双目相机和RGB-D传感器,本文仅介绍双目下算法的主要程序流程和重点函数。
在具体算法实现上,ORB-SLAM2主要包含以下类:
- 地图点类(MapPoint);
- 图像帧类(Frame);
- 关键帧类(KeyFrame);
- 特征提取类(ORBextractor);
- 特征匹配类(ORBmatcher);
- 跟踪类(Tracker);
- 局部建图类(LocalMapping);
- 闭环类(LoopClosing);
- 优化类(Optimizer);
- 系统类(System);
其中1-3 是ORB-SLAM2的数据基础; 4-5是特征处理相关类; 6-8是算法三个主要线程的实现类;9是非线性优化类,用于估计相机位姿和地图点位置;10是系统集成类,接收传感器数据,加载SLAM的三个线程。
一、数据基础
1.1 MapPoint类
地图点类是对环境中真实存在的点的描述,主要包含的类成员变量有:
- 地图点在绝对坐标系下的坐标 cv::Mat mWorldPos
- 观测量 std::map <KeyFrame *,size_t> mObservations, 其中键为观测到该地图点的关键帧指针,值为该地图点在该关键帧的索引;
- 描述子cv::Mat mDescriptor;
- int mnVisible 为理论上该地图被观测到的次数
- int mnFound 为实际该地图被观测到的次数
1.2 Frame类
帧是指一个时刻得到的图像信息及其附加信息。值得注意的是,不同的SLAM算法需要的附加信息不尽相同。
ORB-SLAM2中图像帧类Frame主要包含的类成员变量有:
- 该帧索引 long unsigned int mnID;
- 相机位姿 cv::Mat mTcw;
- 左右图像中的关键点 std::vector< cv::KeyPoint > mvKeys, mvKeysRight;
- 关联图像中特征点的地图点集合 std::vector<MapPoint *> mvpMapPoints;
- 左右图像中关键点的描述子 cv::Mat mDescriptors, mDescriptorsRight;
- 词袋向量 DBoW2::BowVector mBowVec;
- 外点标志位 std::vector< bool > mvbOutlier.
主要包含的类成员函数有:
- void ExtractORB(int flag,const cv::Mat &im); 提取图像ORB特征;
- void ComputeBoW():计算特征的词袋表示;
- void SetPose(cv::Mat Tcw): 设置帧的位姿mTcw;
- cv::Mat UnprojectStereo(const int &i): 获取第i个特征点在该帧坐标系下的3D坐标。
由于图像信息数据量大,保留所有的帧信息会对存储造成较大压力,因此通常的做法是选取具有代表性的信息作为关键帧。在ORB-SLAM2的程序实现中,关键帧类KeyFrame由Frame构造得到,包含的类成员变量类似。