• ORB-SLAM2从理论到代码实现(十):LoopClosing程序详解


    LoopClosing是专门负责做闭环的类,它的主要功能就是检测闭环,计算闭环帧的相对位姿病以此做闭环修正。

    1. 成员变量

    1. std::list mlpLoopKeyFrameQueue; // 关键帧队列
    2. std::mutex mMutexLoopQueue;
    3. // Loop detector parameters
    4. float mnCovisibilityConsistencyTh;
    5. // Loop detector variables
    6. KeyFrame* mpCurrentKF;
    7. KeyFrame* mpMatchedKF;
    8. std::vector mvConsistentGroups;
    9. std::vector mvpEnoughConsistentCandidates;
    10. std::vector mvpCurrentConnectedKFs;
    11. std::vector mvpCurrentMatchedPoints;
    12. std::vector mvpLoopMapPoints;
    13. cv::Mat mScw;
    14. g2o::Sim3 mg2oScw;

    2. Run主循环

    1. void LoopClosing::Run()
    2. {
    3. mbFinished =false;
    4. while(1)
    5. {
    6. // Check if there are keyframes in the queue
    7. if(CheckNewKeyFrames())
    8. {
    9. // Detect loop candidates and check covisibility consistency
    10. if(DetectLoop())
    11. {
    12. // Compute similarity transformation [sR|t]
    13. // In the stereo/RGBD case s=1
    14. // 单目情况因为尺度是不可观的,所以是sim3,双目、RGBD、有IMU等有尺度的情况下,变为SE3
    15. if(ComputeSim3()) // 主要是判断该闭环是否可靠,只有在十分可靠的情况下才进行闭环计算
    16. {
    17. // Perform loop fusion and pose graph optimization
    18. CorrectLoop();
    19. }
    20. }
    21. }
    22. ResetIfRequested();
    23. if(CheckFinish())
    24. break;
    25. usleep(5000);
    26. }
    27. SetFinish();
    28. }

    2. InsertKeyFrame插入关键帧

    LocalMapping模块处理完关键帧之后把它插入进来

    1. void LoopClosing::InsertKeyFrame(KeyFrame *pKF)
    2. {
    3. unique_lock lock(mMutexLoopQueue);
    4. if(pKF->mnId!=0)
    5. mlpLoopKeyFrameQueue.push_back(pKF);
    6. }

    3. DetectLoop:检测闭环

    它的主要流程包括:

    1)如果地图中的关键帧数小于10,那么不进行闭环检测

    2)获取共视关键帧,并计算他们和当前关键帧之间的BoW分数,求得最低分

    3)通过上一步计算出的最低分数到数据库中查找出候选关键帧,这一步相当于是找到了曾经到过此处的关键帧们

    4)对候选关键帧集进行连续性检测

    1. bool LoopClosing::DetectLoop()
    2. {
    3. {
    4. // 取出队首的关键帧,也就是最旧的关键帧
    5. unique_lock lock(mMutexLoopQueue);
    6. mpCurrentKF = mlpLoopKeyFrameQueue.front();
    7. mlpLoopKeyFrameQueue.pop_front();
    8. // Avoid that a keyframe can be erased while it is being process by this thread
    9. mpCurrentKF->SetNotErase();
    10. }
    11. //If the map contains less than 10 KF or less than 10 KF have passed from last loop detection
    12. // 如果距离上次闭环小于10帧,则不进行闭环检测
    13. if(mpCurrentKF->mnId10)
    14. {
    15. mpKeyFrameDB->add(mpCurrentKF);
    16. mpCurrentKF->SetErase();
    17. return false;
    18. }
    19. // Compute reference BoW similarity score
    20. // This is the lowest score to a connected keyframe in the covisibility graph
    21. // We will impose loop candidates to have a higher similarity than this
    22. //计算当前帧及其共视关键帧的词袋模型匹配得分,获得最小得分minScore
    23. const vector vpConnectedKeyFrames = mpCurrentKF->GetVectorCovisibleKeyFrames();
    24. const DBoW2::BowVector &CurrentBowVec = mpCurrentKF->mBowVec;
    25. float minScore = 1;
    26. for(size_t i=0; isize(); i++)
    27. {
    28. KeyFrame* pKF = vpConnectedKeyFrames[i];
    29. if(pKF->isBad())
    30. continue;
    31. const DBoW2::BowVector &BowVec = pKF->mBowVec;
    32. float score = mpORBVocabulary->score(CurrentBowVec, BowVec);
    33. if(score
    34. minScore = score;
    35. }
    36. // Query the database imposing the minimum score
    37. //在除去当前帧共视关系的关键帧数据中,检测闭环候选帧(这个函数在KeyFrameDatabase中)
    38. //闭环候选帧删选过程:
    39. //1,BoW得分>minScore;
    40. //2,统计满足1的关键帧中有共同单子最多的单词数maxcommonwords
    41. //3,筛选出共同单词数大于mincommons(=0.8*maxcommons)的关键帧
    42. //4,相连的关键帧分为一组,计算组得分(总分),得到最大总分bestAccScore,筛选出总分大于minScoreToRetain(=0.75*bestAccScore)的组
    43. //用得分最高的候选帧IAccScoreAndMathch代表该组,计算组得分的目的是剔除单独一帧得分较高,但是没有共视关键帧作为闭环来说不够鲁棒
    44. //对于通过了闭环检测的关键帧,还需要通过连续性检测(连续三帧都通过上面的筛选),才能作为闭环候选帧
    45. vector vpCandidateKFs = mpKeyFrameDB->DetectLoopCandidates(mpCurrentKF, minScore);
    46. // If there are no loop candidates, just add new keyframe and return false
    47. if(vpCandidateKFs.empty())
    48. {
    49. mpKeyFrameDB->add(mpCurrentKF);
    50. mvConsistentGroups.clear();
    51. mpCurrentKF->SetErase();
    52. return false;
    53. }
    54. // For each loop candidate check consistency with previous loop candidates
    55. // Each candidate expands a covisibility group (keyframes connected to the loop candidate in the covisibility graph)
    56. // A group is consistent with a previous group if they share at least a keyframe
    57. // We must detect a consistent loop in several consecutive keyframes to accept it
    58. // 在候选帧中检测具有连续性的候选帧
    59. // 每个候选帧将与自己相连的关键帧构成一个“候选组spCandidateGroup”
    60. // 检测“候选组”中每一个关键帧是否存在于“连续组”,如果存在nCurrentConsistency++,将该“候选组”放入“当前连续组vCurrentConsistentGroups”
    61. // 如果nCurrentConsistency大于等于3,那么该”子候选组“代表的候选帧过关,进入mvpEnoughConsistentCandidates
    62. mvpEnoughConsistentCandidates.clear();
    63. vector vCurrentConsistentGroups;
    64. vector<bool> vbConsistentGroup(mvConsistentGroups.size(),false);
    65. for(size_t i=0, iend=vpCandidateKFs.size(); i
    66. {
    67. KeyFrame* pCandidateKF = vpCandidateKFs[i];
    68. // 将自己以及与自己相连的关键帧构成一个“候选组”
    69. set spCandidateGroup = pCandidateKF->GetConnectedKeyFrames();
    70. spCandidateGroup.insert(pCandidateKF);
    71. bool bEnoughConsistent = false;
    72. bool bConsistentForSomeGroup = false;
    73. // 遍历之前的“连续组”
    74. for(size_t iG=0, iendG=mvConsistentGroups.size(); iG
    75. {
    76. // 取出一个之前的连续组
    77. set sPreviousGroup = mvConsistentGroups[iG].first;
    78. // 遍历每个“候选组”,检测候选组中每一个关键帧在“连续组”中是否存在
    79. bool bConsistent = false;
    80. for(set::iterator sit=spCandidateGroup.begin(), send=spCandidateGroup.end(); sit!=send;sit++)
    81. {
    82. if(sPreviousGroup.count(*sit))
    83. {
    84. bConsistent=true;
    85. bConsistentForSomeGroup=true;// 该“候选组”至少与一个”连续组“相连
    86. break;
    87. }
    88. }
    89. if(bConsistent)
    90. {
    91. int nPreviousConsistency = mvConsistentGroups[iG].second;
    92. int nCurrentConsistency = nPreviousConsistency + 1;
    93. if(!vbConsistentGroup[iG])
    94. {
    95. ConsistentGroup cg = make_pair(spCandidateGroup,nCurrentConsistency);
    96. vCurrentConsistentGroups.push_back(cg);
    97. vbConsistentGroup[iG]=true; //this avoid to include the same group more than once
    98. }
    99. if(nCurrentConsistency>=mnCovisibilityConsistencyTh && !bEnoughConsistent)
    100. {
    101. mvpEnoughConsistentCandidates.push_back(pCandidateKF);
    102. bEnoughConsistent=true; //this avoid to insert the same candidate more than once
    103. }
    104. }
    105. }
    106. // If the group is not consistent with any previous group insert with consistency counter set to zero
    107. // 如果该“候选组”的所有关键帧都不存在于“连续组”,那么vCurrentConsistentGroups将为空,
    108. // 于是就把“子候选组”全部拷贝到vCurrentConsistentGroups,并最终用于更新mvConsistentGroups,计数设为0,重新开始
    109. if(!bConsistentForSomeGroup)
    110. {
    111. ConsistentGroup cg = make_pair(spCandidateGroup,0);
    112. vCurrentConsistentGroups.push_back(cg);
    113. }
    114. }
    115. // Update Covisibility Consistent Groups
    116. mvConsistentGroups = vCurrentConsistentGroups;
    117. // Add Current Keyframe to database
    118. mpKeyFrameDB->add(mpCurrentKF);
    119. if(mvpEnoughConsistentCandidates.empty())
    120. {
    121. mpCurrentKF->SetErase();
    122. return false;
    123. }
    124. else
    125. {
    126. return true;
    127. }
    128. mpCurrentKF->SetErase();
    129. return false;
    130. }

    2. ComputeSim3:计算两帧之间的相对位姿

    主要流程包括:

    1)对每一个闭环帧,通过BoW的matcher方法进行第一次匹配,匹配闭环帧和当前关键帧之间的匹配关系,如果对应关系少于20个,则丢弃,否则构造一个Sim3求解器并保存起来。

    2)对上一步得到的每一个满足条件的闭环帧,通过RANSAC迭代,求解Sim3。

    3)通过返回的Sim3进行第二次匹配。

    4)使用非线性最小二乘法优化Sim3.

    5)使用非线性最小二乘法优化Sim3.

    6)使用投影得到更多的匹配点,如果匹配点数量充足,则接受该闭环。

    1. bool LoopClosing::ComputeSim3()
    2. {
    3. // For each consistent loop candidate we try to compute a Sim3
    4. const int nInitialCandidates = mvpEnoughConsistentCandidates.size();
    5. // We compute first ORB matches for each candidate
    6. // If enough matches are found, we setup a Sim3Solver
    7. ORBmatcher matcher(0.75,true);
    8. vector vpSim3Solvers;
    9. vpSim3Solvers.resize(nInitialCandidates);
    10. vector > vvpMapPointMatches;
    11. vvpMapPointMatches.resize(nInitialCandidates);
    12. vector<bool> vbDiscarded;
    13. vbDiscarded.resize(nInitialCandidates);
    14. int nCandidates=0; //candidates with enough matches
    15. for(int i=0; i
    16. {
    17. // 闭环候选帧中取出一帧关键帧pKF
    18. KeyFrame* pKF = mvpEnoughConsistentCandidates[i];
    19. // avoid that local mapping erase it while it is being processed in this thread
    20. // 防止在LocalMapping中KeyFrameCulling函数将此关键帧作为冗余帧剔除
    21. pKF->SetNotErase();
    22. if(pKF->isBad())
    23. {
    24. vbDiscarded[i] = true;
    25. continue;
    26. }
    27. // 将当前帧mpCurrentKF与闭环候选关键帧pKF匹配
    28. // 通过bow加速得到mpCurrentKF与pKF之间的匹配特征点,vvpMapPointMatches是匹配特征点对应的MapPoints
    29. int nmatches = matcher.SearchByBoW(mpCurrentKF,pKF,vvpMapPointMatches[i]);
    30. // 匹配的特征点数太少,剔除
    31. if(nmatches<20)
    32. {
    33. vbDiscarded[i] = true;
    34. continue;
    35. }
    36. else
    37. {
    38. // 构造Sim3求解器
    39. // 如果mbFixScale为true,则是6DoFf优化,如果是false,则是7DoF优化(单目)
    40. Sim3Solver* pSolver = new Sim3Solver(mpCurrentKF,pKF,vvpMapPointMatches[i],mbFixScale);
    41. pSolver->SetRansacParameters(0.99,20,300);
    42. vpSim3Solvers[i] = pSolver;
    43. }
    44. // 参与Sim3计算的候选关键帧数加1
    45. nCandidates++;
    46. }
    47. bool bMatch = false;// 标记是否有一个候选帧通过Sim3的求解
    48. // Perform alternatively RANSAC iterations for each candidate
    49. // until one is succesful or all fail
    50. // 一直循环所有的候选帧,每个候选帧迭代5次,如果5次迭代后得不到结果,就换下一个候选帧
    51. // 直到有一个候选帧首次迭代成功,或者某个候选帧总的迭代次数超过限制,直接将它剔除
    52. while(nCandidates>0 && !bMatch)
    53. {
    54. for(int i=0; i
    55. {
    56. if(vbDiscarded[i])
    57. continue;
    58. KeyFrame* pKF = mvpEnoughConsistentCandidates[i];
    59. // Perform 5 Ransac Iterations
    60. vector<bool> vbInliers;
    61. int nInliers;
    62. bool bNoMore;
    63. // 对有较好的匹配的关键帧求取Sim3变换
    64. Sim3Solver* pSolver = vpSim3Solvers[i];
    65. cv::Mat Scm = pSolver->iterate(5,bNoMore,vbInliers,nInliers);
    66. // If Ransac reachs max. iterations discard keyframe
    67. // 总迭代次数达到最大限制还没有求出合格的Sim3变换,该候选帧剔除
    68. if(bNoMore)
    69. {
    70. vbDiscarded[i]=true;
    71. nCandidates--;
    72. }
    73. // If RANSAC returns a Sim3, perform a guided matching and optimize with all correspondences
    74. if(!Scm.empty())
    75. {
    76. vector vpMapPointMatches(vvpMapPointMatches[i].size(), static_cast(NULL));
    77. for(size_t j=0, jend=vbInliers.size(); j
    78. {
    79. // 保存inlier的MapPoint
    80. if(vbInliers[j])
    81. vpMapPointMatches[j]=vvpMapPointMatches[i][j];
    82. }
    83. // 通过步骤3求取的Sim3变换引导关键帧匹配弥补步骤2中的漏匹配
    84. cv::Mat R = pSolver->GetEstimatedRotation();
    85. cv::Mat t = pSolver->GetEstimatedTranslation();
    86. const float s = pSolver->GetEstimatedScale();
    87. // 查找更多的匹配 使用SearchByBoW进行特征点匹配时会有漏匹配
    88. // 通过Sim3变换,确定pKF1的特征点在pKF2中的大致区域,同理,确定pKF2的特征点在pKF1中的大致区域
    89. // 在该区域内通过描述子进行匹配pKF1和pKF2之前漏匹配的特征点,更新匹配vpMapPointMatches
    90. matcher.SearchBySim3(mpCurrentKF,pKF,vpMapPointMatches,s,R,t,7.5);
    91. // Sim3优化,只要有一个候选帧通过Sim3的求解与优化,就跳出停止对其它候选帧的判断
    92. g2o::Sim3 gScm(Converter::toMatrix3d(R),Converter::toVector3d(t),s);
    93. // 优化mpCurrentKF与pKF对应的MapPoints间的Sim3,得到优化后的量gScm
    94. const int nInliers = Optimizer::OptimizeSim3(mpCurrentKF, pKF, vpMapPointMatches, gScm, 10, mbFixScale);
    95. // If optimization is succesful stop ransacs and continue
    96. if(nInliers>=20)
    97. {
    98. bMatch = true;
    99. // mpMatchedKF是最终闭环检测出来与当前帧形成闭环的关键帧
    100. mpMatchedKF = pKF;
    101. // 得到从世界坐标系到该候选帧的Sim3变换
    102. g2o::Sim3 gSmw(Converter::toMatrix3d(pKF->GetRotation()),Converter::toVector3d(pKF->GetTranslation()),1.0);
    103. // 得到优化后从世界坐标系到当前帧的Sim3变换
    104. mg2oScw = gScm*gSmw;
    105. mScw = Converter::toCvMat(mg2oScw);
    106. mvpCurrentMatchedPoints = vpMapPointMatches;
    107. break;//跳出对其它候选帧的判断
    108. }
    109. }
    110. }
    111. }
    112. // 没有一个闭环匹配候选帧通过Sim3的求解与优化
    113. if(!bMatch)
    114. {
    115. for(int i=0; i
    116. mvpEnoughConsistentCandidates[i]->SetErase();
    117. mpCurrentKF->SetErase();
    118. return false;
    119. }
    120. // Retrieve MapPoints seen in Loop Keyframe and neighbors
    121. // 取出闭环匹配上关键帧的相连关键帧,得到它们的MapPoints放入mvpLoopMapPoints
    122. // 将mpMatchedKF相连的关键帧全部取出来放入vpLoopConnectedKFs
    123. vector vpLoopConnectedKFs = mpMatchedKF->GetVectorCovisibleKeyFrames();
    124. vpLoopConnectedKFs.push_back(mpMatchedKF);
    125. mvpLoopMapPoints.clear();
    126. for(vector::iterator vit=vpLoopConnectedKFs.begin(); vit!=vpLoopConnectedKFs.end(); vit++)
    127. {
    128. KeyFrame* pKF = *vit;
    129. vector vpMapPoints = pKF->GetMapPointMatches();
    130. for(size_t i=0, iend=vpMapPoints.size(); i
    131. {
    132. MapPoint* pMP = vpMapPoints[i];
    133. if(pMP)
    134. {
    135. if(!pMP->isBad() && pMP->mnLoopPointForKF!=mpCurrentKF->mnId)
    136. {
    137. mvpLoopMapPoints.push_back(pMP);
    138. pMP->mnLoopPointForKF=mpCurrentKF->mnId;
    139. }
    140. }
    141. }
    142. }
    143. // Find more matches projecting with the computed Sim3
    144. // 将闭环匹配上关键帧以及相连关键帧的MapPoints投影到当前关键帧进行投影匹配
    145. // 根据投影查找更多的匹配
    146. // 根据Sim3变换,将每个mvpLoopMapPoints投影到mpCurrentKF上,并根据尺度确定一个搜索区域,
    147. // 根据该MapPoint的描述子与该区域内的特征点进行匹配,如果匹配误差小于TH_LOW即匹配成功,更新mvpCurrentMatchedPoints
    148. matcher.SearchByProjection(mpCurrentKF, mScw, mvpLoopMapPoints, mvpCurrentMatchedPoints,10);
    149. // If enough matches accept Loop
    150. // 断当前帧与检测出的所有闭环关键帧是否有足够多的MapPoints匹配
    151. int nTotalMatches = 0;
    152. for(size_t i=0; isize(); i++)
    153. {
    154. if(mvpCurrentMatchedPoints[i])
    155. nTotalMatches++;
    156. }
    157. if(nTotalMatches>=40)
    158. {
    159. for(int i=0; i
    160. if(mvpEnoughConsistentCandidates[i]!=mpMatchedKF)
    161. mvpEnoughConsistentCandidates[i]->SetErase();
    162. return true;
    163. }
    164. else
    165. {
    166. for(int i=0; i
    167. mvpEnoughConsistentCandidates[i]->SetErase();
    168. mpCurrentKF->SetErase();
    169. return false;
    170. }
    171. }

    3. CorrectLoop:根据闭环做校正

    主要流程包括:

    1)如果有全局BA运算在运行的话,终止之前的BA运算。

    2)使用传播法计算每一个关键帧正确的Sim3变换值

    3)优化图

    4)全局BA优化

    1. void LoopClosing::CorrectLoop()
    2. {
    3. cout << "Loop detected!" << endl;
    4. // Send a stop signal to Local Mapping
    5. // Avoid new keyframes are inserted while correcting the loop
    6. //请求局部地图停止
    7. mpLocalMapper->RequestStop();
    8. // If a Global Bundle Adjustment is running, abort it
    9. if(isRunningGBA())
    10. {
    11. unique_lock lock(mMutexGBA);
    12. mbStopGBA = true;
    13. mnFullBAIdx++;
    14. if(mpThreadGBA)
    15. {
    16. mpThreadGBA->detach();
    17. delete mpThreadGBA;
    18. }
    19. }
    20. // Wait until Local Mapping has effectively stopped
    21. while(!mpLocalMapper->isStopped())
    22. {
    23. usleep(1000);
    24. }
    25. // Ensure current keyframe is updated
    26. // 根据共视关系更新当前帧与其它关键帧之间的连接
    27. mpCurrentKF->UpdateConnections();
    28. // Retrive keyframes connected to the current keyframe and compute corrected Sim3 pose by propagation
    29. // 得到Sim3优化后,与当前帧相连的关键帧的位姿,以及它们的MapPoints
    30. // 通过相对位姿关系,可以确定这些相连的关键帧与世界坐标系之间的Sim3变换
    31. // 取出与当前帧相连的关键帧,包括当前关键帧
    32. mvpCurrentConnectedKFs = mpCurrentKF->GetVectorCovisibleKeyFrames();
    33. mvpCurrentConnectedKFs.push_back(mpCurrentKF);
    34. KeyFrameAndPose CorrectedSim3, NonCorrectedSim3;
    35. CorrectedSim3[mpCurrentKF]=mg2oScw;
    36. cv::Mat Twc = mpCurrentKF->GetPoseInverse();
    37. {
    38. // Get Map Mutex
    39. unique_lock lock(mpMap->mMutexMapUpdate);
    40. // 得到Sim3调整后其它与当前帧相连关键帧的位姿
    41. for(vector::iterator vit=mvpCurrentConnectedKFs.begin(), vend=mvpCurrentConnectedKFs.end(); vit!=vend; vit++)
    42. {
    43. KeyFrame* pKFi = *vit;
    44. cv::Mat Tiw = pKFi->GetPose();
    45. if(pKFi!=mpCurrentKF)
    46. {
    47. // 得到当前帧到pKFi帧的相对变换
    48. cv::Mat Tic = Tiw*Twc;
    49. cv::Mat Ric = Tic.rowRange(0,3).colRange(0,3);
    50. cv::Mat tic = Tic.rowRange(0,3).col(3);
    51. g2o::Sim3 g2oSic(Converter::toMatrix3d(Ric),Converter::toVector3d(tic),1.0);
    52. // 当前帧的位姿固定不动,其它的关键帧根据相对关系得到Sim3调整的位姿
    53. g2o::Sim3 g2oCorrectedSiw = g2oSic*mg2oScw;
    54. //Pose corrected with the Sim3 of the loop closure
    55. // 得到闭环g2o优化后各个关键帧的位姿
    56. CorrectedSim3[pKFi]=g2oCorrectedSiw;
    57. }
    58. cv::Mat Riw = Tiw.rowRange(0,3).colRange(0,3);
    59. cv::Mat tiw = Tiw.rowRange(0,3).col(3);
    60. g2o::Sim3 g2oSiw(Converter::toMatrix3d(Riw),Converter::toVector3d(tiw),1.0);
    61. //Pose without correction
    62. // 当前帧相连关键帧,没有进行闭环优化的位姿
    63. NonCorrectedSim3[pKFi]=g2oSiw;
    64. }
    65. // Correct all MapPoints obsrved by current keyframe and neighbors, so that they align with the other side of the loop
    66. // 上一步得到调整相连帧位姿后,修正这些关键帧的地图点
    67. for(KeyFrameAndPose::iterator mit=CorrectedSim3.begin(), mend=CorrectedSim3.end(); mit!=mend; mit++)
    68. {
    69. KeyFrame* pKFi = mit->first;
    70. g2o::Sim3 g2oCorrectedSiw = mit->second;
    71. g2o::Sim3 g2oCorrectedSwi = g2oCorrectedSiw.inverse();
    72. g2o::Sim3 g2oSiw =NonCorrectedSim3[pKFi];
    73. vector vpMPsi = pKFi->GetMapPointMatches();
    74. for(size_t iMP=0, endMPi = vpMPsi.size(); iMP
    75. {
    76. MapPoint* pMPi = vpMPsi[iMP];
    77. if(!pMPi)
    78. continue;
    79. if(pMPi->isBad())
    80. continue;
    81. if(pMPi->mnCorrectedByKF==mpCurrentKF->mnId)
    82. continue;
    83. // Project with non-corrected pose and project back with corrected pose
    84. cv::Mat P3Dw = pMPi->GetWorldPos();
    85. Eigen::Matrix<double,3,1> eigP3Dw = Converter::toVector3d(P3Dw);
    86. Eigen::Matrix<double,3,1> eigCorrectedP3Dw = g2oCorrectedSwi.map(g2oSiw.map(eigP3Dw));
    87. cv::Mat cvCorrectedP3Dw = Converter::toCvMat(eigCorrectedP3Dw);
    88. pMPi->SetWorldPos(cvCorrectedP3Dw);
    89. pMPi->mnCorrectedByKF = mpCurrentKF->mnId;
    90. pMPi->mnCorrectedReference = pKFi->mnId;
    91. pMPi->UpdateNormalAndDepth();
    92. }
    93. // Update keyframe pose with corrected Sim3. First transform Sim3 to SE3 (scale translation)
    94. Eigen::Matrix3d eigR = g2oCorrectedSiw.rotation().toRotationMatrix();
    95. Eigen::Vector3d eigt = g2oCorrectedSiw.translation();
    96. double s = g2oCorrectedSiw.scale();
    97. eigt *=(1./s); //[R t/s;0 1]
    98. cv::Mat correctedTiw = Converter::toCvSE3(eigR,eigt);
    99. pKFi->SetPose(correctedTiw);
    100. // Make sure connections are updated
    101. pKFi->UpdateConnections();
    102. }
    103. // Start Loop Fusion
    104. // Update matched map points and replace if duplicated
    105. // 检查当前帧的MapPoints与闭环匹配帧的MapPoints是否存在冲突,对冲突的MapPoints进行替换或填补
    106. for(size_t i=0; isize(); i++)
    107. {
    108. if(mvpCurrentMatchedPoints[i])
    109. {
    110. MapPoint* pLoopMP = mvpCurrentMatchedPoints[i];
    111. MapPoint* pCurMP = mpCurrentKF->GetMapPoint(i);
    112. if(pCurMP) // 如果有重复的MapPoint,则用匹配帧的代替现有的
    113. pCurMP->Replace(pLoopMP);
    114. else // 如果当前帧没有该MapPoint,则直接添加
    115. {
    116. mpCurrentKF->AddMapPoint(pLoopMP,i);
    117. pLoopMP->AddObservation(mpCurrentKF,i);
    118. pLoopMP->ComputeDistinctiveDescriptors();
    119. }
    120. }
    121. }
    122. }
    123. // Project MapPoints observed in the neighborhood of the loop keyframe
    124. // into the current keyframe and neighbors using corrected poses.
    125. // Fuse duplications.
    126. // 通过将闭环时相连关键帧的mvpLoopMapPoints投影到这些关键帧中,进行MapPoints检查与替换
    127. SearchAndFuse(CorrectedSim3);
    128. // After the MapPoint fusion, new links in the covisibility graph will appear attaching both sides of the loop
    129. // 更新当前关键帧之间的共视相连关系,得到因闭环时MapPoints融合而新得到的连接关系
    130. map > LoopConnections;
    131. // 遍历当前帧相连关键帧
    132. for(vector::iterator vit=mvpCurrentConnectedKFs.begin(), vend=mvpCurrentConnectedKFs.end(); vit!=vend; vit++)
    133. {
    134. KeyFrame* pKFi = *vit;
    135. // 得到与当前帧相连关键帧的相连关键帧(二级相连)
    136. vector vpPreviousNeighbors = pKFi->GetVectorCovisibleKeyFrames();
    137. // Update connections. Detect new links.
    138. // 更新一级相连关键帧的连接关系
    139. pKFi->UpdateConnections();
    140. // 取出该帧更新后的连接关系
    141. LoopConnections[pKFi]=pKFi->GetConnectedKeyFrames();
    142. // 从连接关系中去除闭环之前的二级连接关系,剩下的是由闭环得到的连接关系
    143. for(vector::iterator vit_prev=vpPreviousNeighbors.begin(), vend_prev=vpPreviousNeighbors.end(); vit_prev!=vend_prev; vit_prev++)
    144. {
    145. LoopConnections[pKFi].erase(*vit_prev);
    146. }
    147. // 从连接关系中去除闭环之前的一级连接关系,剩下的是由闭环得到的连接关系
    148. for(vector::iterator vit2=mvpCurrentConnectedKFs.begin(), vend2=mvpCurrentConnectedKFs.end(); vit2!=vend2; vit2++)
    149. {
    150. LoopConnections[pKFi].erase(*vit2);
    151. }
    152. }
    153. // Optimize graph
    154. // 进行EssentialGraph优化,LoopConnections是形成闭环后新生成的连接关系
    155. Optimizer::OptimizeEssentialGraph(mpMap, mpMatchedKF, mpCurrentKF, NonCorrectedSim3, CorrectedSim3, LoopConnections, mbFixScale);
    156. mpMap->InformNewBigChange();
    157. // Add loop edge
    158. // 添加当前帧与闭环匹配帧之间的边
    159. mpMatchedKF->AddLoopEdge(mpCurrentKF);
    160. mpCurrentKF->AddLoopEdge(mpMatchedKF);
    161. // Launch a new thread to perform Global Bundle Adjustment
    162. // 新建一个线程用于全局BA优化
    163. mbRunningGBA = true;
    164. mbFinishedGBA = false;
    165. mbStopGBA = false;
    166. mpThreadGBA = new thread(&LoopClosing::RunGlobalBundleAdjustment,this,mpCurrentKF->mnId);
    167. // Loop closed. Release Local Mapping.
    168. mpLocalMapper->Release();
    169. mLastLoopKFid = mpCurrentKF->mnId;
    170. }

    4. MergeLocal

    1. void LoopClosing::MergeLocal()
    2. {
    3. Verbose::PrintMess("MERGE: Merge Visual detected!!!!", Verbose::VERBOSITY_NORMAL);
    4. int numTemporalKFs = 15;
    5. //Relationship to rebuild the essential graph, it is used two times, first in the local window and later in the rest of the map
    6. KeyFrame* pNewChild;
    7. KeyFrame* pNewParent;
    8. vector vpLocalCurrentWindowKFs;
    9. vector vpMergeConnectedKFs;
    10. // Flag that is true only when we stopped a running BA, in this case we need relaunch at the end of the merge
    11. bool bRelaunchBA = false;
    12. Verbose::PrintMess("MERGE: Check Full Bundle Adjustment", Verbose::VERBOSITY_DEBUG);
    13. // If a Global Bundle Adjustment is running, abort it
    14. if(isRunningGBA())
    15. {
    16. unique_lock lock(mMutexGBA);
    17. mbStopGBA = true;
    18. mnFullBAIdx++;
    19. if(mpThreadGBA)
    20. {
    21. mpThreadGBA->detach();
    22. delete mpThreadGBA;
    23. }
    24. bRelaunchBA = true;
    25. }
    26. Verbose::PrintMess("MERGE: Request Stop Local Mapping", Verbose::VERBOSITY_DEBUG);
    27. mpLocalMapper->RequestStop();
    28. // Wait until Local Mapping has effectively stopped
    29. while(!mpLocalMapper->isStopped())
    30. {
    31. usleep(1000);
    32. }
    33. Verbose::PrintMess("MERGE: Local Map stopped", Verbose::VERBOSITY_DEBUG);
    34. mpLocalMapper->EmptyQueue();
    35. // Merge map will become in the new active map with the local window of KFs and MPs from the current map.
    36. // Later, the elements of the current map will be transform to the new active map reference, in order to keep real time tracking
    37. Map* pCurrentMap = mpCurrentKF->GetMap();
    38. Map* pMergeMap = mpMergeMatchedKF->GetMap();
    39. // Ensure current keyframe is updated
    40. mpCurrentKF->UpdateConnections();
    41. //Get the current KF and its neighbors(visual->covisibles; inertial->temporal+covisibles)
    42. set spLocalWindowKFs;
    43. //Get MPs in the welding area from the current map
    44. set spLocalWindowMPs;
    45. if(pCurrentMap->IsInertial() && pMergeMap->IsInertial()) //TODO Check the correct initialization
    46. {
    47. KeyFrame* pKFi = mpCurrentKF;
    48. int nInserted = 0;
    49. while(pKFi && nInserted < numTemporalKFs)
    50. {
    51. spLocalWindowKFs.insert(pKFi);
    52. pKFi = mpCurrentKF->mPrevKF;
    53. nInserted++;
    54. set spMPi = pKFi->GetMapPoints();
    55. spLocalWindowMPs.insert(spMPi.begin(), spMPi.end());
    56. }
    57. pKFi = mpCurrentKF->mNextKF;
    58. while(pKFi)
    59. {
    60. spLocalWindowKFs.insert(pKFi);
    61. set spMPi = pKFi->GetMapPoints();
    62. spLocalWindowMPs.insert(spMPi.begin(), spMPi.end());
    63. }
    64. }
    65. else
    66. {
    67. spLocalWindowKFs.insert(mpCurrentKF);
    68. }
    69. vector vpCovisibleKFs = mpCurrentKF->GetBestCovisibilityKeyFrames(numTemporalKFs);
    70. spLocalWindowKFs.insert(vpCovisibleKFs.begin(), vpCovisibleKFs.end());
    71. const int nMaxTries = 3;
    72. int nNumTries = 0;
    73. while(spLocalWindowKFs.size() < numTemporalKFs && nNumTries < nMaxTries)
    74. {
    75. vector vpNewCovKFs;
    76. vpNewCovKFs.empty();
    77. for(KeyFrame* pKFi : spLocalWindowKFs)
    78. {
    79. vector vpKFiCov = pKFi->GetBestCovisibilityKeyFrames(numTemporalKFs/2);
    80. for(KeyFrame* pKFcov : vpKFiCov)
    81. {
    82. if(pKFcov && !pKFcov->isBad() && spLocalWindowKFs.find(pKFcov) == spLocalWindowKFs.end())
    83. {
    84. vpNewCovKFs.push_back(pKFcov);
    85. }
    86. }
    87. }
    88. spLocalWindowKFs.insert(vpNewCovKFs.begin(), vpNewCovKFs.end());
    89. nNumTries++;
    90. }
    91. //TODO TEST
    92. //vector vpTestKFs = pCurrentMap->GetAllKeyFrames();
    93. //spLocalWindowKFs.insert(vpTestKFs.begin(), vpTestKFs.end());
    94. for(KeyFrame* pKFi : spLocalWindowKFs)
    95. {
    96. if(!pKFi || pKFi->isBad())
    97. continue;
    98. set spMPs = pKFi->GetMapPoints();
    99. spLocalWindowMPs.insert(spMPs.begin(), spMPs.end());
    100. }
    101. set spMergeConnectedKFs;
    102. if(pCurrentMap->IsInertial() && pMergeMap->IsInertial()) //TODO Check the correct initialization
    103. {
    104. KeyFrame* pKFi = mpMergeMatchedKF;
    105. int nInserted = 0;
    106. while(pKFi && nInserted < numTemporalKFs)
    107. {
    108. spMergeConnectedKFs.insert(pKFi);
    109. pKFi = mpCurrentKF->mPrevKF;
    110. nInserted++;
    111. }
    112. pKFi = mpMergeMatchedKF->mNextKF;
    113. while(pKFi)
    114. {
    115. spMergeConnectedKFs.insert(pKFi);
    116. }
    117. }
    118. else
    119. {
    120. spMergeConnectedKFs.insert(mpMergeMatchedKF);
    121. }
    122. vpCovisibleKFs = mpMergeMatchedKF->GetBestCovisibilityKeyFrames(numTemporalKFs);
    123. spMergeConnectedKFs.insert(vpCovisibleKFs.begin(), vpCovisibleKFs.end());
    124. nNumTries = 0;
    125. while(spMergeConnectedKFs.size() < numTemporalKFs && nNumTries < nMaxTries)
    126. {
    127. vector vpNewCovKFs;
    128. for(KeyFrame* pKFi : spMergeConnectedKFs)
    129. {
    130. vector vpKFiCov = pKFi->GetBestCovisibilityKeyFrames(numTemporalKFs/2);
    131. for(KeyFrame* pKFcov : vpKFiCov)
    132. {
    133. if(pKFcov && !pKFcov->isBad() && spMergeConnectedKFs.find(pKFcov) == spMergeConnectedKFs.end())
    134. {
    135. vpNewCovKFs.push_back(pKFcov);
    136. }
    137. }
    138. }
    139. spMergeConnectedKFs.insert(vpNewCovKFs.begin(), vpNewCovKFs.end());
    140. nNumTries++;
    141. }
    142. set spMapPointMerge;
    143. for(KeyFrame* pKFi : spMergeConnectedKFs)
    144. {
    145. set vpMPs = pKFi->GetMapPoints();
    146. spMapPointMerge.insert(vpMPs.begin(),vpMPs.end());
    147. }
    148. vector vpCheckFuseMapPoint;
    149. vpCheckFuseMapPoint.reserve(spMapPointMerge.size());
    150. std::copy(spMapPointMerge.begin(), spMapPointMerge.end(), std::back_inserter(vpCheckFuseMapPoint));
    151. cv::Mat Twc = mpCurrentKF->GetPoseInverse();
    152. cv::Mat Rwc = Twc.rowRange(0,3).colRange(0,3);
    153. cv::Mat twc = Twc.rowRange(0,3).col(3);
    154. g2o::Sim3 g2oNonCorrectedSwc(Converter::toMatrix3d(Rwc),Converter::toVector3d(twc),1.0);
    155. g2o::Sim3 g2oNonCorrectedScw = g2oNonCorrectedSwc.inverse();
    156. g2o::Sim3 g2oCorrectedScw = mg2oMergeScw;
    157. KeyFrameAndPose vCorrectedSim3, vNonCorrectedSim3;
    158. vCorrectedSim3[mpCurrentKF]=g2oCorrectedScw;
    159. vNonCorrectedSim3[mpCurrentKF]=g2oNonCorrectedScw;
    160. for(KeyFrame* pKFi : spLocalWindowKFs)
    161. {
    162. if(!pKFi || pKFi->isBad())
    163. {
    164. continue;
    165. }
    166. g2o::Sim3 g2oCorrectedSiw;
    167. if(pKFi!=mpCurrentKF)
    168. {
    169. cv::Mat Tiw = pKFi->GetPose();
    170. cv::Mat Riw = Tiw.rowRange(0,3).colRange(0,3);
    171. cv::Mat tiw = Tiw.rowRange(0,3).col(3);
    172. g2o::Sim3 g2oSiw(Converter::toMatrix3d(Riw),Converter::toVector3d(tiw),1.0);
    173. //Pose without correction
    174. vNonCorrectedSim3[pKFi]=g2oSiw;
    175. cv::Mat Tic = Tiw*Twc;
    176. cv::Mat Ric = Tic.rowRange(0,3).colRange(0,3);
    177. cv::Mat tic = Tic.rowRange(0,3).col(3);
    178. g2o::Sim3 g2oSic(Converter::toMatrix3d(Ric),Converter::toVector3d(tic),1.0);
    179. g2oCorrectedSiw = g2oSic*mg2oMergeScw;
    180. vCorrectedSim3[pKFi]=g2oCorrectedSiw;
    181. }
    182. else
    183. {
    184. g2oCorrectedSiw = g2oCorrectedScw;
    185. }
    186. pKFi->mTcwMerge = pKFi->GetPose();
    187. // Update keyframe pose with corrected Sim3. First transform Sim3 to SE3 (scale translation)
    188. Eigen::Matrix3d eigR = g2oCorrectedSiw.rotation().toRotationMatrix();
    189. Eigen::Vector3d eigt = g2oCorrectedSiw.translation();
    190. double s = g2oCorrectedSiw.scale();
    191. pKFi->mfScale = s;
    192. eigt *=(1./s); //[R t/s;0 1]
    193. cv::Mat correctedTiw = Converter::toCvSE3(eigR,eigt);
    194. pKFi->mTcwMerge = correctedTiw;
    195. // Make sure connections are updated
    196. if(pCurrentMap->isImuInitialized())
    197. {
    198. Eigen::Matrix3d Rcor = eigR.transpose()*vNonCorrectedSim3[pKFi].rotation().toRotationMatrix();
    199. pKFi->mVwbMerge = Converter::toCvMat(Rcor)*pKFi->GetVelocity();
    200. }
    201. //TODO DEBUG to know which are the KFs that had been moved to the other map
    202. //pKFi->mnOriginMapId = 5;
    203. }
    204. for(MapPoint* pMPi : spLocalWindowMPs)
    205. {
    206. if(!pMPi || pMPi->isBad())
    207. continue;
    208. KeyFrame* pKFref = pMPi->GetReferenceKeyFrame();
    209. g2o::Sim3 g2oCorrectedSwi = vCorrectedSim3[pKFref].inverse();
    210. g2o::Sim3 g2oNonCorrectedSiw = vNonCorrectedSim3[pKFref];
    211. // Project with non-corrected pose and project back with corrected pose
    212. cv::Mat P3Dw = pMPi->GetWorldPos();
    213. Eigen::Matrix<double,3,1> eigP3Dw = Converter::toVector3d(P3Dw);
    214. Eigen::Matrix<double,3,1> eigCorrectedP3Dw = g2oCorrectedSwi.map(g2oNonCorrectedSiw.map(eigP3Dw));
    215. Eigen::Matrix3d eigR = g2oCorrectedSwi.rotation().toRotationMatrix();
    216. Eigen::Matrix3d Rcor = eigR * g2oNonCorrectedSiw.rotation().toRotationMatrix();
    217. cv::Mat cvCorrectedP3Dw = Converter::toCvMat(eigCorrectedP3Dw);
    218. pMPi->mPosMerge = cvCorrectedP3Dw;
    219. pMPi->mNormalVectorMerge = Converter::toCvMat(Rcor) * pMPi->GetNormal();
    220. }
    221. {
    222. unique_lock currentLock(pCurrentMap->mMutexMapUpdate); // We update the current map with the Merge information
    223. unique_lock mergeLock(pMergeMap->mMutexMapUpdate); // We remove the Kfs and MPs in the merged area from the old map
    224. for(KeyFrame* pKFi : spLocalWindowKFs)
    225. {
    226. if(!pKFi || pKFi->isBad())
    227. {
    228. continue;
    229. }
    230. pKFi->mTcwBefMerge = pKFi->GetPose();
    231. pKFi->mTwcBefMerge = pKFi->GetPoseInverse();
    232. pKFi->SetPose(pKFi->mTcwMerge);
    233. // Make sure connections are updated
    234. pKFi->UpdateMap(pMergeMap);
    235. pKFi->mnMergeCorrectedForKF = mpCurrentKF->mnId;
    236. pMergeMap->AddKeyFrame(pKFi);
    237. pCurrentMap->EraseKeyFrame(pKFi);
    238. if(pCurrentMap->isImuInitialized())
    239. {
    240. pKFi->SetVelocity(pKFi->mVwbMerge);
    241. }
    242. }
    243. for(MapPoint* pMPi : spLocalWindowMPs)
    244. {
    245. if(!pMPi || pMPi->isBad())
    246. continue;
    247. pMPi->SetWorldPos(pMPi->mPosMerge);
    248. pMPi->SetNormalVector(pMPi->mNormalVectorMerge);
    249. pMPi->UpdateMap(pMergeMap);
    250. pMergeMap->AddMapPoint(pMPi);
    251. pCurrentMap->EraseMapPoint(pMPi);
    252. }
    253. mpAtlas->ChangeMap(pMergeMap);
    254. mpAtlas->SetMapBad(pCurrentMap);
    255. pMergeMap->IncreaseChangeIndex();
    256. }
    257. //Rebuild the essential graph in the local window
    258. pCurrentMap->GetOriginKF()->SetFirstConnection(false);
    259. pNewChild = mpCurrentKF->GetParent(); // Old parent, it will be the new child of this KF
    260. pNewParent = mpCurrentKF; // Old child, now it will be the parent of its own parent(we need eliminate this KF from children list in its old parent)
    261. mpCurrentKF->ChangeParent(mpMergeMatchedKF);
    262. while(pNewChild )
    263. {
    264. pNewChild->EraseChild(pNewParent); // We remove the relation between the old parent and the new for avoid loop
    265. KeyFrame * pOldParent = pNewChild->GetParent();
    266. pNewChild->ChangeParent(pNewParent);
    267. pNewParent = pNewChild;
    268. pNewChild = pOldParent;
    269. }
    270. //Update the connections between the local window
    271. mpMergeMatchedKF->UpdateConnections();
    272. vpMergeConnectedKFs = mpMergeMatchedKF->GetVectorCovisibleKeyFrames();
    273. vpMergeConnectedKFs.push_back(mpMergeMatchedKF);
    274. vpCheckFuseMapPoint.reserve(spMapPointMerge.size());
    275. std::copy(spMapPointMerge.begin(), spMapPointMerge.end(), std::back_inserter(vpCheckFuseMapPoint));
    276. // Project MapPoints observed in the neighborhood of the merge keyframe
    277. // into the current keyframe and neighbors using corrected poses.
    278. // Fuse duplications.
    279. SearchAndFuse(vCorrectedSim3, vpCheckFuseMapPoint);
    280. // Update connectivity
    281. for(KeyFrame* pKFi : spLocalWindowKFs)
    282. {
    283. if(!pKFi || pKFi->isBad())
    284. continue;
    285. pKFi->UpdateConnections();
    286. }
    287. for(KeyFrame* pKFi : spMergeConnectedKFs)
    288. {
    289. if(!pKFi || pKFi->isBad())
    290. continue;
    291. pKFi->UpdateConnections();
    292. }
    293. bool bStop = false;
    294. Verbose::PrintMess("MERGE: Start local BA ", Verbose::VERBOSITY_DEBUG);
    295. vpLocalCurrentWindowKFs.clear();
    296. vpMergeConnectedKFs.clear();
    297. std::copy(spLocalWindowKFs.begin(), spLocalWindowKFs.end(), std::back_inserter(vpLocalCurrentWindowKFs));
    298. std::copy(spMergeConnectedKFs.begin(), spMergeConnectedKFs.end(), std::back_inserter(vpMergeConnectedKFs));
    299. if (mpTracker->mSensor==System::IMU_MONOCULAR || mpTracker->mSensor==System::IMU_STEREO)
    300. {
    301. Optimizer::MergeInertialBA(mpLocalMapper->GetCurrKF(),mpMergeMatchedKF,&bStop, mpCurrentKF->GetMap(),vCorrectedSim3);
    302. }
    303. else
    304. {
    305. Optimizer::LocalBundleAdjustment(mpCurrentKF, vpLocalCurrentWindowKFs, vpMergeConnectedKFs,&bStop);
    306. }
    307. // Loop closed. Release Local Mapping.
    308. mpLocalMapper->Release();
    309. Verbose::PrintMess("MERGE: Finish the LBA", Verbose::VERBOSITY_DEBUG);
    310. //Update the non critical area from the current map to the merged map
    311. vector vpCurrentMapKFs = pCurrentMap->GetAllKeyFrames();
    312. vector vpCurrentMapMPs = pCurrentMap->GetAllMapPoints();
    313. if(vpCurrentMapKFs.size() == 0)
    314. {
    315. Verbose::PrintMess("MERGE: There are not KFs outside of the welding area", Verbose::VERBOSITY_DEBUG);
    316. }
    317. else
    318. {
    319. Verbose::PrintMess("MERGE: Calculate the new position of the elements outside of the window", Verbose::VERBOSITY_DEBUG);
    320. //Apply the transformation
    321. {
    322. if(mpTracker->mSensor == System::MONOCULAR)
    323. {
    324. unique_lock currentLock(pCurrentMap->mMutexMapUpdate); // We update the current map with the Merge information
    325. for(KeyFrame* pKFi : vpCurrentMapKFs)
    326. {
    327. if(!pKFi || pKFi->isBad() || pKFi->GetMap() != pCurrentMap)
    328. {
    329. continue;
    330. }
    331. g2o::Sim3 g2oCorrectedSiw;
    332. cv::Mat Tiw = pKFi->GetPose();
    333. cv::Mat Riw = Tiw.rowRange(0,3).colRange(0,3);
    334. cv::Mat tiw = Tiw.rowRange(0,3).col(3);
    335. g2o::Sim3 g2oSiw(Converter::toMatrix3d(Riw),Converter::toVector3d(tiw),1.0);
    336. //Pose without correction
    337. vNonCorrectedSim3[pKFi]=g2oSiw;
    338. cv::Mat Tic = Tiw*Twc;
    339. cv::Mat Ric = Tic.rowRange(0,3).colRange(0,3);
    340. cv::Mat tic = Tic.rowRange(0,3).col(3);
    341. g2o::Sim3 g2oSim(Converter::toMatrix3d(Ric),Converter::toVector3d(tic),1.0);
    342. g2oCorrectedSiw = g2oSim*mg2oMergeScw;
    343. vCorrectedSim3[pKFi]=g2oCorrectedSiw;
    344. // Update keyframe pose with corrected Sim3. First transform Sim3 to SE3 (scale translation)
    345. Eigen::Matrix3d eigR = g2oCorrectedSiw.rotation().toRotationMatrix();
    346. Eigen::Vector3d eigt = g2oCorrectedSiw.translation();
    347. double s = g2oCorrectedSiw.scale();
    348. pKFi->mfScale = s;
    349. eigt *=(1./s); //[R t/s;0 1]
    350. cv::Mat correctedTiw = Converter::toCvSE3(eigR,eigt);
    351. pKFi->mTcwBefMerge = pKFi->GetPose();
    352. pKFi->mTwcBefMerge = pKFi->GetPoseInverse();
    353. pKFi->SetPose(correctedTiw);
    354. if(pCurrentMap->isImuInitialized())
    355. {
    356. Eigen::Matrix3d Rcor = eigR.transpose()*vNonCorrectedSim3[pKFi].rotation().toRotationMatrix();
    357. pKFi->SetVelocity(Converter::toCvMat(Rcor)*pKFi->GetVelocity()); // TODO: should add here scale s
    358. }
    359. }
    360. for(MapPoint* pMPi : vpCurrentMapMPs)
    361. {
    362. if(!pMPi || pMPi->isBad()|| pMPi->GetMap() != pCurrentMap)
    363. continue;
    364. KeyFrame* pKFref = pMPi->GetReferenceKeyFrame();
    365. g2o::Sim3 g2oCorrectedSwi = vCorrectedSim3[pKFref].inverse();
    366. g2o::Sim3 g2oNonCorrectedSiw = vNonCorrectedSim3[pKFref];
    367. // Project with non-corrected pose and project back with corrected pose
    368. cv::Mat P3Dw = pMPi->GetWorldPos();
    369. Eigen::Matrix<double,3,1> eigP3Dw = Converter::toVector3d(P3Dw);
    370. Eigen::Matrix<double,3,1> eigCorrectedP3Dw = g2oCorrectedSwi.map(g2oNonCorrectedSiw.map(eigP3Dw));
    371. cv::Mat cvCorrectedP3Dw = Converter::toCvMat(eigCorrectedP3Dw);
    372. pMPi->SetWorldPos(cvCorrectedP3Dw);
    373. pMPi->UpdateNormalAndDepth();
    374. }
    375. }
    376. }
    377. mpLocalMapper->RequestStop();
    378. // Wait until Local Mapping has effectively stopped
    379. while(!mpLocalMapper->isStopped())
    380. {
    381. usleep(1000);
    382. }
    383. // Optimize graph (and update the loop position for each element form the begining to the end)
    384. if(mpTracker->mSensor != System::MONOCULAR)
    385. {
    386. Optimizer::OptimizeEssentialGraph(mpCurrentKF, vpMergeConnectedKFs, vpLocalCurrentWindowKFs, vpCurrentMapKFs, vpCurrentMapMPs);
    387. }
    388. {
    389. // Get Merge Map Mutex
    390. unique_lock currentLock(pCurrentMap->mMutexMapUpdate); // We update the current map with the Merge information
    391. unique_lock mergeLock(pMergeMap->mMutexMapUpdate); // We remove the Kfs and MPs in the merged area from the old map
    392. for(KeyFrame* pKFi : vpCurrentMapKFs)
    393. {
    394. if(!pKFi || pKFi->isBad() || pKFi->GetMap() != pCurrentMap)
    395. {
    396. continue;
    397. }
    398. // Make sure connections are updated
    399. pKFi->UpdateMap(pMergeMap);
    400. pMergeMap->AddKeyFrame(pKFi);
    401. pCurrentMap->EraseKeyFrame(pKFi);
    402. }
    403. for(MapPoint* pMPi : vpCurrentMapMPs)
    404. {
    405. if(!pMPi || pMPi->isBad())
    406. continue;
    407. pMPi->UpdateMap(pMergeMap);
    408. pMergeMap->AddMapPoint(pMPi);
    409. pCurrentMap->EraseMapPoint(pMPi);
    410. }
    411. }
    412. }
    413. mpLocalMapper->Release();
    414. Verbose::PrintMess("MERGE:Completed!!!!!", Verbose::VERBOSITY_DEBUG);
    415. if(bRelaunchBA && (!pCurrentMap->isImuInitialized() || (pCurrentMap->KeyFramesInMap()<200 && mpAtlas->CountMaps()==1)))
    416. {
    417. // Launch a new thread to perform Global Bundle Adjustment
    418. Verbose::PrintMess("Relaunch Global BA", Verbose::VERBOSITY_DEBUG);
    419. mbRunningGBA = true;
    420. mbFinishedGBA = false;
    421. mbStopGBA = false;
    422. mpThreadGBA = new thread(&LoopClosing::RunGlobalBundleAdjustment,this, pMergeMap, mpCurrentKF->mnId);
    423. }
    424. mpMergeMatchedKF->AddMergeEdge(mpCurrentKF);
    425. mpCurrentKF->AddMergeEdge(mpMergeMatchedKF);
    426. pCurrentMap->IncreaseChangeIndex();
    427. pMergeMap->IncreaseChangeIndex();
    428. mpAtlas->RemoveBadMaps();
    429. }

    参考文献

    ORB SLAM2源码解读(十一):LoopClosing类 - 知乎

    https://blog.csdn.net/qq_45794281/article/details/121579998 

  • 相关阅读:
    光流法optical flow
    基于MiniTest的小程序自动化测试
    (Git)git clone报错——SSL certificate problem: self signed certificate
    2022年数学建模国赛--赛后总结
    string(讲解)
    ffmpeg基础四:RTP协议
    【历史上的今天】8 月 15 日:苹果推出初代 iMac;谷歌收购摩托罗拉移动;Fuchsia 首次发布
    数据安全:.[bkpsvr@firemail.cc].EKING勒索病毒的特点和数据恢复方法
    Java多线程篇(3)——线程池
    企业集中监控体系思路及架构
  • 原文地址:https://blog.csdn.net/xhtchina/article/details/119767848