转载请注明出处,谢谢
原创做者:MingruiYu
原创连接:http://www.javashuo.com/article/p-amuyogdu-hb.htmlhtml
本文要点:算法
上一篇文章中咱们已经对 ORB-SLAM2 系统有了一个概览性的了解。经过我绘制的详细的思惟导图形式的程序导图,咱们也能够很清晰地看出各个线程之间的关系,以及它们是如何和论文中的 System Overview 图对应上的。app
依旧祭出该图,方便查看:dom
也再次献上我绘制的程序导图全图:ORB-SLAM2 程序导图学习
从这篇文章开始,咱们将会进入 ORB-SLAM2 的每一个部分,学习 ORB-SLAM2 每一个部分的具体结构和逻辑。Tracking 线程是 ORB-SLAM2 系统的主线程,每一帧图像送入后也会先通过 Tracking 线程的处理。因此这篇文章,咱们先来看看 Tracking 线程的具体工做。优化
老规矩,仍是分两部分:以 ORB-SLAM 论文为参考 和 以 ORB-SLAM2 代码(程序导图)为参考。ui
首先,来看看论文中对 Tracking 线程的介绍。.net
Tracking 线程的主要工做以下:线程
下面咱们具体来看这些内容。code
注: Tracking 线程中很重要的一个工做是进行单目初始化,这一部分我会单独写一片文章来进行介绍,因此本文会暂时跳过单目初始化的具体内容。
ORB-SLAM2 系统采用 ORB 特征做为贯穿整个系统使用的特征提取和描述方式。其优点在于,提取速度快(大幅快于 SIFT 和 SURF,但其实 ORB 特征的提取仍是整个系统中最耗时的部分)。关于 ORB 特征的详细内容可见论文:ORB: An efficient alternative to SIFT or SURF PDF。
ORB 特征具备旋转不变性,但没有尺度不变性。为了减少尺度变化对于 ORB 特征的影响,ORB-SLAM 采用尺度金字塔的方式,将图像放大或缩小造成不一样尺度(共8个,每一个尺度之间的缩放比例为1.2),以后再在每一个尺度的图像上都提取一遍 ORB 特征(提出 ORB 特征会带有一个标记,标记其是从哪一个尺度提取出来的),将每一个尺度提取出的 ORB 特征汇总在一块儿,就成为了该图像提取的 ORB 特征。
为了尽量使得 提取的 ORB 特征在图像上分布均匀(ORB 特征提取自己存在一个问题,其在图像上分布不均,常常有的局部一大堆特征点,有的局部没有特征点),ORB-SLAM 将每一个尺度的图像,划分红一个个小格格(切蛋糕了),在每一个小格格上提取至少5个特征点。若是提取不出5个特征点,就将提取特征的阈值放低一些。
提取的 ORB 特征在 ORB-SLAM 系统中至关重要,会贯穿整个系统,用于全部的特征匹配。
Tracking 线程的目的之一是求出当前帧的位姿,其巧妙地将这个求解过程分为两步,从粗到细。相对较粗的步骤 —— 当前帧位姿初值估计,在估计好一个初值后,会进入相对较细的步骤 —— 局部地图跟踪,而后获得一个最终的位姿(固然在 LocalMapping 线程中还要继续优化)。
首先来看这个相对较粗的步骤 —— 相机位姿初值估计。其有三种可能的估计方式,论文里提到了两种:根据上一帧和运动模型进行估计(上一帧跟踪成功) 和 经过全局重定位估计(上一帧跟踪丢失)。还有一种是根据 Reference KF 进行估计(虽然上一帧跟踪成功,但由于种种缘由,没法使用上一帧和运动模型进行估计),咱们会在代码部分对其进行介绍。另外,在这一部分中,除了会估计当前帧的位姿外,还会将当前帧的 FeaturePoints 和 MapPoints 作一个初步的匹配。
若是上一帧跟踪成功,就能够继续正常的跟踪。ORB-SLAM 系统假设了一个匀速运动模型,意思就是假设当前帧与上一帧之间的相对位姿变化量 = 上一帧和上上帧之间的相对位姿变化量。经过这个能够先估计出当前帧的一个位姿初值,根据这个位姿初值,将上一帧的 MapPoints 和当前帧的 FeaturePoints 进行匹配,以后根据匹配进行优化。(若是没有找到足够多的匹配,就要使用上面提到的 根据 Reference KF 进行估计的方法了)
若是上一帧跟踪失败了,没有上一帧的位姿,确定是没法经过上面的方法继续跟踪的,因此要进行重定位。重定位的含义就是从 KF Database 中寻找有没有哪一个 KF 与当前帧很类似,有的话可能当前帧就在那个 KF 附近,从而定位了当前帧。
寻找可能的 KF 并计算当前帧位姿的方法以下:根据当前帧的 FeaturePoints 计算当前帧的 BoW。经过当前帧的 BoW 与 KF Database 中的 KFs 的 BoW 进行匹配,初步筛选初一批 Candidate KFs,并将当前帧的 FeaturePoints 与 Candidate KFs 含有的 MapPoints 进行匹配。以后,RANSAC 迭代计算当前帧的位姿(经过 PnP 算法求解)。注意,上述计算的目的之一是进一步筛选 Candidate KFs,因此根据每个 Candidate KFs 都要计算出一个当前帧的位姿,直到找到一个合适的 Candidate KF,根据它计算出的当前帧位姿很合适(有足够多的 inliers)。再对其进行进一步优化,再进行更多的 FeaturePoints 和 MapPoints 的匹配。若是再优化后这个位姿计算还很合适(有足够多的 inliers),那就肯定当前帧的位姿了,以后就能够继续正常跟踪了。
当在上一步中得到了当前帧的位姿初值而且当前帧的 FeaturePoints 和 MapPoints 有了初步的匹配后,就会进入这个更精细的求解当前帧位姿的步骤 —— 局部地图跟踪。
局部地图里包括:
在计算获得局部地图的同时,还须要尽量进一步地将局部地图的 MapPoints 与 当前帧还未匹配的 FeaturePoints 相匹配。最终,对该局部地图进行 BA 优化。
若是当前帧比较重要,则会将其做为 KF 插入 Map 并送入 LocalMapping 线程。ORB-SLAM 的一个特色就是,其插入 KF 的条件很宽松,这样会插入不少 KFs,而 ORB-SLAM 会在 LocalMapping 线程中对它们中冗余的进行剔除。这样的目的是不放过可能有用的帧,加强系统的鲁棒性,以应对纯旋转等很难处理的相机运动。
虽然这个条件很宽松,但仍是有条件的:
看完了论文,可能有点很差理解,毕竟用文字进行描述的难度是很高的,特别是 ORB-SLAM2 系统内部各部分之间的逻辑又是较为复杂的。Talk is cheap, give me code. 下面咱们从 ORB-SLAM2 的代码出发,结合我绘制的 ORB-SLAM2 程序导图,进一步加深对 Tracking 线程的理解。
如上图所示,在 System.cc 的主循环中,启动了对于 Tracking 线程的调用。每次读入一帧图像,为其建立 Frame 对象,在建立的同时就提起了 ORB 特征。这里有一个细节,在单目初始化时,对于该帧提取的 ORB 特征数是平时的两倍。
如上图所示,进入 Tracking 线程中,能够看到一个很重要的状态变量为 mState,根据它来区分当前系统的状态。当系统还未初始化时,会运行 MonocularInitialization() 来进行初始化。关于这一部分会在后面的博文中专门介绍。
初始化以后,就会进入常规 Tracking 过程,其中首先进行当前帧位姿,以后进行局部地图跟踪,再以后决定是否生成 KF,并插入 KF。下面咱们一个部分一个部分来看。
由于这些地方实在很差截图,请你们点击这张导图的连接 (在文首)来查看清晰大图吧。
注:
ORB-SLAM2 系统有两种模式(能够由使用者手动切换),其以 mbOnlyTracking 变量进行区分:
同时,Localization 模式中也有两种状况(系统自动断定,根据当前跟踪状况自动切换),其以 mbVO 变量进行区分:
若是是 SLAM 模式,则首先根据 mState 判断系统以前的跟踪状态。若是以前跟踪丢失,则要不断进行重定位 Tracking::Relocalization(),直到当前帧与 KF Database 中的某个 KF 匹配上了。若是以前跟踪正常,则继续跟踪,通常来讲使用 Tracking::TrackWithMotionMode() 进行估计,但若是运动模型还未创建,或者刚刚进行了重定位,则使用 Tracking::TrackReferenceKeyFrame() 进行估计。TrackReferenceKeyFrame() 指当前帧和其 Reference KF 进行匹配来估计位姿,其匹配的搜索量会大不少,因此当 Tracking::TrackWithMotionMode() 不行的时候才会用它。
具体的位姿估计方式都是 匹配 + 优化。只是匹配的方式会有所不一样:
若是是 Localization 模式,那么若是以前系统跟踪丢失,一样不断进行重定位 Tracking::Relocalization()。若是以前系统跟踪正常,与 SLAM 模式不一样的地方在于,其会判断当前处于 VO 状况仍是正常状况:
只有 SLAM 模式下,且上一步当前帧位姿初值估计成功(有位姿初值了)的状况下才会进行局部地图跟踪。
在局部地图跟踪优化后,会判断优化的效果如何,若是效果能够的话,才会判断本次跟踪成功(当前帧位姿初值估计 + 局部地图跟踪 都成功才算成功),不然本次跟踪丢失。
若是当前帧丢失的话,那确定是不会将其做为 KF 插入的。但刚初始化完没几帧就丢失了,说明初始化的质量不行,系统 Reset,从新初始化。(从中能够看出,ORB-SLAM2 对于初始化的质量标准很高,因此也常常出如今实际中其迟迟不愿启动的情况)。
若是当前帧跟踪成功,更新运动模型,且根据论文中的标准决定当前帧是否做为 KF 插入 Map,并送入 LocalMapping 线程。