ORB_SLAM2学习之源码分析二-初始化


这篇文章是有关ORB_SLAM2系统源码分析的内容,主要记录单目、双目、RGB-D初始化过程,并进行比较。

概述

SLAM过程初始化的目的是创建3d地图点,为后续跟踪提供初值。其中单目初始化较为复杂,双目、RGB-D初始化类似。

图像帧创建

SLAM系统可以接收各种传感器的图像,不管是双目、单目还是RGB-D,都会将原始图像封装成帧,帧中包含所有SLAM过程需要的信息,包括矫正前后的关键点及数量、特征描述子、右图成像坐标信息(单目除外)、深度信息(单目除外)、时间戳、词袋、内参矩阵、畸变参数、相机位姿、旋转矩阵、平移向量、尺度金字塔信息、参考关键帧等等,通过原始图像获取到帧所需信息之后,原始图像就被丢弃,之后的处理过程和原始图像没有关系了。

在进行初始化之前都要将彩色图像(3或4通道图像)处理成灰度图像(无论图片是RGB、BGR, 还是RGBA、BGRA,均转化为灰度图,放弃彩色信息),继而将图片封装成帧(Frame类对象)。下面介绍下图像帧的创建过程,三者初始化分别调用重载的Frame类构造函数,重载的构造函数都有ORB特征提取、畸变矫正等环节。重载函数传入的参数有差别,这一点很显然。值得注意的是函数内部构造过程的一些区别,比如双目初始化需要进行双目匹配ComputeStereoMatches、RGB-D初始化需要进行双目信息计算ComputeStereoFromRGBD,这一点涉及到mvuRightmvDepth这两个变量,详细的理解另作记录。

单目创建图像帧

函数调用

1
mCurrentFrame = Frame(mImGray, timestamp, mpIniORBextractor, mpORBextractor, mpORBVocabulary, mK, mDistCoef, mbf, mThDepth);

主要过程

设置尺度金字塔信息、ORB特征提取、畸变矫正、设置无双目信息(设置mvuRightmvDepth两个变量为负)、关键点分布到网格。

双目创建图像帧

函数调用

1
mCurrentFrame = Frame(mImGray, imGrayRight, timestamp, mpORBextractorLeft, mpORBextractorRight, mpORBVocabulary,mK, mDistCoef, mbf, mThDepth);

主要过程

设置尺度金字塔信息、ORB特征提取、畸变矫正、双目匹配(计算左图中特征点对应的右图坐标,并恢复出的深度信息。设置mvuRightmvDepth两个变量为负)、计算基线、关键点分布到网格。

RGB-D创建图像帧

函数调用

1
mCurrentFrame = Frame(mImGray, imDepth, timestamp, mpORBextractorLeft, mpORBVocabulary, mK, mDistCoef, mbf, mThDepth);

主要过程

设置尺度金字塔信息、ORB特征提取、畸变矫正、根据RGB-D计算双目信息(设置mvuRightmvDepth两个变量)、关键点分布到网格。

ORB特征提取

1
2
3
4
5
6
7
void Frame::ExtractORB(int flag, const cv::Mat &im)
{
if(flag==0)
(*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors);
else
(*mpORBextractorRight)(im,cv::Mat(),mvKeysRight,mDescriptorsRight);
}

创建图像帧的关键一步是进行ORB特征提取,ExtractORB()调用了ORBextractor类中的重载操作符void operator(),完成特征提取,提取结果被保存在Frame类的成员变量std::vector<cv:KeyPoint> mvKeyscv:Mat mDescriptors中,即提取出特征的关键点和描述子。关于ORB特征及其提取、匹配,会在后续继续学习。

单目初始化

单目SLAM地图初始化的目标是构建初始的三维点云。由于不能仅仅从单帧得到深度信息,因此需要从图像序列中选取两帧以上的图像,估计摄像机姿态并重建出初始的三维点云。单目初始化调用Tracking::MonocularInitialization()函数。

重点分析

  1. 需要获取连续两帧特征点数量超过100的图像帧,并且两帧图像匹配点大于100,才可以开始初始化,否则重新接收数据帧;连续两帧的前一帧设为参考帧;
  2. 找到连续可用的图像帧后,需要使用专门的初始化器进行初始化(Initializer.cc),这个通过并行计算分解单应矩阵H和基础矩阵F,得到帧间运动(位姿)(关于对极几何方法,使用并行计算F和H矩阵的初始化后续再做专门的记录);
  3. 创建初始地图过程。首先创建关键帧和地图点,通过将关键帧和地图点插入初始地图完成初始地图的构建,接着更新关键帧之间的连接关系(以共视地图点的数量作为权重),对两帧姿态图像进行全局优化重投影误差(和回环检测调整后的大回环优化使用的是同一函数);
  4. 比较重要的三个对象:地图、地图点、关键帧。地图就是整个的位姿和地图点。一个关键帧提取出的特征点对应一个地图点集,因此需要记下每个地图点在该帧中的编号;一个地图点会被多帧关键帧观测到,需要记下每个关键帧在该点中的编号。因此,地图点和关键帧的关系是:每个地图点会记录观测到自身的关键帧,关键帧中会记录观测到的所有地图点;
  5. 创建地图点时,地图点中需要加入的一些属性:观测到该地图点的关键帧(以及对应的特征点);该地图点的描述子(观测到该地图点的多个特征点中(对应多个关键帧),挑选出区分度最高的描述子,作为这个地图点的描述子); 该MapPoint的平均观测方向和观测距离的,为后面做描述子融合做准备;
  6. 局部地图、局部关键帧、局部地图点,是为了进行局部Bundle Adjustment。

单目初始化特点

  1. 单目通过一帧无法估计深度,所以初始化时需要使用两帧图像;
  2. 需要使用专门的初始化器进行初始化,使用对极约束几何方法恢复运动,得到Rcw、tcw;
  3. 恢复运动之后使用三角化测量方法得到特征点的空间位置;
  4. 由于通过分解基础矩阵$E$恢复相机运动,得到$R$,$t$,如果相机发生的纯旋转,导致$t$为0,得到的$E$也将为0,无法进一步求解$R$。虽然可以依靠单应矩阵$H$求解旋转,但仅有旋转无法使用三角测量方法估计特征点的空间位置;因此,单目初始化不能只有纯旋转,必须要有一定程度的平移(平移太小会使得位姿求解和三角化结果不稳定,从而导致失败)。
  5. 为了让单目成功初始化(单目的初始化需要通过平移运动归一化尺度因子),初始化TrackingmpIniORBextractor提取的特征点数量设定为普通帧的2倍(Tracking.cc)。

双目、RGB-D初始化

双目和RGB-D相机不需要通过两个相邻帧来恢复地图点深度,所以初始化过程极其相似,只要当前到来帧满足条件即可开始初始化,调用的是同一个函数Tracking::StereoInitialization()

重点分析

  1. 创建初始地图过程。首先创建关键帧和地图点,注意这里只会使用有深度的点进行初始化;然后通过将关键帧和地图点插入初始地图完成初始地图的构建。因为此初始化只用到一个图像帧,所以没有关键帧连接关系的更新和姿态的优化;
  2. 其他同单目4、5、6条。

疑问:初始化过程中,满足条件的第一个图像帧作为参考关键帧,后来帧都以该参考关键帧为参考吗?即参考关键帧会更新吗?

答:后续的追踪过程还会有新的关键帧的插入(在Tracking::CreateNewKeyFrame()中完成),最新插入的关键帧作为参考关键帧的。即参考关键帧会更新,总是当前帧最临近的关键帧,或者说上一个关键帧。

初始化比较

单目初始化的特点是双目、RGD-D初始化过程不具备的。(废话么这不是()> _ <) )单目初始化一定要有一定程度的平移。值得关注的一点是,在三者初始化之前图像帧的创建过程也是有区别的,单目不涉及深度和右图特征点成像平面坐标的计算,后两者需要此过程,这一点涉及到mvuRightmvDepth这两个变量,详细的理解另作记录。

区分

图像帧相关

  1. 上一帧mLastFrame:即上一帧图像

  2. 上一关键帧mpLastKeyFrame:最邻近当前帧的关键帧,不一定是上一帧,因为图像帧要经过判断后,满足条件才能称为关键帧

  3. 参考关键帧mpReferenceKF:就是当前帧的上一关键帧;若创建了新的关键帧,参考关键帧就更新为新创建的关键帧;或者是局部地图中与当前帧共享地图点最多的关键帧。

    参考关键帧更新的时机

    • 创建新的关键帧时(初始化、追踪过程两处)
    • TrackLocalMap()更新局部关键帧的过程中
  1. 当前帧的参考关键帧:或者是上一关键帧,或者是由当前帧创建的关键帧(即当前帧满足关键帧创建的条件),或者是局部地图中与当前帧共享地图点最多的关键帧。

地图相关

  1. 全局地图mpMap

    Map类的对象,本质上也是由关键帧和地图点组成。

  2. 局部地图

    局部地图不像全局地图一样有Map类表示,它只是一个概念叫法,其作用是在局部地图追踪过程中通过地图点重投影匹配关键点,进一步优化初步估计的当前帧位姿(是否还有其他作用???)。实际上它包括三个变量:

    • 参考关键帧mpReferenceKF
    • 局部关键帧集合mvpLocalKeyFrames
    • 局部地图点集合mvpLocalMapPoints
  1. 局部建图线程接口指针mpLocalMapper

    主要是和局部建图线程建立连接,给该线程传递关键帧并由其维护地图,也就是全局地图。

地图点相关

地图点有两个私有成员变量mnVisiblemnfound,前者表示该地图点在图像帧视野范围内,在创建地图点时构造函数就将该值置为1;后者表示该地图点有对应特征点的图像帧帧数。通常来说,found的地图点一定是visible的,但是visible的地图点很可能not found。

参考资料

  1. ORB-SLAM 代码笔记(四)tracking代码结构
  2. 单目、双目和RGB-D视觉SLAM初始化比较
  3. 视觉SLAM十四讲P152

本文标题:ORB_SLAM2学习之源码分析二-初始化

文章作者:阿翔

发布时间:2018年08月16日 - 15:08

最后更新:2019年05月28日 - 21:05

原始链接:http://ttshun.com/2018/08/16/ORB-SLAM2学习之源码分析二-初始化/

许可协议: 署名-非商业性使用-禁止演绎 4.0 国际 转载请保留原文链接及作者。

点击给我一些鼓励叭!
-------------本文结束感谢您的阅读-------------
0%