ORB-SLAM2源码学习(四)——局部建图LocalMapping.cc

 LocalMapping线程具体为一个run线程函数,其主要流程为:

  1. 插入关键帧
  2. 剔除不合格MapPoints
  3. 生成新MapPoints并局部BA
  4. 删除冗余关键帧
  5. 当前帧加入闭环队列中

ORB-SLAM2源码学习(四)——局部建图LocalMapping.cc_第1张图片

void LocalMapping::Run()
{

    mbFinished = false;

    while(1)
    {
        // Tracking will see that Local Mapping is busy
        // 告诉Tracking,LocalMapping正处于繁忙状态,
        // LocalMapping线程处理的关键帧都是Tracking线程发过的
        // 在LocalMapping线程还没有处理完关键帧之前Tracking线程最好不要发送太快
        SetAcceptKeyFrames(false);

        // Check if there are keyframes in the queue
        // 等待处理的关键帧列表不为空
        if(CheckNewKeyFrames())
        {
            // BoW conversion and insertion in Map
            // VI-A keyframe insertion
            // 计算关键帧特征点的BoW映射,将关键帧插入地图
            ProcessNewKeyFrame();

            // Check recent MapPoints
            // VI-B recent map points culling
            // 剔除ProcessNewKeyFrame函数中引入的不合格MapPoints
            MapPointCulling();

            // Triangulate new MapPoints
            // VI-C new map points creation
            // 相机运动过程中与相邻关键帧通过三角化恢复出一些MapPoints
            CreateNewMapPoints();

            // 已经处理完队列中的最后的一个关键帧
            if(!CheckNewKeyFrames())
            {
                // Find more matches in neighbor keyframes and fuse point duplications
                // 检查并融合当前关键帧与相邻帧(两级相邻)重复的MapPoints
                SearchInNeighbors();
            }

            mbAbortBA = false;

            // 已经处理完队列中的最后的一个关键帧,并且闭环检测没有请求停止LocalMapping
            if(!CheckNewKeyFrames() && !stopRequested())
            {
                // VI-D Local BA
                if(mpMap->KeyFramesInMap()>2)
                    Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpMap);

                // Check redundant local Keyframes
                // VI-E local keyframes culling
                // 检测并剔除当前帧相邻的关键帧中冗余的关键帧
                // 剔除的标准是:该关键帧的90%的MapPoints可以被其它关键帧观测到
                // trick! 
                // Tracking中先把关键帧交给LocalMapping线程
                // 并且在Tracking中InsertKeyFrame函数的条件比较松,交给LocalMapping线程的关键帧会比较密
                // 在这里再删除冗余的关键帧
                KeyFrameCulling();
            }

            // 将当前帧加入到闭环检测队列中
            mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame);
        }
        else if(Stop())
        {
            // Safe area to stop
            while(isStopped() && !CheckFinish())
            {
                // usleep(3000);
                std::this_thread::sleep_for(std::chrono::milliseconds(3));
            }
            if(CheckFinish())
                break;
        }

        ResetIfRequested();

        // Tracking will see that Local Mapping is not busy
        SetAcceptKeyFrames(true);

        if(CheckFinish())
            break;

        //usleep(3000);
        std::this_thread::sleep_for(std::chrono::milliseconds(3));

    }

    SetFinish();
}

一、插入关键帧ProcessNewKeyFrame()

  1. 计算当前关键帧Bow,便于后面三角化恢复新地图点;

  2. 将TrackLocalMap中跟踪局部地图匹配上的地图点绑定到当前关键帧(在Tracking线程中只是通过匹配进行局部地图跟踪,优化当前关键帧姿态),也就是在graph中加入当前关键帧作为node,并更新edge。而CreateNewMapPoint()中则通过当前关键帧,在局部地图中添加新的地图点

  3. 更新加入当前关键帧之后关键帧之间的连接关系,包括更新Covisibility图和Essential图(最小生成树spanning tree,共视关系好的边subset of edges from covisibility graph with high covisibility (θ=100), 闭环边)。

二、剔除不合适的MapPoints MapPointCulling()

  1. 跟踪(匹配上)到该地图点的普通帧帧数(IncreaseFound)<应该观测到该地图点的普通帧数量(25%*IncreaseVisible):该地图点虽在视野范围内,但很少被普通帧检测到。

  2. 从添加该地图点的关键帧算起的初始三个关键帧,第一帧不算,后面两帧看到该地图点的帧数,对于单目<=2,对于双目和RGBD<=3;因此在地图点刚建立的阶段,要求比较严格,很容易被剔除;而且单目的要求更严格,需要三帧都看到。若从添加该地图点的关键帧算起,一共有了大于三个关键帧,还存在列表中,则说明该地图点是高质量的,从检查列表中去掉。

       3.从2点可以看到,剔除过程剔除的点包括ProcessNewKeyFrame()与CreateNewMapPoints()引入的MapPoints

三、生成新的MapPoints CreateNewMapPoints()

  1. 取共视前20的关键帧
  2. 遍历每一相邻帧进行三角化生成3D点
  3. 检查3D点正向景深、视差、反投影误差和尺度一致性
  4. 3D点构造成MapPoints,并检查二级相邻关键帧进行融合

四、删除冗余帧KeyFrameCulling()

为了控制重建的紧凑度,LocalMapping会去检测冗余的关键帧,然后删除它们。这样的话会有利于控制,随着关键帧数目增长后,局部BA的复杂度。因为除非视角改变了,否则关键帧的数量在相同的环境中不应该无休止地增长。这里将那些有90%的点能够被超过三个关键帧观察到的关键帧认为是冗余关键帧,并将其删除。

最后将通过的关键帧加入闭环检测队列中。
 

你可能感兴趣的:(slam)