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


    1. 流程图

    LocalMapping线程负责对新加入的KeyFrames和MapPoints筛选融合,剔除冗余的KeyFrames和MapPoints,维护稳定的KeyFrame集合,传给后续的LoopClosing线程。
    主要的功能点在:

    处理新的关键帧ProcessNewKeyFrame()

    剔除不合格地图点MapPointCulling()

    三角化恢复新地图点CreateNewMapPoints()

    融合当前帧与相邻帧重复的地图点SearchInNeighbors()

    局部BA优化LocalBundleAdjustment()

    剔除冗余关键帧KeyFrameCulling()

     

    2. 入口函数LocalMapping::Run()

    入口函数是LocalMapping.cc中的Run()函数,Run()函数也相当于LocalMapping的主函数。这个线程在系统运行起来的时候处于休眠或者等待状态。当有新的关键帧加入的时候线程就将自己设置为繁忙状态(告诉Tracking线程我很忙,暂时不接受新的关键帧)并立刻处理新的关键帧;当处理完一个关键帧后,就会将自己设置为空闲状态(告诉Tracking线程,我可以接受新的关键帧了)并进入睡眠状态3毫秒。当代码如下:

    1. void LocalMapping::Run()
    2. {
    3. mbFinished = false;
    4. while(1)
    5. {
    6. // Tracking will see that Local Mapping is busy
    7. // 告诉Tracking,LocalMapping正处于繁忙状态,
    8. // LocalMapping线程处理的关键帧都是Tracking线程发过的
    9. // 在LocalMapping线程还没有处理完关键帧之前Tracking线程最好不要发送太快
    10. SetAcceptKeyFrames(false);
    11. // Check if there are keyframes in the queue
    12. // 等待处理的关键帧列表不为空
    13. if(CheckNewKeyFrames())
    14. {
    15. // BoW conversion and insertion in Map
    16. ProcessNewKeyFrame();
    17. // Check recent MapPoints
    18. // 剔除ProcessNewKeyFrame函数中引入的不合格MapPoints
    19. MapPointCulling();
    20. // Triangulate new MapPoints
    21. // 相机运动过程中与相邻关键帧通过三角化恢复出一些MapPoints
    22. CreateNewMapPoints();
    23. // 已经处理完队列中的最后的一个关键帧
    24. if(!CheckNewKeyFrames())
    25. {
    26. // Find more matches in neighbor keyframes and fuse point duplications
    27. // 检查并融合当前关键帧与相邻帧(两级相邻)重复的MapPoints
    28. SearchInNeighbors();
    29. }
    30. mbAbortBA = false;
    31. if(!CheckNewKeyFrames() && !stopRequested())
    32. {
    33. // Local BA
    34. if(mpMap->KeyFramesInMap()>2)
    35. Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpMap);
    36. // Check redundant local Keyframes
    37. // 检测并剔除当前帧相邻的关键帧中冗余的关键帧
    38. // 剔除的标准是:该关键帧的90%的MapPoints可以被其它关键帧观测到
    39. // trick!
    40. // Tracking中先把关键帧交给LocalMapping线程
    41. // 并且在Tracking中InsertKeyFrame函数的条件比较松,交给LocalMapping线程的关键帧会比较密
    42. // 在这里再删除冗余的关键帧
    43. KeyFrameCulling();
    44. }
    45. // 将当前帧加入到闭环检测队列中
    46. mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame);
    47. }
    48. else if(Stop())
    49. {
    50. // Safe area to stop
    51. while(isStopped() && !CheckFinish())
    52. {
    53. usleep(3000);
    54. }
    55. if(CheckFinish())
    56. break;
    57. }
    58. ResetIfRequested();
    59. // Tracking will see that Local Mapping is busy
    60. SetAcceptKeyFrames(true);
    61. if(CheckFinish())
    62. break;
    63. usleep(3000);
    64. }
    65. SetFinish();
    66. }

    3. void LocalMapping::SetAcceptKeyFrames()

    告诉Tracking线程,LocalMapping是否处于繁忙状态。如果处于繁忙状态则不要再添加新的关键帧了,否则可以添加关键帧。

    1. void LocalMapping::SetAcceptKeyFrames(bool flag)
    2. {
    3. unique_lock lock(mMutexAccept);
    4. mbAcceptKeyFrames=flag;
    5. }

    4. void LocalMapping::ProcessNewKeyFrame()

    作用是,从队列取出第一个关键帧(该关键帧时队列中按时间上最旧的关键帧),计算该关键帧的Bow特征,更新关键帧观测到的地图点的信息,并且将该关键帧新生成的地图点添加进mlpRecentAddedMapPoints,等待后续检测。然后将该关键帧插入地图。

    1. void LocalMapping::ProcessNewKeyFrame()
    2. {
    3. {
    4. unique_lock lock(mMutexNewKFs);
    5. mpCurrentKeyFrame = mlNewKeyFrames.front();
    6. mlNewKeyFrames.pop_front();
    7. }
    8. // Compute Bags of Words structures
    9. mpCurrentKeyFrame->ComputeBoW();
    10. // Associate MapPoints to the new keyframe and update normal and descriptor
    11. const vector vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches();
    12. for(size_t i=0; isize(); i++)
    13. {
    14. MapPoint* pMP = vpMapPointMatches[i];
    15. if(pMP)
    16. {
    17. if(!pMP->isBad())
    18. {
    19. // 如果该地图点没有记录该帧,则添加上这个记录。
    20. if(!pMP->IsInKeyFrame(mpCurrentKeyFrame))
    21. {
    22. // i记录了地图点在关键帧中的索引
    23. pMP->AddObservation(mpCurrentKeyFrame, i);
    24. // 因为地图点增加了新的观测,而法向量是所有观测到该点的关键帧都求一个法徽号向量之后求均,所以需要更新
    25. pMP->UpdateNormalAndDepth();
    26. // 从所有关键帧的观测点中选择一个作为该点的描述子
    27. pMP->ComputeDistinctiveDescriptors();
    28. }
    29. else // this can only happen for new stereo points inserted by the Tracking
    30. {
    31. mlpRecentAddedMapPoints.push_back(pMP);
    32. }
    33. }
    34. }
    35. }
    36. // Update links in the Covisibility Graph
    37. mpCurrentKeyFrame->UpdateConnections();
    38. // Insert Keyframe in Map
    39. mpMap->AddKeyFrame(mpCurrentKeyFrame);
    40. }

    5. void LocalMapping::MapPointCulling()

    主要作用是筛选mlpRecentAddedMapPoints里的点,对于不好的点标记为bad。

    已经是坏点的MapPoints直接从检查链表中删除;
    跟踪到该MapPoint的Frame中被判定为内点的比例须大于25%,注意不一定是关键帧。
    从该点建立开始,到现在已经过了不小于2个关键帧,但是观测到该点的关键帧数却不超过cnThObs帧,那么该点检验不合格。
    从建立该点开始,已经过了3个关键帧而没有被剔除,则认为是质量高的点,因此没有SetBadFlag(),仅从队列中删除,放弃继续对该MapPoint的检测mlpRecentAddedMapPoints剩下的点,需要继续经过以后的检测。

    1. void LocalMapping::MapPointCulling()
    2. {
    3. // Check Recent Added MapPoints
    4. list::iterator lit = mlpRecentAddedMapPoints.begin();
    5. const unsigned long int nCurrentKFid = mpCurrentKeyFrame->mnId;
    6. int nThObs;
    7. if(mbMonocular)
    8. nThObs = 2;
    9. else
    10. nThObs = 3;
    11. const int cnThObs = nThObs;
    12. while(lit!=mlpRecentAddedMapPoints.end())
    13. {
    14. MapPoint* pMP = *lit;
    15. if(pMP->isBad())
    16. {
    17. lit = mlpRecentAddedMapPoints.erase(lit);
    18. }
    19. else if(pMP->GetFoundRatio()<0.25f )
    20. {
    21. pMP->SetBadFlag();
    22. lit = mlpRecentAddedMapPoints.erase(lit);
    23. }
    24. else if(((int)nCurrentKFid-(int)pMP->mnFirstKFid)>=2 && pMP->Observations()<=cnThObs)
    25. {
    26. pMP->SetBadFlag();
    27. lit = mlpRecentAddedMapPoints.erase(lit);
    28. }
    29. else if(((int)nCurrentKFid-(int)pMP->mnFirstKFid)>=3)
    30. lit = mlpRecentAddedMapPoints.erase(lit);
    31. else
    32. lit++;
    33. }
    34. }

    5. void LocalMapping::CreateNewMapPoints()

    利用三角化新建一些地图点

    在当前关键帧的共视关键帧中找到共视程度最高的nn帧相邻帧vpNeighKFs
    遍历相邻关键帧vpNeighKFs,得到基线向量vBaseline = Ow2-Ow1
    判断相机运动的基线是不是足够长,邻接关键帧的场景深度中值medianDepthKF2,baseline与景深的比例,如果特别远(比例特别小),那么不考虑当前邻接的关键帧,不生成3D点
    根据两个关键帧的位姿计算它们之间的基本矩阵F
    通过极线约束限制匹配时的搜索范围,对满足对极约束的特征点进行特征点匹配
    对每对匹配通过三角化生成3D点,和Triangulate函数差不多
    接着分别检查新得到的点在两个平面上的重投影误差,如果大于一定的值,直接抛弃该点。
    检查尺度连续性
    如果满足对极约束则建立当前帧的地图点及其属性(a.观测到该MapPoint的关键帧 b.该MapPoint的描述子 c.该MapPoint的平均观测方向和深度范围)
    将地图点加入关键帧,加入全局map

    1. void LocalMapping::CreateNewMapPoints()
    2. {
    3. // Retrieve neighbor keyframes in covisibility graph
    4. int nn = 10;
    5. if(mbMonocular)
    6. nn=20;
    7. //在当前关键帧的共视关键帧中找到共视程度最高的nn帧相邻帧vpNeighKFs
    8. const vector vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn);
    9. ORBmatcher matcher(0.6,false);
    10. cv::Mat Rcw1 = mpCurrentKeyFrame->GetRotation();
    11. cv::Mat Rwc1 = Rcw1.t();
    12. cv::Mat tcw1 = mpCurrentKeyFrame->GetTranslation();
    13. cv::Mat Tcw1(3,4,CV_32F);
    14. Rcw1.copyTo(Tcw1.colRange(0,3));
    15. tcw1.copyTo(Tcw1.col(3));
    16. cv::Mat Ow1 = mpCurrentKeyFrame->GetCameraCenter();
    17. const float &fx1 = mpCurrentKeyFrame->fx;
    18. const float &fy1 = mpCurrentKeyFrame->fy;
    19. const float &cx1 = mpCurrentKeyFrame->cx;
    20. const float &cy1 = mpCurrentKeyFrame->cy;
    21. const float &invfx1 = mpCurrentKeyFrame->invfx;
    22. const float &invfy1 = mpCurrentKeyFrame->invfy;
    23. const float ratioFactor = 1.5f*mpCurrentKeyFrame->mfScaleFactor;
    24. int nnew=0;
    25. // Search matches with epipolar restriction and triangulate
    26. for(size_t i=0; isize(); i++)
    27. {
    28. // 基于实时性考虑,如果已经处理了与新关键帧最邻近的一个关键帧,但又来了更新的关键帧,则停止立即返回,去处理更新的关键帧。
    29. if(i>0 && CheckNewKeyFrames())
    30. return;
    31. KeyFrame* pKF2 = vpNeighKFs[i];
    32. // Check first that baseline is not too short
    33. cv::Mat Ow2 = pKF2->GetCameraCenter();
    34. cv::Mat vBaseline = Ow2-Ow1;
    35. const float baseline = cv::norm(vBaseline);
    36. if(!mbMonocular)
    37. {
    38. if(baselinemb)
    39. continue;
    40. }
    41. else
    42. {
    43. const float medianDepthKF2 = pKF2->ComputeSceneMedianDepth(2);
    44. const float ratioBaselineDepth = baseline/medianDepthKF2;
    45. if(ratioBaselineDepth<0.01)
    46. continue;
    47. }
    48. // Compute Fundamental Matrix
    49. //根据两个关键帧的位姿计算它们之间的基本矩阵F
    50. cv::Mat F12 = ComputeF12(mpCurrentKeyFrame,pKF2);
    51. // Search matches that fullfil epipolar constraint
    52. vectorsize_t,size_t> > vMatchedIndices;
    53. matcher.SearchForTriangulation(mpCurrentKeyFrame,pKF2,F12,vMatchedIndices,false);
    54. cv::Mat Rcw2 = pKF2->GetRotation();
    55. cv::Mat Rwc2 = Rcw2.t();
    56. cv::Mat tcw2 = pKF2->GetTranslation();
    57. cv::Mat Tcw2(3,4,CV_32F);
    58. Rcw2.copyTo(Tcw2.colRange(0,3));
    59. tcw2.copyTo(Tcw2.col(3));
    60. const float &fx2 = pKF2->fx;
    61. const float &fy2 = pKF2->fy;
    62. const float &cx2 = pKF2->cx;
    63. const float &cy2 = pKF2->cy;
    64. const float &invfx2 = pKF2->invfx;
    65. const float &invfy2 = pKF2->invfy;
    66. // Triangulate each match
    67. const int nmatches = vMatchedIndices.size();
    68. for(int ikp=0; ikp
    69. {
    70. const int &idx1 = vMatchedIndices[ikp].first;
    71. const int &idx2 = vMatchedIndices[ikp].second;
    72. const cv::KeyPoint &kp1 = mpCurrentKeyFrame->mvKeysUn[idx1];
    73. const float kp1_ur=mpCurrentKeyFrame->mvuRight[idx1];
    74. bool bStereo1 = kp1_ur>=0; // 在上一帧中被双目观测到
    75. const cv::KeyPoint &kp2 = pKF2->mvKeysUn[idx2];
    76. const float kp2_ur = pKF2->mvuRight[idx2];
    77. bool bStereo2 = kp2_ur>=0; // 在当前帧中被双目观测到
    78. // Check parallax between rays
    79. cv::Mat xn1 = (cv::Mat_<float>(3,1) << (kp1.pt.x-cx1)*invfx1, (kp1.pt.y-cy1)*invfy1, 1.0);
    80. cv::Mat xn2 = (cv::Mat_<float>(3,1) << (kp2.pt.x-cx2)*invfx2, (kp2.pt.y-cy2)*invfy2, 1.0);
    81. cv::Mat ray1 = Rwc1*xn1;
    82. cv::Mat ray2 = Rwc2*xn2;
    83. const float cosParallaxRays = ray1.dot(ray2)/(cv::norm(ray1)*cv::norm(ray2));
    84. float cosParallaxStereo = cosParallaxRays+1;
    85. float cosParallaxStereo1 = cosParallaxStereo;
    86. float cosParallaxStereo2 = cosParallaxStereo;
    87. if(bStereo1)
    88. cosParallaxStereo1 = cos(2*atan2(mpCurrentKeyFrame->mb/2,mpCurrentKeyFrame->mvDepth[idx1]));
    89. else if(bStereo2)
    90. cosParallaxStereo2 = cos(2*atan2(pKF2->mb/2,pKF2->mvDepth[idx2]));
    91. cosParallaxStereo = min(cosParallaxStereo1,cosParallaxStereo2);
    92. cv::Mat x3D;
    93. if(cosParallaxRays0 && (bStereo1 || bStereo2 || cosParallaxRays<0.9998))
    94. {
    95. // Linear Triangulation Method
    96. cv::Mat A(4,4,CV_32F);
    97. A.row(0) = xn1.at<float>(0)*Tcw1.row(2)-Tcw1.row(0);
    98. A.row(1) = xn1.at<float>(1)*Tcw1.row(2)-Tcw1.row(1);
    99. A.row(2) = xn2.at<float>(0)*Tcw2.row(2)-Tcw2.row(0);
    100. A.row(3) = xn2.at<float>(1)*Tcw2.row(2)-Tcw2.row(1);
    101. cv::Mat w,u,vt;
    102. cv::SVD::compute(A,w,u,vt,cv::SVD::MODIFY_A| cv::SVD::FULL_UV);
    103. x3D = vt.row(3).t();
    104. if(x3D.at<float>(3)==0)
    105. continue;
    106. // Euclidean coordinates
    107. x3D = x3D.rowRange(0,3)/x3D.at<float>(3);
    108. }
    109. else if(bStereo1 && cosParallaxStereo1
    110. {
    111. x3D = mpCurrentKeyFrame->UnprojectStereo(idx1);
    112. }
    113. else if(bStereo2 && cosParallaxStereo2
    114. {
    115. x3D = pKF2->UnprojectStereo(idx2);
    116. }
    117. else
    118. continue; //No stereo and very low parallax
    119. cv::Mat x3Dt = x3D.t();
    120. //Check triangulation in front of cameras
    121. float z1 = Rcw1.row(2).dot(x3Dt)+tcw1.at<float>(2);
    122. if(z1<=0)
    123. continue;
    124. float z2 = Rcw2.row(2).dot(x3Dt)+tcw2.at<float>(2);
    125. if(z2<=0)
    126. continue;
    127. //Check reprojection error in first keyframe
    128. const float &sigmaSquare1 = mpCurrentKeyFrame->mvLevelSigma2[kp1.octave];
    129. const float x1 = Rcw1.row(0).dot(x3Dt)+tcw1.at<float>(0);
    130. const float y1 = Rcw1.row(1).dot(x3Dt)+tcw1.at<float>(1);
    131. const float invz1 = 1.0/z1;
    132. if(!bStereo1)
    133. {
    134. float u1 = fx1*x1*invz1+cx1;
    135. float v1 = fy1*y1*invz1+cy1;
    136. float errX1 = u1 - kp1.pt.x;
    137. float errY1 = v1 - kp1.pt.y;
    138. if((errX1*errX1+errY1*errY1)>5.991*sigmaSquare1)
    139. continue;
    140. }
    141. else
    142. {
    143. float u1 = fx1*x1*invz1+cx1;
    144. float u1_r = u1 - mpCurrentKeyFrame->mbf*invz1;
    145. float v1 = fy1*y1*invz1+cy1;
    146. float errX1 = u1 - kp1.pt.x;
    147. float errY1 = v1 - kp1.pt.y;
    148. float errX1_r = u1_r - kp1_ur;
    149. if((errX1*errX1+errY1*errY1+errX1_r*errX1_r)>7.8*sigmaSquare1)
    150. continue;
    151. }
    152. //Check reprojection error in second keyframe
    153. const float sigmaSquare2 = pKF2->mvLevelSigma2[kp2.octave];
    154. const float x2 = Rcw2.row(0).dot(x3Dt)+tcw2.at<float>(0);
    155. const float y2 = Rcw2.row(1).dot(x3Dt)+tcw2.at<float>(1);
    156. const float invz2 = 1.0/z2;
    157. if(!bStereo2)
    158. {
    159. float u2 = fx2*x2*invz2+cx2;
    160. float v2 = fy2*y2*invz2+cy2;
    161. float errX2 = u2 - kp2.pt.x;
    162. float errY2 = v2 - kp2.pt.y;
    163. if((errX2*errX2+errY2*errY2)>5.991*sigmaSquare2)
    164. continue;
    165. }
    166. else
    167. {
    168. float u2 = fx2*x2*invz2+cx2;
    169. float u2_r = u2 - mpCurrentKeyFrame->mbf*invz2;
    170. float v2 = fy2*y2*invz2+cy2;
    171. float errX2 = u2 - kp2.pt.x;
    172. float errY2 = v2 - kp2.pt.y;
    173. float errX2_r = u2_r - kp2_ur;
    174. if((errX2*errX2+errY2*errY2+errX2_r*errX2_r)>7.8*sigmaSquare2)
    175. continue;
    176. }
    177. //Check scale consistency
    178. cv::Mat normal1 = x3D-Ow1;
    179. float dist1 = cv::norm(normal1);
    180. cv::Mat normal2 = x3D-Ow2;
    181. float dist2 = cv::norm(normal2);
    182. if(dist1==0 || dist2==0)
    183. continue;
    184. const float ratioDist = dist2/dist1;
    185. const float ratioOctave = mpCurrentKeyFrame->mvScaleFactors[kp1.octave]/pKF2->mvScaleFactors[kp2.octave];
    186. /*if(fabs(ratioDist-ratioOctave)>ratioFactor)
    187. continue;*/
    188. if(ratioDist*ratioFactorratioOctave*ratioFactor)
    189. continue;
    190. // Triangulation is succesfull
    191. MapPoint* pMP = new MapPoint(x3D,mpCurrentKeyFrame,mpMap);
    192. pMP->AddObservation(mpCurrentKeyFrame,idx1);
    193. pMP->AddObservation(pKF2,idx2);
    194. mpCurrentKeyFrame->AddMapPoint(pMP,idx1);
    195. pKF2->AddMapPoint(pMP,idx2);
    196. pMP->ComputeDistinctiveDescriptors();
    197. pMP->UpdateNormalAndDepth();
    198. mpMap->AddMapPoint(pMP);
    199. mlpRecentAddedMapPoints.push_back(pMP);
    200. nnew++;
    201. }
    202. }
    203. }

    6. void LocalMapping::SearchInNeighbors().

    检查并融合当前关键帧与相邻帧(两级相邻)重复的MapPoints,更新当前关键帧的连接关系。

    获得当前关键帧在covisibility图中权重排名前nn的邻接关键帧,找到当前帧一级相邻与二级相邻关键帧
    将当前帧的MapPoints分别与一级二级相邻帧(的MapPoints)进行融合
    matcher.Fuse(pKFi,vpMapPointMatches);
    投影当前帧的MapPoints到相邻关键帧pKFi中,并判断是否有重复的MapPoints
    如果MapPoint能匹配关键帧的特征点,并且该点有对应的MapPoint,那么将两个MapPoint合并(选择观测数多的)
    如果MapPoint能匹配关键帧的特征点,并且该点没有对应的MapPoint,那么为该点添加MapPoint
    将一级二级相邻帧的MapPoints分别与当前帧(的MapPoints)进行融合
    更新当前帧MapPoints的描述子,深度,观测主方向等属性
    在这里插入代码片
    更新当前帧的MapPoints后更新与其它帧的连接关系

    1. void LocalMapping::SearchInNeighbors()
    2. {
    3. // Retrieve neighbor keyframes
    4. int nn = 10;
    5. if(mbMonocular)
    6. nn=20;
    7. const vector vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn);
    8. vector vpTargetKFs;
    9. for(vector::const_iterator vit=vpNeighKFs.begin(), vend=vpNeighKFs.end(); vit!=vend; vit++)
    10. {
    11. KeyFrame* pKFi = *vit;
    12. if(pKFi->isBad() || pKFi->mnFuseTargetForKF == mpCurrentKeyFrame->mnId)
    13. continue;
    14. vpTargetKFs.push_back(pKFi);
    15. pKFi->mnFuseTargetForKF = mpCurrentKeyFrame->mnId;
    16. // Extend to some second neighbors
    17. const vector vpSecondNeighKFs = pKFi->GetBestCovisibilityKeyFrames(5);
    18. for(vector::const_iterator vit2=vpSecondNeighKFs.begin(), vend2=vpSecondNeighKFs.end(); vit2!=vend2; vit2++)
    19. {
    20. KeyFrame* pKFi2 = *vit2;
    21. if(pKFi2->isBad() || pKFi2->mnFuseTargetForKF==mpCurrentKeyFrame->mnId || pKFi2->mnId==mpCurrentKeyFrame->mnId)
    22. continue;
    23. vpTargetKFs.push_back(pKFi2);
    24. }
    25. }
    26. // Search matches by projection from current KF in target KFs
    27. ORBmatcher matcher;
    28. vector vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches();
    29. for(vector::iterator vit=vpTargetKFs.begin(), vend=vpTargetKFs.end(); vit!=vend; vit++)
    30. {
    31. KeyFrame* pKFi = *vit;
    32. matcher.Fuse(pKFi,vpMapPointMatches);
    33. }
    34. // Search matches by projection from target KFs in current KF
    35. vector vpFuseCandidates;
    36. vpFuseCandidates.reserve(vpTargetKFs.size()*vpMapPointMatches.size());
    37. for(vector::iterator vitKF=vpTargetKFs.begin(), vendKF=vpTargetKFs.end(); vitKF!=vendKF; vitKF++)
    38. {
    39. KeyFrame* pKFi = *vitKF;
    40. vector vpMapPointsKFi = pKFi->GetMapPointMatches();
    41. for(vector::iterator vitMP=vpMapPointsKFi.begin(), vendMP=vpMapPointsKFi.end(); vitMP!=vendMP; vitMP++)
    42. {
    43. MapPoint* pMP = *vitMP;
    44. if(!pMP)
    45. continue;
    46. if(pMP->isBad() || pMP->mnFuseCandidateForKF == mpCurrentKeyFrame->mnId)
    47. continue;
    48. pMP->mnFuseCandidateForKF = mpCurrentKeyFrame->mnId;
    49. vpFuseCandidates.push_back(pMP);
    50. }
    51. }
    52. matcher.Fuse(mpCurrentKeyFrame,vpFuseCandidates);
    53. // Update points
    54. vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches();
    55. for(size_t i=0, iend=vpMapPointMatches.size(); i
    56. {
    57. MapPoint* pMP=vpMapPointMatches[i];
    58. if(pMP)
    59. {
    60. if(!pMP->isBad())
    61. {
    62. pMP->ComputeDistinctiveDescriptors();
    63. pMP->UpdateNormalAndDepth();
    64. }
    65. }
    66. }
    67. // Update connections in covisibility graph
    68. mpCurrentKeyFrame->UpdateConnections();
    69. }

    7. void Optimizer::LocalBundleAdjustment()

    优化的顶点是包括局部地图帧的位姿,概念lLocalKeyFrames,指的是当前关键帧和其相连接的关键帧组成的集合。还包括这些关键帧可以观测到的所有地图点,地图点的位置也会优化。还有一些帧,这些帧能够观测到这些地图点,但却不是局部地图里,这些帧的位姿也作为顶点添加进图中,但是却固定不动,不会被优化。

    1. void Optimizer::LocalBundleAdjustment(KeyFrame *pKF, bool* pbStopFlag, Map* pMap)
    2. {
    3. // Local KeyFrames: First Breath Search from Current Keyframe
    4. list lLocalKeyFrames;
    5. lLocalKeyFrames.push_back(pKF);
    6. pKF->mnBALocalForKF = pKF->mnId;
    7. const vector vNeighKFs = pKF->GetVectorCovisibleKeyFrames();
    8. for(int i=0, iend=vNeighKFs.size(); i
    9. {
    10. KeyFrame* pKFi = vNeighKFs[i];
    11. pKFi->mnBALocalForKF = pKF->mnId;
    12. if(!pKFi->isBad())
    13. lLocalKeyFrames.push_back(pKFi);
    14. }
    15. // Local MapPoints seen in Local KeyFrames
    16. list lLocalMapPoints;
    17. for(list::iterator lit=lLocalKeyFrames.begin() , lend=lLocalKeyFrames.end(); lit!=lend; lit++)
    18. {
    19. vector vpMPs = (*lit)->GetMapPointMatches();
    20. for(vector::iterator vit=vpMPs.begin(), vend=vpMPs.end(); vit!=vend; vit++)
    21. {
    22. MapPoint* pMP = *vit;
    23. if(pMP)
    24. if(!pMP->isBad())
    25. if(pMP->mnBALocalForKF!=pKF->mnId)
    26. {
    27. lLocalMapPoints.push_back(pMP);
    28. pMP->mnBALocalForKF=pKF->mnId;
    29. }
    30. }
    31. }
    32. // Fixed Keyframes. Keyframes that see Local MapPoints but that are not Local Keyframes
    33. list lFixedCameras;
    34. for(list::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++)
    35. {
    36. mapsize_t> observations = (*lit)->GetObservations();
    37. for(mapsize_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    38. {
    39. KeyFrame* pKFi = mit->first;
    40. if(pKFi->mnBALocalForKF!=pKF->mnId && pKFi->mnBAFixedForKF!=pKF->mnId)
    41. {
    42. pKFi->mnBAFixedForKF=pKF->mnId;
    43. if(!pKFi->isBad())
    44. lFixedCameras.push_back(pKFi);
    45. }
    46. }
    47. }
    48. // Setup optimizer
    49. g2o::SparseOptimizer optimizer;
    50. g2o::BlockSolver_6_3::LinearSolverType * linearSolver;
    51. linearSolver = new g2o::LinearSolverEigen();
    52. g2o::BlockSolver_6_3 * solver_ptr = new g2o::BlockSolver_6_3(linearSolver);
    53. g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg(solver_ptr);
    54. optimizer.setAlgorithm(solver);
    55. if(pbStopFlag)
    56. optimizer.setForceStopFlag(pbStopFlag);
    57. unsigned long maxKFid = 0;
    58. // Set Local KeyFrame vertices
    59. for(list::iterator lit=lLocalKeyFrames.begin(), lend=lLocalKeyFrames.end(); lit!=lend; lit++)
    60. {
    61. KeyFrame* pKFi = *lit;
    62. g2o::VertexSE3Expmap * vSE3 = new g2o::VertexSE3Expmap();
    63. vSE3->setEstimate(Converter::toSE3Quat(pKFi->GetPose()));
    64. vSE3->setId(pKFi->mnId);
    65. vSE3->setFixed(pKFi->mnId==0);
    66. optimizer.addVertex(vSE3);
    67. if(pKFi->mnId>maxKFid)
    68. maxKFid=pKFi->mnId;
    69. }
    70. // Set Fixed KeyFrame vertices
    71. for(list::iterator lit=lFixedCameras.begin(), lend=lFixedCameras.end(); lit!=lend; lit++)
    72. {
    73. KeyFrame* pKFi = *lit;
    74. g2o::VertexSE3Expmap * vSE3 = new g2o::VertexSE3Expmap();
    75. vSE3->setEstimate(Converter::toSE3Quat(pKFi->GetPose()));
    76. vSE3->setId(pKFi->mnId);
    77. vSE3->setFixed(true);
    78. optimizer.addVertex(vSE3);
    79. if(pKFi->mnId>maxKFid)
    80. maxKFid=pKFi->mnId;
    81. }
    82. // Set MapPoint vertices
    83. const int nExpectedSize = (lLocalKeyFrames.size()+lFixedCameras.size())*lLocalMapPoints.size();
    84. vector vpEdgesMono;
    85. vpEdgesMono.reserve(nExpectedSize);
    86. vector vpEdgeKFMono;
    87. vpEdgeKFMono.reserve(nExpectedSize);
    88. vector vpMapPointEdgeMono;
    89. vpMapPointEdgeMono.reserve(nExpectedSize);
    90. vector vpEdgesStereo;
    91. vpEdgesStereo.reserve(nExpectedSize);
    92. vector vpEdgeKFStereo;
    93. vpEdgeKFStereo.reserve(nExpectedSize);
    94. vector vpMapPointEdgeStereo;
    95. vpMapPointEdgeStereo.reserve(nExpectedSize);
    96. const float thHuberMono = sqrt(5.991);
    97. const float thHuberStereo = sqrt(7.815);
    98. for(list::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++)
    99. {
    100. MapPoint* pMP = *lit;
    101. g2o::VertexSBAPointXYZ* vPoint = new g2o::VertexSBAPointXYZ();
    102. vPoint->setEstimate(Converter::toVector3d(pMP->GetWorldPos()));
    103. int id = pMP->mnId+maxKFid+1;
    104. vPoint->setId(id);
    105. vPoint->setMarginalized(true);
    106. optimizer.addVertex(vPoint);
    107. const mapsize_t> observations = pMP->GetObservations();
    108. //Set edges
    109. for(mapsize_t>::const_iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    110. {
    111. KeyFrame* pKFi = mit->first;
    112. if(!pKFi->isBad())
    113. {
    114. const cv::KeyPoint &kpUn = pKFi->mvKeysUn[mit->second];
    115. // Monocular observation
    116. if(pKFi->mvuRight[mit->second]<0)
    117. {
    118. Eigen::Matrix<double,2,1> obs;
    119. obs << kpUn.pt.x, kpUn.pt.y;
    120. g2o::EdgeSE3ProjectXYZ* e = new g2o::EdgeSE3ProjectXYZ();
    121. e->setVertex(0, dynamic_cast(optimizer.vertex(id)));
    122. e->setVertex(1, dynamic_cast(optimizer.vertex(pKFi->mnId)));
    123. e->setMeasurement(obs);
    124. const float &invSigma2 = pKFi->mvInvLevelSigma2[kpUn.octave];
    125. e->setInformation(Eigen::Matrix2d::Identity()*invSigma2);
    126. g2o::RobustKernelHuber* rk = new g2o::RobustKernelHuber;
    127. e->setRobustKernel(rk);
    128. rk->setDelta(thHuberMono);
    129. e->fx = pKFi->fx;
    130. e->fy = pKFi->fy;
    131. e->cx = pKFi->cx;
    132. e->cy = pKFi->cy;
    133. optimizer.addEdge(e);
    134. vpEdgesMono.push_back(e);
    135. vpEdgeKFMono.push_back(pKFi);
    136. vpMapPointEdgeMono.push_back(pMP);
    137. }
    138. else // Stereo observation
    139. {
    140. Eigen::Matrix<double,3,1> obs;
    141. const float kp_ur = pKFi->mvuRight[mit->second];
    142. obs << kpUn.pt.x, kpUn.pt.y, kp_ur;
    143. g2o::EdgeStereoSE3ProjectXYZ* e = new g2o::EdgeStereoSE3ProjectXYZ();
    144. e->setVertex(0, dynamic_cast(optimizer.vertex(id)));
    145. e->setVertex(1, dynamic_cast(optimizer.vertex(pKFi->mnId)));
    146. e->setMeasurement(obs);
    147. const float &invSigma2 = pKFi->mvInvLevelSigma2[kpUn.octave];
    148. Eigen::Matrix3d Info = Eigen::Matrix3d::Identity()*invSigma2;
    149. e->setInformation(Info);
    150. g2o::RobustKernelHuber* rk = new g2o::RobustKernelHuber;
    151. e->setRobustKernel(rk);
    152. rk->setDelta(thHuberStereo);
    153. e->fx = pKFi->fx;
    154. e->fy = pKFi->fy;
    155. e->cx = pKFi->cx;
    156. e->cy = pKFi->cy;
    157. e->bf = pKFi->mbf;
    158. optimizer.addEdge(e);
    159. vpEdgesStereo.push_back(e);
    160. vpEdgeKFStereo.push_back(pKFi);
    161. vpMapPointEdgeStereo.push_back(pMP);
    162. }
    163. }
    164. }
    165. }
    166. if(pbStopFlag)
    167. if(*pbStopFlag)
    168. return;
    169. optimizer.initializeOptimization();
    170. optimizer.optimize(5);
    171. bool bDoMore= true;
    172. if(pbStopFlag)
    173. if(*pbStopFlag)
    174. bDoMore = false;
    175. if(bDoMore)
    176. {
    177. // Check inlier observations
    178. for(size_t i=0, iend=vpEdgesMono.size(); i
    179. {
    180. g2o::EdgeSE3ProjectXYZ* e = vpEdgesMono[i];
    181. MapPoint* pMP = vpMapPointEdgeMono[i];
    182. if(pMP->isBad())
    183. continue;
    184. if(e->chi2()>5.991 || !e->isDepthPositive())
    185. {
    186. e->setLevel(1);
    187. }
    188. e->setRobustKernel(0);
    189. }
    190. for(size_t i=0, iend=vpEdgesStereo.size(); i
    191. {
    192. g2o::EdgeStereoSE3ProjectXYZ* e = vpEdgesStereo[i];
    193. MapPoint* pMP = vpMapPointEdgeStereo[i];
    194. if(pMP->isBad())
    195. continue;
    196. if(e->chi2()>7.815 || !e->isDepthPositive())
    197. {
    198. e->setLevel(1);
    199. }
    200. e->setRobustKernel(0);
    201. }
    202. // Optimize again without the outliers
    203. optimizer.initializeOptimization(0);
    204. optimizer.optimize(10);
    205. }
    206. vector > vToErase;
    207. vToErase.reserve(vpEdgesMono.size()+vpEdgesStereo.size());
    208. // Check inlier observations
    209. for(size_t i=0, iend=vpEdgesMono.size(); i
    210. {
    211. g2o::EdgeSE3ProjectXYZ* e = vpEdgesMono[i];
    212. MapPoint* pMP = vpMapPointEdgeMono[i];
    213. if(pMP->isBad())
    214. continue;
    215. if(e->chi2()>5.991 || !e->isDepthPositive())
    216. {
    217. KeyFrame* pKFi = vpEdgeKFMono[i];
    218. vToErase.push_back(make_pair(pKFi,pMP));
    219. }
    220. }
    221. for(size_t i=0, iend=vpEdgesStereo.size(); i
    222. {
    223. g2o::EdgeStereoSE3ProjectXYZ* e = vpEdgesStereo[i];
    224. MapPoint* pMP = vpMapPointEdgeStereo[i];
    225. if(pMP->isBad())
    226. continue;
    227. if(e->chi2()>7.815 || !e->isDepthPositive())
    228. {
    229. KeyFrame* pKFi = vpEdgeKFStereo[i];
    230. vToErase.push_back(make_pair(pKFi,pMP));
    231. }
    232. }
    233. // Get Map Mutex
    234. unique_lock lock(pMap->mMutexMapUpdate);
    235. if(!vToErase.empty())
    236. {
    237. for(size_t i=0;isize();i++)
    238. {
    239. KeyFrame* pKFi = vToErase[i].first;
    240. MapPoint* pMPi = vToErase[i].second;
    241. pKFi->EraseMapPointMatch(pMPi);
    242. pMPi->EraseObservation(pKFi);
    243. }
    244. }
    245. // Recover optimized data
    246. //Keyframes
    247. for(list::iterator lit=lLocalKeyFrames.begin(), lend=lLocalKeyFrames.end(); lit!=lend; lit++)
    248. {
    249. KeyFrame* pKF = *lit;
    250. g2o::VertexSE3Expmap* vSE3 = static_cast(optimizer.vertex(pKF->mnId));
    251. g2o::SE3Quat SE3quat = vSE3->estimate();
    252. pKF->SetPose(Converter::toCvMat(SE3quat));
    253. }
    254. //Points
    255. for(list::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++)
    256. {
    257. MapPoint* pMP = *lit;
    258. g2o::VertexSBAPointXYZ* vPoint = static_cast(optimizer.vertex(pMP->mnId+maxKFid+1));
    259. pMP->SetWorldPos(Converter::toCvMat(vPoint->estimate()));
    260. pMP->UpdateNormalAndDepth();
    261. }
    262. }

    8. void LocalMapping::KeyFrameCulling()


    在Covisibility Graph,也就是局部地图中的关键帧,一个关键帧的90%以上的MapPoints能被其他关键帧(至少3个,这里的其他关键帧不特指当前的局部地图关键帧)观测到,则认为该关键帧为冗余关键帧。

    根据Covisibility Graph提取当前帧的共视关键帧
    对所有的局部关键帧进行遍历,提取每个共视关键帧的MapPoints
    遍历该局部关键帧的MapPoints,判断是否90%以上的MapPoints能被其它关键帧(至少3个)观测到
    该局部关键帧90%以上的MapPoints能被其它关键帧(至少3个)观测到,则认为是冗余关键帧

    1. void LocalMapping::KeyFrameCulling()
    2. {
    3. // Check redundant keyframes (only local keyframes)
    4. // A keyframe is considered redundant if the 90% of the MapPoints it sees, are seen
    5. // in at least other 3 keyframes (in the same or finer scale)
    6. // We only consider close stereo points
    7. // 检查冗余关键帧。一个关键帧的地图点中90%的地图点可以被至少其他3个相同或者更小等级(这里的等级是图像金字塔的层数)关键帧看到,则认为这个关键帧是冗余的。
    8. vector vpLocalKeyFrames = mpCurrentKeyFrame->GetVectorCovisibleKeyFrames();
    9. for(vector::iterator vit=vpLocalKeyFrames.begin(), vend=vpLocalKeyFrames.end(); vit!=vend; vit++)
    10. {
    11. KeyFrame* pKF = *vit;
    12. if(pKF->mnId==0)
    13. continue;
    14. const vector vpMapPoints = pKF->GetMapPointMatches();
    15. int nObs = 3;
    16. const int thObs=nObs;
    17. int nRedundantObservations=0;
    18. int nMPs=0;
    19. for(size_t i=0, iend=vpMapPoints.size(); i
    20. {
    21. MapPoint* pMP = vpMapPoints[i];
    22. if(pMP)
    23. {
    24. if(!pMP->isBad())
    25. {
    26. if(!mbMonocular)
    27. {
    28. if(pKF->mvDepth[i]>pKF->mThDepth || pKF->mvDepth[i]<0)
    29. continue;
    30. }
    31. //MapPoint计数
    32. nMPs++;
    33. //该pMP是否可以被大于3个的关键帧看到
    34. if(pMP->Observations()>thObs)
    35. {
    36. const int &scaleLevel = pKF->mvKeysUn[i].octave;
    37. const mapsize_t> observations = pMP->GetObservations();
    38. int nObs=0;
    39. for(mapsize_t>::const_iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++)
    40. {
    41. KeyFrame* pKFi = mit->first;
    42. if(pKFi==pKF)
    43. continue;
    44. // 获取关键点在金字塔图像中所处的层数
    45. const int &scaleLeveli = pKFi->mvKeysUn[mit->second].octave;
    46. const int &scaleLeveli = pKFi->mvKeysUn[mit->second].octave;
    47. //pKFi的关键点所处的层数<=scaleLevel+1
    48. //为什么要用层数来判断呢?还没有想明白
    49. if(scaleLeveli<=scaleLevel+1)
    50. {
    51. //共视关键帧计数
    52. nObs++;
    53. if(nObs>=thObs)
    54. break;
    55. }
    56. }
    57. //共视关键帧大于等于3判断
    58. if(nObs>=thObs)
    59. {
    60. nRedundantObservations++;
    61. }
    62. }
    63. }
    64. }
    65. }
    66. if(nRedundantObservations>0.9*nMPs)
    67. //关键帧设置为bag,即被认为是冗余关键帧
    68. pKF->SetBadFlag();
    69. }
    70. }

    参考文献

    主要内容来自下文,重写了一说说明,添加了一些注释

    读懂ORBSLAM2——LocalMapping线程_令狐少侠、的博客-CSDN博客

  • 相关阅读:
    vue-router的基本用法
    Camera2 OpenCamera流程
    【欧拉函数】CF1731E
    基于springboot实现校园在线拍卖系统项目【项目源码】计算机毕业设计
    教程更新 | RK3568驱动指南第六篇-平台总线
    HTML5期末考核大作业,电影网站——橙色国外电影 web期末作业设计网页
    python基于django学生成绩管理系统o8mkp
    numpy 和 tensorflow 中的各种乘法(点乘和矩阵乘)
    朝阳药品数据分析案例
    Mybatis-Plus 条件构造器Wrapper
  • 原文地址:https://blog.csdn.net/xhtchina/article/details/126678378