ORB-SLAM笔记——(5)Track Local Map分析

种种原因,关于我自己对orb-slam理解的笔记一直没有更新。翻了一下,最近的一次笔记还要追溯到几个月前,真的深感惭愧......我最早的想法是将自己对这个框架从整体到每一模块细节的理解,都进行整理,最终写成一个系列。既然做就一定要做到最后啦,所以再次......立flag:我一定会更快更新的!

回归正题,上一次的笔记对Tracking线程做了一个整体的介绍。我们知道orb的前端线程首先通过匀速运动模型,跟踪临近关键帧,或是重定位的方法对当前帧的位姿做了初始估计。接下来,因为当前帧无论是通过上述三种方法的哪一种,基本都是可以看到已存地图中的一些点,同时自然是会和一部分关键帧产生共视关系的。观测地图点的信息存在了mCurrentFrame.mvpMapPoints里面,然后对于这些点有共视的关键帧,通过MapPoint的GetObservations()就可以轻松获取。虽然有共视,但之前的追踪效果是有限的,当前帧和这些帧的共视关系还并未全部找出来。此外,这些帧周围的一些关键帧,也是非常有可能和当前关键帧存在共视的。如果我们能够获取更多的共视关系,便可用poseBA进一步优化当前位姿。因为即使是前台线程算出的初始值,也是非常重要的,无论这一帧是不是关键帧。先说是关键帧,插入较为准确的关键帧是直接影响全局轨迹精度的。要不是关键帧呢,在trackmotionmodel模式下,普通帧的轨迹也是派上用场的。所以作者在这里用心良苦,选择去追踪一个被称为localmap的东西,根本目的就是优化当前帧位姿,一切为了精度。

说到这里也引出了我之前说的为什么要单独拉出来一讲笔记来说tracklocalmap:orb算是我刚接触到slam时便去学习的框架,那时还过分幼稚的我固化于前后端的死逻辑,认为前台酒只管初始的第一步估计,后端就是优化......所以那时被这复杂的逻辑搞的也是比较懵,为什么在有了initial estimate之后还有费半天劲去找一些neighbor出来再次优化,这里不是前台线程吗?直接进行关键帧判断然后送去localmapping线程不行吗?逐步到后面,才慢慢地理清了上一段所讲的内容。身边有很多学slam的朋友,发现很多都像我一样,orb-slam是接触较早的一个框架。网上大家对于orb的总结不少,但看了很多下来,发现对于这一小部分内容的详细论述不是很多。做事精于细,我们不光要从整体对它的思路有一个了解,更重要的是针对每一个小模块儿更要清楚作者这样设计的意图,有什么好处,甚至有没有什么负面影响。这对正处于或是未来计划投身于做产品的同学们是非常重要的,细节积累得足够多,才能在面对极端复杂case时,有更多的灵感。

好了回归正题!

追踪局部地图的第一步,是要确定当前帧的局部地图的内容,这通过Tracking::UpdateLocalMap()完成。局部地图包含临近有或可能共视关系的关键帧,以及已经或可能即将被看到的地图点。所以这个函数包含两部分内容: (1)更新局部关键帧;(2)更新局部地图点。

更新局部关键帧:UpdateLocalKeyFrames()

1. 首先建立一个map keyframeCounter来存当前帧和其他帧的共视情况,遍历当前帧已经建立对应的地图点:找出每个点已经建立对应的所有关键帧。针对每一个点的每一个共视帧,keyframeCounter[KeyFrame*]++。

2. 将1中找出的所有共视帧都按当前map的顺序push到mvpLocalKeyFrames中,并找出共视程度最高的那一帧(上面做++那步最直接就是干这事儿的),用pKFmax指向它。

3. 遍历2中找出的所有帧:首先按照共视程度找出10个临近关键帧,只要不满足isBad(),便也push到mvpLocalKeyFrames中。第二步,在orb-slam中,作者维护了一个essential graph(这个可以先初步比较直白地理解为用最小生成树维护的一个全局概括性的covisibility graph),在这个graph中,每一个KF会有一个parent关键帧和若干个child关键帧。将这些关键帧也都认为是local keyframes,push到mvpLocalKeyFrames里面。

不过这里我认为有一点问题,首先因为在这一环节的遍历过程中,每遍历2中获得的一个关键帧时,会先检测mvpLocalKeyFrames的大小是否到了上限,如果到了的话便直接break,剩下的关键帧也不会再去找neighbor了。个人理解,只有和当前帧共视程度越高的帧,其neighbor和当前帧获得高共视的可能性才越大。那么这里我们是不是应该在做1的时候,将得到的map按value由大到小排序呢?这样才能保证做完2后,mvplocalKFs那个变量是按共视高低排序的。大家都清楚map默认是按key值由小到大排列的,我之前在阅读源码的时候并没有发现作者在这里有实现对应的compare函数并做sort操作,基本确认没有按共视排序,所以这里存在些许疑问。是不是也有可能考虑到共视程度最高的那些帧找出临近10个关键帧大多数还都是现在已有的彼此?但即使这样,只要能找出不重复的,是不是也应该将这些优先选为local keyframe呢?那么关于这点大家也有自己的想法,欢迎评论区一起讨论哈,博客我虽然更的慢,但还是时常在线的^_^

更新局部地图点:UpdateLocalPoints()

在做完UpdateLocalKeyFrames之后,我们已经确定了当前帧周围哪些关键帧可以作为我们的邻居,那么这一步,我们要确定这些邻居都看到了哪些地图点。这一步比较清晰,直接把每一个关键帧match到的每一个mappoint都找出来并放到mvpLocalMapPoints中,代码中每push一个点,进行pMP->mnTrackReferenceForFrame==mCurrentFrame.mnId,可避免mappoint点重复。

寻找匹配:SearchLocalPoints()

以上两步操作已经确定了当前帧附近的关键帧以及地图点信息,现在要做的就是将前面找出的但还没有与当前帧有匹配的那些地图点投到当前帧,进行匹配操作。这里的匹配思路是,首先利用几何关系进行投影,若能投到当前帧画布上,匹配投影位置周围的一些特征点的描述子。当最匹配的点的距离小于次最佳点的距离时,认为匹配成功。

姿态优化:Optimizer::PoseOptimization(&mCurrentFrame)

在有了更多匹配后,再一次优化当前帧的位姿,常规BA问题,目标问题是最小化重投影误差。

at last

在做完以上内容后,对当前帧mappoints的一些数据进行一次更新,并判断这次追踪局部地图是否成功。作者认为如果刚刚发生回环不久的情况下匹配内点数仍少于50,那么是一次失败的追踪;同时正常情况下,匹配到的内点数也要不少于30。

这就是关于tracklocalmap想要分享的全部内容啦,再说一次,后面一定会更加勤奋地更新博客的,即使工作再忙!

(以上全部为个人学习心得,如有错误欢迎评论指正,如有幸被转发,请标明转载出处)

你可能感兴趣的:(SLAM)