秋招复习之--ORB-SLAM2
前言
其实ORB-SLAM2算是自己接触到的第一个开源SLAM框架,当时自己是是花了大量时间(感觉得看了两三个月)和金钱(当时还报了计算机视觉life的源码解析网课),可以说几乎是一行一行地把这个框架看完了。后续在六哥推出ORB-SLAM2一个月挑战赛的时候,也是去当了一期的助教。但是出于种种原因,从研一下开始自己就没再深入研究ORB-SLAM系列(包括后边的ORB-SLAM3也只是简单看了下,然后跑实测的数据效果不好就没再看了。。),但是自己简历上又写了熟悉ORB-SLAM,所以这里还是把这个框架简单复习一遍吧,以免面试被问到了自己什么都忘了觉得尴尬
因为是复习为主的博客,所以这里不会对代码实现细节进行过多回忆,主要还是回忆一下其中一些比较有代表性的东西
ORB特征提取
ORB特征点
ORB特征点右关键点+描述子两部分组成,当然这里的关键点其实底层还是FAST角点,不过在计算的ORB特征点的时候,增加了尺度和旋转这两种表述,其中尺度是由图像金字塔实现的,其实金字塔就是把图像不停地resize,然后得到很多层分辨率下的图像,再依次对每一层提取特征点,这样的好处就是一些距离不合适的点(可以狭义地理解为应该是特征,但因为比较远或比较近导致图像上不清晰的特征)就有被提取出来的可能了。
至于旋转不变性,这里使用到的方法是灰度质心法,其实就是找到图像中心和几何质心(用图像矩算出来),然后把中心指向质心的这个方向当作了特征点的方向。
ORB-SLAM2的特点
我觉得特征提取这部分的特点主要有两点:
- 在进行初步提取的时候,其实已经先把图像分成网格了,然后再分配到网格里去匹配,相当于一个粗均匀化过程
- 接下来是精细均匀化过程,通过四叉树的形式,来不停对提取到的特征点来划分节点(也可以理解为网格),然后最后选取每个部分里最有代表性的特征点,这样的话特征点就可以看作均匀分布在图片上了
BRIEF描述子
BRIEF描述子其实就是一种二进制的描述子,在特征点的周围(我记得是31*31)里面随机选择128对点,然后比较两者之间的像素大小关系,这样就得到了一个128维的向量,这个描述子主要发挥作用的地方在特征匹配,ORB-SLAM2中有很多特征匹配,比如重投影匹配就是通过比较候选特征点与待匹配特征点之间的描述子距离来找匹配的
初始化
单目初始化
单目初始化是单目SLAM非常重要的部分,究其根本原因还是单目无法得到绝对尺度下的点、位姿信息,这样即便通过三角化恢复出来的点没有一个标准的尺度信息,所以这里还有一步就是在初始化的时候得到的平移向量强行设置为1,这样后续恢复出来的尺度都可以对齐到这个尺度下,当然尺度漂移的话没有办法,回环能稍微修正一下。 单目初始化的时候ORB-SLAM2是选择了分别计算F矩阵和H矩阵,然后选择两者之中得分更高(其实就是误差更小的那种方法)来进行初始位姿的恢复
双目模式初始化
这里双目模式的初始化就简单很多了,因为可以直接根据基线得到点云的3D坐标,所以直接通过一个立体匹配(这里也是稍微有点技巧,是先粗匹配也就是根据位置选,然后再精确匹配得到更细致的匹配结果)就直接把点云信息恢复出来了,然后第一帧位姿设置为1就好
地图点部分
地图点的性质
ORB-SLAM里对地图点有几个性质还是比较有趣的:
- 平均观测方向:所有观测到该点的帧到当前点的向量的平均
- 最具代表性的描述子:一个地图点在不同关键帧中对应不同的特征点和描述子,其特征描述子mDescriptor是其在所有观测关键帧中描述子的中位数(准确地说,该描述子与其他所有描述子的中值距离最小).
- 平均观测距离:这个又是和图像金字塔呼应上了,其实就是限制一个最近和最远的观测距离,然后如果已知距离的话还能知道这个地图点是在第几层提取到的
地图点的生成
地图点的生成主要有以下四个部分:
- 无论是单目初始化还是双目初始化,都会生成地图点,可以看成是初始点云
- 局部建图线程会根据关键帧之间的匹配关系来生成新的地图点
- 在创建新的关键帧的时候,双目和RGBD模式会直接生成地图点,当然这些点在局部线程里会进行检查
- 双目和RGBD在跟踪线程还会生成临时地图点,不过这些在进入局部建图线程之前就会被删除了,所以本质上还是没有影响到局部建图的
地图点的删除
主要在局部见图线程里
- 跟踪到该地图点的帧数相比预计可观测到该地图点的帧数的比例小于25%
- 从创建开始的3帧内,观测数目少于2
这里我不知道总结的全不全,后边如果有那种重投影失败的地图点应该也是要被删除的?不过有点忘了
关键帧
关键帧的选取原则
ORB-SLAM采取了很宽松的选取原则,主要从三方面考虑:
- 当前帧和参考关键帧跟踪到点的比例,比例越大,越倾向于增加关键帧
- 很长时间没有插入关键帧,可以插入
- 满足插入关键帧的最小间隔并且localMapper处于空闲状态,可以插入
- 和参考帧相比当前跟踪到的点太少
当然在后边会对这些关键帧进行过滤,所以这里先采取了很宽松的条件
共视图
ORB-SLAM中会根据关键帧之间的共视关系(有多少相同的地图点)来生成一个共视图,共视关系会在初始化创建关键帧后,局部建图线程处理新插入的关键帧后以及处理完所有的关键帧后,还有回环检测后来进行更新,其实可以理解为关键帧或者关键帧与地图点之间的联系发生改变的时候,就要进行更新了
此外ORB-SLAM中还有生成树的概念,在回环检测和修正的时候,保存所有关键帧构成的最小生成树(优先选择权重大的边作为生成树的边),在回环闭合时只需对最小生成树做BA优化就能以最小代价优化所有关键帧和地图点的位姿,相比于优化共视图大大减少了计算量,当然实际上实际上并没有对最小生成树做BA优化,而是对包含生成树的本质图做BA优化
生成树对应的父子关系,在关键帧被深处的时候必须进行维护,维护的办法就是为每一个都找新的对应关系
关键帧的删除
在局部建图线程,检查到当前关键帧为冗余关键帧了(里面有90%的地图点都被至少其他三帧观察到过,就会设置为冗余关键帧进行删除)
跟踪
跟踪线程的几种模式
- 第一种就是根据参考关键帧跟踪,比如我们刚刚完成初始化,那么这个时候的运动模型还不稳定,所以会利用参考关键帧来进行跟踪,具体的话就会对两帧之间进行BoW的匹配
- 运动模型跟踪:根据运动速度y和上一帧的位姿计算出本帧位姿的估计值,再进行位姿优化.也就是把地图点再投影到当前帧进行匹配,然后就可以根据BA来进行优化了,相当于经典的PnP
- 重定位:这个是在跟踪失败的时候才会进行的一种方法,里面会用到PnP(具体是EPnP),相当于重新估计初始位姿了
- 局部地图跟踪:1和2相当于两种粗跟踪,在我们已经有局部地图的情况下,再重新进行一次重投影匹配,这里相当于进行了一次局部BA只优化当前位姿,当然这里结束后会根据匹配结果来更新局部关键帧和局部地图点
局部建图
地图点的生成
这里最重要的部分其实就是地图点的生成,因为ORB-SLAM中关键帧之间的共视关系是一个重要的参考,所以这里也是根据共视程度比较高的关键帧来进行三角化恢复地图点
当然因为同一个地图点可能会被生成好几次,所以这里还做了一个工作就是把当前新生成的点和一二级共视关键帧的点进行了一波融合,其实就是正着投影一遍,反着投影一遍,没有的就加一下,有的就fuse一下
局部BA
之前跟踪线程的局部BA相当于是用地图点来约束当前帧位姿,局部建图里的局部BA地图点也是会被优化的,这里是用一二级关键帧来约束当前关键帧和地图点
回环检测
Sim3
回环检测用到的Sim3是三维空间的相似变换,三个参数分别是旋转、平移和尺度因子,因为实际发生回环的地方可能已经发生了很大的漂移,所以这里用Sim3来计算一下两个之间的一个转换关系,这样就可以转到一起,或者说至少差不多对齐的地方
ORB-SLAM里是根据当前帧和共视关键帧的连续观测条件来判断是否认为发生回环的,发生回环的话就会计算Sim3,然后通过计算得到的参数来进行整体的矫正,当然这里是分别对关键帧位姿和地图点都进行了位姿的修正
这里更多的其实是代码实现的细节,当然大体的思路大家还是要清楚的,如果不清楚的话也可以参考大佬的文章:ORB-SLAM2代码详解09: 闭环线程LoopClosing 当然如果有时间的话也可以结合大佬系列的文章把整个ORB-SLAM2再复习一遍,肯定会印象更深刻一些