ORB_SLAM3源码阅读笔记(三)

发布时间 2023-04-03 14:37:40作者: Shang-Zhi

LocalMapping 线程

    与Tracking线程一样,同样从LocalMapping线程的创建开始逐步对LocalMapping进行分析。

1 LocalMapping 线程的创建

mpLocalMapper = new LocalMapping(this, mpAtlas, mSensor==MONOCULAR || mSensor==IMU_MONOCULAR,mSensor==IMU_MONOCULAR || mSensor==IMU_STEREO || mSensor==IMU_RGBD, strSequence);

    在System类的构造函数中创建了LocalMapping类的mpLocalMapper这样一个对象,现在进入LocalMapping类的的构造函数中查看具体的内容,在构造函数中并没有特别,仅仅只是进行了一些成员变量的初始化。接着往下看:

mptLocalMapping = new thread(&ORB_SLAM3::LocalMapping::Run,mpLocalMapper);

原来关键在这里,关键在于LocalMapping类的run()函数,该条语句的执行也代表着LocalMapping线程的正式启动。上面这条语句表示线程将运行类中的成员函数Run,传入的参数为LocalMapping类对象的一个指针。

2 Run 函数

    现在只需要明白Run函数中是如何工作的,整个线程的工作也就清晰明了了。进入Run()函数发现该函数的主体是一个“死循环”(没错,就是“死循环”)。在Run()函数中,通过对多个和Tracking类共享的变量进行查询,判断是否需要进行LocalMapping。在整个循环中关键在于if(CheckNewKeyFrames() && !mbBadImu)判断,如果满足条件则会进入真正核心的部分。现在假设满足该条件进行进一步分析(根据程序运行自上而下的顺序进行分析)。

  • CheckNewKeyFrames() 函数
    对于CheckNewKeyFrames() 函数,它的作用就是检查是否有新的关键帧输入进来(关键帧列表是否为空,因为LocalMapping每次处理完一个关键帧就会将其从列表中删除)。
  • ProcessNewKeyFrame() 函数
    ProcessNewKeyFrame() 函数首先会将容器中的新的关键帧删除,接着计算关键帧的词袋模型并进行匹配,如果匹配结果良好则添加到地图点容器中,并将当前帧添加到地图的关键帧容器中。
  • MapPointCulling() 函数
    MapPointCulling() 函数目的在于检查最近的地图点,该函数对最近新添加的地图点进行检查,如果新添加的地图点计算得到的值小于阈值则认为是坏点,此时该点将从地图中删除。
  • CreateNewMapPoints() 函数
    CreateNewMapPoints() 函数对新的地图点进行三角剖分,在该函数中针对单目,取了30帧可见性关键帧,关于IMU部分的内容暂时不看,函数最终返回的也是 MapPoint 类型。

2.1 进入“死循环”

  进入“死循环”,首先对地图中关键帧的个数进行判断,当帧数大于2时进入,如果只是单目的话则执行以下的代码:

 Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpCurrentKeyFrame->GetMap(),num_FixedKF_BA,num_OptKF_BA,num_MPs_BA,num_edges_BA);
 b_doneLBA = true;

该部分的代码就是开始进行 BA 优化了,这里暂时不对 BA 优化进行说明,后续再进行详细说明。BA 优化完成后同样先跳过IMU部分,然后开始进行本地冗余帧的检查,关键函数为KeyFrameCulling()。函数中作者的注释是这样描述的“如果看到关键帧 90% 的地图点,则该关键帧被认为是多余的,在至少其他 3 个关键帧中(相同或更精细的比例),我们只考虑接近的立体点”。整个过程的不断重复,直到完成标志位为“True”时跳出“死循环”。

  以上所有的描述仅仅为最简介的方式进行了大致粗略的说明,后续还需要对每一部分的细节更进一步的进行分析描述。