LocalMapping::ProcessNewKeyFrame()
函数
需要处理的变量:私有成员变量std::list<KeyFrame*> mlNewKeyFrames;
数据来源:Tracking::createNewKeyFrame()函数
调用了局部地图中LocalMapping::InsertKeyFrame(KeyFrame *pKF)
此函数,将关键帧插入到列表中,同时将终止局部BA的标志置为true。
更新的信息:
私有成员变量KeyFrame* mpCurrentKeyFrame;
当前正在处理的关键帧,更新此关键帧在tracking过程跟踪到的地图点属性以及其与其他关键帧的连接关系;
std::list<MapPoint*> mlpRecentAddedMapPoints;
待检验的地图点;
Map* mpMap;
更新局部地图;
步骤1:获取关键帧
涉及多线程操作关键帧列表,因此需要加锁。
利用list容器的常用函数,获取关键帧,并将已获取的关键帧从列表中移除。
步骤2:计算关键帧特征点的BoW映射关系
从当前帧的描述子中得到对应的词袋向量和节点的特征向量和特征索引。
- 将描述子矩阵类型(
cv::mat
)转换为描述子向量类型(std::vector
); - 通过词袋模型得到词袋向量和节点的特征向量和特征索引。
步骤3:关联地图点和新的关键帧,更新方向和描述子
- 获取当前关键帧中的地图点。
TrackLocalMap
函数将局部地图中的MapPoints
与当前帧进行了匹配,但是没有对这些匹配上的MapPoints
与当前帧进行关联; - 对所有
MapPoints
展开遍历,确认地图点存在,判断地图点是否是坏点; - 如果当前关键帧能观测到的地图点添加到待检验的地图点列表中,如果当前关键帧不能观测到地图点,说明此地图点是经过检验的,因此需要更新此地图点的属性(共视关系、平均观测方向和观测距离、最佳描述子);
确认当前关键帧是否能观测到此地图点
利用map
容器的特点,mObservations.count(关键帧)
函数检测地图点是否在关键帧中。
添加观测
将此关键帧添加到map
容器mObservations
中,更新地图点被观测到的次数。
更新平均观测方向和观测距离范围
平均观测方向的计算:
观测距离范围的计算:(利用图像金字塔的原理)
在orb_slam2中,为了实现特征尺度不变性采用了图像金字塔,金字塔的缩放因子为1.2。其思路就是对原始图形(第0层)依次进行1/1.2缩放比例进行降采样得到共计8张图片(包括原始图像),然后分别对得到的图像进行特征提取,并记录特征所在金字塔的第几层,这样得到一帧图像的特征点。
现在假设在第二层中有一特征点F,为了避免缩放带来特征点F在纵向的移动,为简化叙述,选择的特征点F位于图像中心。根据相机成像“物近像大,物远像小”的原理,。假设摄像机原始图像即金字塔第0层对应成像视野I0I_0I0,则图像金字塔第2层图像可以相应对应于成像视野I2I_2I2。
其中特征点F所在patch的相应关系:d2/d0=1.22d_2 / d_0 = 1.2^2d2/d0=1.22。
对于第m层上的一个特征点,其对应尺度不变时相机与特征点对应空间位置之间距离(简称物距)的范围。
假设第m层上有一特征点FmF_mFm,其空间位置与拍摄时相机中心的位置为dmd_mdm ,显然这是原始图像缩放1/1.2m1/1.2^m1/1.2m 倍后得到的特征点patch,考虑“物远像小”的成像特点,要使得该第m层特征点对应patch变为图像金字塔第0层中同样大小的patch,其相机与空间点的距离d=dm∗1.2md=d_m * 1.2^md=dm∗1.2m,即尺度不变的最大物距dmax=dm∗1.2md_{max} = d_m*1.2^mdmax=dm∗1.2m。
要求尺度不变的最小物距则这样考虑:根据“物近像大”的成像特点,使得当前第m层的特征点移到第7层上则,真实相机成像图像得放大1.27−m1.2^{7-m}1.27−m倍,故对应最小物距dmin=dm∗1.2m−7=dmax/1.2金字塔层数−1d_{min} = d_m *1.2^{m-7} = d_{max} / 1.2^{金字塔层数 - 1}dmin=dm∗1.2m−7=dmax/1.2金字塔层数−1。
更新3D点的最佳描述子
由于一个MapPoint
会被许多相机观测到,因此在插入关键帧后,需要判断是否更新当前点的最适合的描述子。先获得当前点的所有描述子,然后计算描述子之间的两两距离,最好的描述子与其他描述子应该具有最小的距离中值。
步骤4:更新关键帧间的连接关系(不太明白树的作用)
- 首先获得该关键帧的所有
MapPoint
点,统计观测到这些3d点的每个关键帧与其它所有关键帧之间的共视程度。对每一个找到的关键帧,建立一条边,边的权重是该关键帧与当前关键帧公共3d点的个数。 - 并且该权重必须大于一个阈值,如果没有超过该阈值的权重,那么就只保留权重最大的边(与其它关键帧的共视程度比较高)。
- 对这些连接按照权重从大到小进行排序,以方便将来的处理。更新完
covisibility
图之后,如果没有初始化过,则初始化为连接权重最大的边(与其它关键帧共视程度最高的那个关键帧),类似于最大生成树。
步骤5:将关键帧插入到地图中
用于建图。