ORB-SLAM3的LocalMapMerging线程详解

news/2024/11/30 3:33:31/

ORB-SLAM3的Local&MapMerging线程的代码主要集中于LocalClosing.cc的run()函数中,主要执行五个函数分别是:CheckNewKeyFrames() 函数、NewDetectCommonRegions()函数、MergeLocal()函数、MergeLocal2()函数、CorrectLoop() 函数。如果新进入的关键帧,在闭环检测的过程中,如果是当前地图下的,不用进入MergeLocal()函数和MergeLocal2()函数,直接做闭环校正;在非当前地图下,先做地图合并,再做闭环校正。

类型函数
boolCheckNewKeyFrames()
boolNewDetectCommonRegions()
voidMergeLocal()
voidMergeLocal2()
voidCorrectLoop()

文章目录

    • 一、LocalClosing的run()函数
      • 1、CheckNewKeyFrames()
      • 2、NewDetectCommonRegions()
      • 3、MergeLocal()
      • 4、MergeLocal2()
      • 5、CorrectLoop()
    • 二、代码详解
      • 1、LoopClosing.h
        • (1)参数
        • (2) 主函数Run()
        • (3) 插入关键帧函数InsertKeyFrame()
        • (4) 运行全局BA优化函数RunGlobalBundleAdjustment()
        • (5)是否有关键帧插入函数bool CheckNewKeyFrames()
        • (6)检测闭环函数()bool NewDetectCommonRegions();
        • (7)最后一帧中计算相似度()bool DetectAndReffineSim3FromLastKF();
        • (8)通过词袋去计算相似度函数()bool DetectCommonRegionsFromBoW();
      • 2、LoopClosing.cc

一、LocalClosing的run()函数

1、CheckNewKeyFrames()

检查队列mlpLoopKeyFrameQueue是否有未处理的关键帧

这个函数和局部建图线程是一样的,首先看队列里是否插入关键帧。对于局部建图线程是跟踪线程给的关键帧,那么对于闭环和地图合并线程是局部建图线程给的关键帧。所以观察是否有未处理的关键帧,如果有,往后执行。

2、NewDetectCommonRegions()

实现闭环检测

布尔函数,在函数中确定有无闭环,有闭环就地图合并。

3、MergeLocal()

非当前地图闭环情况下,纯视觉模式的地图合并与校正

纯视觉误差为重投影误差

4、MergeLocal2()

非当前地图闭环情况下,IMU模式的地图合并与校正

对IMU情况, 考虑IMU误差和视觉的重投影误差

5、CorrectLoop()

当前地图闭环情况下,闭环校正

二、代码详解

1、LoopClosing.h

(1)参数
LoopClosing(Atlas* pAtlas, KeyFrameDatabase* pDB, ORBVocabulary* pVoc,const bool bFixScale, const bool bActiveLC);
函数功能
Atlas多地图系统
KeyFrameDatabase关键帧库
ORBVocabularyORB词袋
bFixScale是否固定大小
bActiveLC主动闭环检测
(2) 主函数Run()
 void Run();

检查是否有执行关键帧到闭环和地图合并线程,闭环检测,地图合并,闭环校正

(3) 插入关键帧函数InsertKeyFrame()
void InsertKeyFrame(KeyFrame *pKF);

将关键帧插入线程

(4) 运行全局BA优化函数RunGlobalBundleAdjustment()
void RunGlobalBundleAdjustment(Map* pActiveMap, unsigned long nLoopKF);

涉及参数:主动图pActiveMap和闭环关键帧nLoopKF

(5)是否有关键帧插入函数bool CheckNewKeyFrames()

核心函数

(6)检测闭环函数()bool NewDetectCommonRegions();

核心函数

有闭环返回为true,没有则为flase

(7)最后一帧中计算相似度()bool DetectAndReffineSim3FromLastKF();

从最后一帧中计算Sim3相似度,通过共视图计算相似关系

(8)通过词袋去计算相似度函数()bool DetectCommonRegionsFromBoW();

通过词袋去计算相似度

2、LoopClosing.cc

/**@brief 回环线程主函数 */void LoopClosing::Run()
{mbFinished =false;// 线程主循环 while(1){//NEW LOOP AND MERGE DETECTION ALGORITHM//----------------------------// LoopClosing中的关键帧是LocalMapping发送过来的,LocalMapping是Tracking中发过来的// 在LocalMapping中通过 InsertKeyFrame 将关键帧插入闭环检测队列mlpLoopKeyFrameQueue// Step 1查看闭环检测队列mlpLoopKeyFrameQueue中有没有关键帧进来 if(CheckNewKeyFrames()){// 这部分后续未使用 if(mpLastCurrentKF){mpLastCurrentKF->mvpLoopCandKFs.clear();mpLastCurrentKF->mvpMergeCandKFs.clear();}
#ifdef REGISTER_TIMESstd::chrono::steady_clock::time_point time_StartPR = std::chrono::steady_clock::now();
#endif// Step 2检测有没有共视的区域 bool bFindedRegion = NewDetectCommonRegions();#ifdef REGISTER_TIMESstd::chrono::steady_clock::time_point time_EndPR = std::chrono::steady_clock::now();double timePRTotal = std::chrono::duration_cast<std::chrono::duration<double,std::milli> >(time_EndPR - time_StartPR).count();vdPRTotal_ms.push_back(timePRTotal);
#endifif(bFindedRegion){// Step 3如果检测到融合(当前关键帧与其他地图有关联),则合并地图 if(mbMergeDetected){if ((mpTracker->mSensor==System::IMU_MONOCULAR || mpTracker->mSensor==System::IMU_STEREO || mpTracker->mSensor==System::IMU_RGBD) &&(!mpCurrentKF->GetMap()->isImuInitialized())){cout << "IMU is not initilized, merge is aborted" << endl;}else{Sophus::SE3d mTmw = mpMergeMatchedKF->GetPose().cast<double>();g2o::Sim3 gSmw2(mTmw.unit_quaternion(), mTmw.translation(), 1.0);Sophus::SE3d mTcw = mpCurrentKF->GetPose().cast<double>();g2o::Sim3 gScw1(mTcw.unit_quaternion(), mTcw.translation(), 1.0);g2o::Sim3 gSw2c = mg2oMergeSlw.inverse();g2o::Sim3 gSw1m = mg2oMergeSlw;mSold_new = (gSw2c * gScw1);if(mpCurrentKF->GetMap()->IsInertial() && mpMergeMatchedKF->GetMap()->IsInertial()){cout << "Merge check transformation with IMU" << endl;if(mSold_new.scale()<0.90||mSold_new.scale()>1.1){mpMergeLastCurrentKF->SetErase();mpMergeMatchedKF->SetErase();mnMergeNumCoincidences = 0;mvpMergeMatchedMPs.clear();mvpMergeMPs.clear();mnMergeNumNotFound = 0;mbMergeDetected = false;Verbose::PrintMess("scale bad estimated. Abort merging", Verbose::VERBOSITY_NORMAL);continue;}// If inertial, force only yawif ((mpTracker->mSensor==System::IMU_MONOCULAR || mpTracker->mSensor==System::IMU_STEREO || mpTracker->mSensor==System::IMU_RGBD) &&mpCurrentKF->GetMap()->GetIniertialBA1()){Eigen::Vector3d phi = LogSO3(mSold_new.rotation().toRotationMatrix());phi(0)=0;phi(1)=0;mSold_new = g2o::Sim3(ExpSO3(phi),mSold_new.translation(),1.0);}}mg2oMergeSmw = gSmw2 * gSw2c * gScw1;mg2oMergeScw = mg2oMergeSlw;//mpTracker->SetStepByStep(true);Verbose::PrintMess("*Merge detected", Verbose::VERBOSITY_QUIET);#ifdef REGISTER_TIMESstd::chrono::steady_clock::time_point time_StartMerge = std::chrono::steady_clock::now();nMerges += 1;
#endif// TODO UNCOMMENTif (mpTracker->mSensor==System::IMU_MONOCULAR ||mpTracker->mSensor==System::IMU_STEREO || mpTracker->mSensor==System::IMU_RGBD)MergeLocal2();elseMergeLocal();#ifdef REGISTER_TIMESstd::chrono::steady_clock::time_point time_EndMerge = std::chrono::steady_clock::now();double timeMergeTotal = std::chrono::duration_cast<std::chrono::duration<double,std::milli> >(time_EndMerge - time_StartMerge).count();vdMergeTotal_ms.push_back(timeMergeTotal);
#endifVerbose::PrintMess("Merge finished!", Verbose::VERBOSITY_QUIET);}vdPR_CurrentTime.push_back(mpCurrentKF->mTimeStamp);vdPR_MatchedTime.push_back(mpMergeMatchedKF->mTimeStamp);vnPR_TypeRecogn.push_back(1);// Reset all variablesmpMergeLastCurrentKF->SetErase();mpMergeMatchedKF->SetErase();mnMergeNumCoincidences = 0;mvpMergeMatchedMPs.clear();mvpMergeMPs.clear();mnMergeNumNotFound = 0;mbMergeDetected = false;if(mbLoopDetected){// Reset Loop variablesmpLoopLastCurrentKF->SetErase();mpLoopMatchedKF->SetErase();mnLoopNumCoincidences = 0;mvpLoopMatchedMPs.clear();mvpLoopMPs.clear();mnLoopNumNotFound = 0;mbLoopDetected = false;}}if(mbLoopDetected){bool bGoodLoop = true;vdPR_CurrentTime.push_back(mpCurrentKF->mTimeStamp);vdPR_MatchedTime.push_back(mpLoopMatchedKF->mTimeStamp);vnPR_TypeRecogn.push_back(0);Verbose::PrintMess("*Loop detected", Verbose::VERBOSITY_QUIET);mg2oLoopScw = mg2oLoopSlw; //*mvg2oSim3LoopTcw[nCurrentIndex];if(mpCurrentKF->GetMap()->IsInertial()){Sophus::SE3d Twc = mpCurrentKF->GetPoseInverse().cast<double>();g2o::Sim3 g2oTwc(Twc.unit_quaternion(),Twc.translation(),1.0);g2o::Sim3 g2oSww_new = g2oTwc*mg2oLoopScw;Eigen::Vector3d phi = LogSO3(g2oSww_new.rotation().toRotationMatrix());cout << "phi = " << phi.transpose() << endl; if (fabs(phi(0))<0.008f && fabs(phi(1))<0.008f && fabs(phi(2))<0.349f){if(mpCurrentKF->GetMap()->IsInertial()){// If inertial, force only yawif ((mpTracker->mSensor==System::IMU_MONOCULAR ||mpTracker->mSensor==System::IMU_STEREO || mpTracker->mSensor==System::IMU_RGBD) &&mpCurrentKF->GetMap()->GetIniertialBA2()){phi(0)=0;phi(1)=0;g2oSww_new = g2o::Sim3(ExpSO3(phi),g2oSww_new.translation(),1.0);mg2oLoopScw = g2oTwc.inverse()*g2oSww_new;}}}else{cout << "BAD LOOP!!!" << endl;bGoodLoop = false;}}if (bGoodLoop) {mvpLoopMapPoints = mvpLoopMPs;#ifdef REGISTER_TIMESstd::chrono::steady_clock::time_point time_StartLoop = std::chrono::steady_clock::now();nLoop += 1;#endifCorrectLoop();
#ifdef REGISTER_TIMESstd::chrono::steady_clock::time_point time_EndLoop = std::chrono::steady_clock::now();double timeLoopTotal = std::chrono::duration_cast<std::chrono::duration<double,std::milli> >(time_EndLoop - time_StartLoop).count();vdLoopTotal_ms.push_back(timeLoopTotal);
#endifmnNumCorrection += 1;}// Reset all variablesmpLoopLastCurrentKF->SetErase();mpLoopMatchedKF->SetErase();mnLoopNumCoincidences = 0;mvpLoopMatchedMPs.clear();mvpLoopMPs.clear();mnLoopNumNotFound = 0;mbLoopDetected = false;}}mpLastCurrentKF = mpCurrentKF;}ResetIfRequested();if(CheckFinish()){break;}usleep(5000);}SetFinish();
}

在这里插入图片描述


http://www.ppmy.cn/news/1282759.html

相关文章

微积分-第四章极限-1

第四章 极限 4.1 极限的基本思想 考虑函数 f ( x ) 2 x f(x)2x f(x)2x。当 x x x趋向于2时 f ( x ) f(x) f(x)会趋向与何值&#xff1f;显而易见的是函数 f f f在 x 2 x2 x2处有定义。所以我们可以说当 x x x趋向于2时 f ( x ) f(x) f(x)趋向于4。 我们可以直接写出 lim ⁡…

2013年第二届数学建模国际赛小美赛A题数学与经济灾难解题全过程文档及程序

2013年第二届数学建模国际赛小美赛 A题 数学与经济灾难 原题再现&#xff1a; 2008年的市场崩盘使世界陷入经济衰退&#xff0c;目前世界经济仍处于低迷状态&#xff0c;其原因是多方面的。其中之一是数学。   当然&#xff0c;并非只有金融界依赖于并非总是可靠的数学模型…

[PyTorch][chapter 8][李宏毅深度学习][DNN 训练技巧]

前言&#xff1a; DNN 是神经网络的里面基础核心模型之一.这里面结合DNN 介绍一下如何解决 深度学习里面过拟合,欠拟合问题 目录&#xff1a; DNN 训练常见问题 过拟合处理 欠拟合处理 keras 项目 一 DNN 训练常见问题 我们在深度学习网络训练的时候经常会遇到下面…

qt项目-《图像标注软件》源码阅读笔记-CentralWidget类及其子类

目录 1. CentralWidget 概览 2. CentralWidget 基类 3. CentralWInit2D 3.1 源码 1. CentralWidget 概览 功能&#xff1a;CentralWidget 负责主窗口中心组件的界面初始化以及后续中心组件的管理。 其两个派生类分别负责2D、3D中心组件&#xff0c;2d和3d的模式可以进…

ros2+gazebo+urdf:ros2机器人使用gazebo的urdf文件中的<gazebo>部分官网资料

原文链接SDFormat extensions to URDF (the gazebo tag) — Documentation 注意了ros2的gazebo部分已经跟ros1的gazebo部分不一样了&#xff1a; Toggle navigation SpecificationAPIDocumentationDownload Back Edit Version: 1.6 Table of C…

【Java、Python】获取电脑当前网络IP进行位置获取(附源码)

我相信看到这篇博客的时候心里肯定是想解决自己的一个问题的&#xff0c;而这篇博客我就以简单快速的方式解决这些烦恼&#xff01; 一、获取当前IP 在Java中自带了一些自己的流对象来获取当前的IP地址&#xff0c;不多说我们直接上代码。 //获取当前网络ip地址 ipAddress Ine…

Graylog日志搜索技巧

graylog搜索日志用的语法是Syntax接近Lucene&#xff0c;搜起来比较方便 Search query languagehttps://go2docs.graylog.org/4-0/making_sense_of_your_log_data/writing_search_queries.html?tocpathSearching%20Your%20Log%20Data|_____1 1.Syntax 语法 1.1 基本匹配 搜…

SQL进阶:子查询

一般情况下,我们都是直接对表进行查询,但有时候,想要的数据可能通过一次select 获取不到,需要嵌套select,这样就形成了子查询。 子查询可以位于查询语句的任意位置,主要的注意点在于用于不同的位置,和不同的关键字一起使用时,需要注意返回的列的数量和行的数量。 位于…