orb-slam系列 LocalMapping线程 后半部分(九)

orb-slam系列 LocalMapping线程 后半部分(九)SearchInNeig 检查并融合当前关键帧与相邻帧 两级相邻 重复的 MapPoints 1 找到带融合的关键帧 当前关键帧的两级相邻关键帧 2 在目标关键帧中寻找当前关键帧地图点的匹配 并在目标关键帧的地图点中寻找当前关键帧所有地图点的融合点 3

大家好,我是讯享网,很高兴认识大家。

SearchInNeighbors`

/ * 检查并融合当前关键帧与相邻帧(两级相邻)重复的MapPoints * 1. 找到带融合的关键帧(当前关键帧的两级相邻关键帧) * 2. 在目标关键帧中寻找当前关键帧地图点的匹配 并在目标关键帧的地图点中寻找当前关键帧所有地图点的融合点 * 3. 在当前关键帧中寻找目标关键帧(当前关键帧的两级相邻)所有地图点的匹配 并在当前关键帧的地图点中中寻找目标关键帧所有地图点的融合点 * 4. 更新特征点融合之后当前关键帧的地图点的最优描述子和该地图点被观察的平均方向以及深度范围 * 5. 更新当前关键帧地图点融合之后的当前关键帧与关联关键帧的联系 */ void LocalMapping::SearchInNeighbors() { 
    // Retrieve neighbor keyframes int nn = 10; if(mbMonocular) nn=20; const vector<KeyFrame*> vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn); //待融合的关键帧 vector<KeyFrame*> vpTargetKFs; for(vector<KeyFrame*>::const_iterator vit=vpNeighKFs.begin(), vend=vpNeighKFs.end(); vit!=vend; vit++) { 
    KeyFrame* pKFi = *vit; if(pKFi->isBad() || pKFi->mnFuseTargetForKF == mpCurrentKeyFrame->mnId) continue; vpTargetKFs.push_back(pKFi); // 一级相邻 pKFi->mnFuseTargetForKF = mpCurrentKeyFrame->mnId; // Extend to some second neighbors const vector<KeyFrame*> vpSecondNeighKFs = pKFi->GetBestCovisibilityKeyFrames(5); for(vector<KeyFrame*>::const_iterator vit2=vpSecondNeighKFs.begin(), vend2=vpSecondNeighKFs.end(); vit2!=vend2; vit2++) { 
    KeyFrame* pKFi2 = *vit2; if(pKFi2->isBad() || pKFi2->mnFuseTargetForKF==mpCurrentKeyFrame->mnId || pKFi2->mnId==mpCurrentKeyFrame->mnId) continue; vpTargetKFs.push_back(pKFi2); //二级相邻 } } // Search matches by projection from current KF in target KFs 当前关键帧和目标关键帧集进行搜索匹配 ORBmatcher matcher; // 当前帧的地图点 vector<MapPoint*> vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches(); // 在目标关键帧中寻找当前关键帧地图点的匹配 并在目标关键帧的地图点中中寻找当前关键帧所有地图点的融合点 for(vector<KeyFrame*>::iterator vit=vpTargetKFs.begin(), vend=vpTargetKFs.end(); vit!=vend; vit++) { 
    KeyFrame* pKFi = *vit; matcher.Fuse(pKFi,vpMapPointMatches); } // Search matches by projection from target KFs in current KF // 在当前关键帧中寻找目标关键帧(当前关键帧的两级相邻)所有地图点的匹配 并在当前关键帧的地图点中中寻找目标关键帧所有地图点的融合点 vector<MapPoint*> vpFuseCandidates; vpFuseCandidates.reserve(vpTargetKFs.size()*vpMapPointMatches.size()); for(vector<KeyFrame*>::iterator vitKF=vpTargetKFs.begin(), vendKF=vpTargetKFs.end(); vitKF!=vendKF; vitKF++) { 
    KeyFrame* pKFi = *vitKF; vector<MapPoint*> vpMapPointsKFi = pKFi->GetMapPointMatches(); for(vector<MapPoint*>::iterator vitMP=vpMapPointsKFi.begin(), vendMP=vpMapPointsKFi.end(); vitMP!=vendMP; vitMP++)// 遍历所有目标关键帧(当前关键帧的两级相邻)中的所有地图点 { 
    MapPoint* pMP = *vitMP; if(!pMP) continue; if(pMP->isBad() || pMP->mnFuseCandidateForKF == mpCurrentKeyFrame->mnId) continue; pMP->mnFuseCandidateForKF = mpCurrentKeyFrame->mnId; vpFuseCandidates.push_back(pMP); } } //在当前关键帧中寻找目标关键帧(当前关键帧的两级相邻)所有地图点的匹配 并在当前关键帧的地图点中中寻找目标关键帧所有地图点的融合点 matcher.Fuse(mpCurrentKeyFrame,vpFuseCandidates); // Update points 更新特征点融合之后当前关键帧的地图点的最优描述子和该地图点被观察的平均方向以及深度范围 vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches(); for(size_t i=0, iend=vpMapPointMatches.size(); i<iend; i++) { 
    MapPoint* pMP=vpMapPointMatches[i]; if(pMP) { 
    if(!pMP->isBad()) { 
    pMP->ComputeDistinctiveDescriptors(); pMP->UpdateNormalAndDepth(); } } } // Update connections in covisibility graph 更新当前关键帧地图点融合之后的当前关键帧与关联关键帧的联系 mpCurrentKeyFrame->UpdateConnections(); } 

讯享网

1)找到最关联的nn帧,存入vpTargetKFs,设置mnFuseTargetForKF标定为当前帧(一级相连)
2)再找到二级相连,存入vpTargetKFs
3)当前帧 与 vpTargetKFs帧的地图点融合。

Fuse
讯享网 * @brief 将MapPoints投影到关键帧pKF中,并判断是否有重复的MapPoints * 1.如果MapPoint能匹配关键帧的特征点,并且该点有对应的MapPoint,那么将两个MapPoint合并(选择观测数多的) * 2.如果MapPoint能匹配关键帧的特征点,并且该点没有对应的MapPoint,那么为该点添加MapPoint * @param pKF 相邻关键帧 * @param vpMapPoints 当前关键帧的MapPoints * @param th 搜索半径的因子 * @return 重复MapPoints的数量 */ int ORBmatcher::Fuse(KeyFrame *pKF, const vector<MapPoint *> &vpMapPoints, const float th) { cv::Mat Rcw = pKF->GetRotation(); cv::Mat tcw = pKF->GetTranslation(); const float &fx = pKF->fx; const float &fy = pKF->fy; const float &cx = pKF->cx; const float &cy = pKF->cy; const float &bf = pKF->mbf; cv::Mat Ow = pKF->GetCameraCenter(); int nFused=0; const int nMPs = vpMapPoints.size(); // 遍历当前帧所有的MapPoints for(int i=0; i<nMPs; i++) { MapPoint* pMP = vpMapPoints[i]; if(!pMP) continue; if(pMP->isBad() || pMP->IsInKeyFrame(pKF)) continue; cv::Mat p3Dw = pMP->GetWorldPos(); cv::Mat p3Dc = Rcw*p3Dw + tcw; // Depth must be positive if(p3Dc.at<float>(2)<0.0f) continue; //归一化处理 const float invz = 1/p3Dc.at<float>(2); const float x = p3Dc.at<float>(0)*invz; const float y = p3Dc.at<float>(1)*invz; const float u = fx*x+cx; const float v = fy*y+cy;// 步骤1:得到MapPoint在图像上的投影坐标 // Point must be inside the image 判断是否在图像中 if(!pKF->IsInImage(u,v)) continue; const float ur = u-bf*invz; const float maxDistance = pMP->GetMaxDistanceInvariance(); const float minDistance = pMP->GetMinDistanceInvariance(); cv::Mat PO = p3Dw-Ow; const float dist3D = cv::norm(PO); // Depth must be inside the scale pyramid of the image if(dist3D<minDistance || dist3D>maxDistance ) continue; // Viewing angle must be less than 60 deg cv::Mat Pn = pMP->GetNormal(); if(PO.dot(Pn)<0.5*dist3D) continue; int nPredictedLevel = pMP->PredictScale(dist3D,pKF); // Search in a radius const float radius = th*pKF->mvScaleFactors[nPredictedLevel];// 步骤2:根据MapPoint的深度确定尺度,从而确定搜索范围 const vector<size_t> vIndices = pKF->GetFeaturesInArea(u,v,radius); if(vIndices.empty()) continue; // Match to the most similar keypoint in the radius const cv::Mat dMP = pMP->GetDescriptor(); int bestDist = 256; int bestIdx = -1; for(vector<size_t>::const_iterator vit=vIndices.begin(), vend=vIndices.end(); vit!=vend; vit++)// 步骤3:遍历搜索范围内的features { const size_t idx = *vit; const cv::KeyPoint &kp = pKF->mvKeysUn[idx]; const int &kpLevel= kp.octave; if(kpLevel<nPredictedLevel-1 || kpLevel>nPredictedLevel) continue; // 计算MapPoint投影的坐标与这个区域特征点的距离,如果偏差很大,直接跳过特征点匹配 if(pKF->mvuRight[idx]>=0) { // Check reprojection error in stereo const float &kpx = kp.pt.x; const float &kpy = kp.pt.y; const float &kpr = pKF->mvuRight[idx]; const float ex = u-kpx; const float ey = v-kpy; const float er = ur-kpr; const float e2 = ex*ex+ey*ey+er*er; if(e2*pKF->mvInvLevelSigma2[kpLevel]>7.8) continue; } else { const float &kpx = kp.pt.x; const float &kpy = kp.pt.y; const float ex = u-kpx; const float ey = v-kpy; const float e2 = ex*ex+ey*ey; // 基于卡方检验计算出的阈值(假设测量有一个像素的偏差) if(e2*pKF->mvInvLevelSigma2[kpLevel]>5.99) continue; } const cv::Mat &dKF = pKF->mDescriptors.row(idx); const int dist = DescriptorDistance(dMP,dKF); if(dist<bestDist)// 找MapPoint在该区域**匹配的特征点 { bestDist = dist; bestIdx = idx; } } // If there is already a MapPoint replace otherwise add new measurement if(bestDist<=TH_LOW)// 找到了MapPoint在该区域**匹配的特征点 { MapPoint* pMPinKF = pKF->GetMapPoint(bestIdx); if(pMPinKF)// 如果这个点有对应的MapPoint { if(!pMPinKF->isBad())// 如果这个MapPoint不是bad,选择哪一个呢? 用被观察次数多的地图点代替被观察次数少的 { if(pMPinKF->Observations()>pMP->Observations()) pMP->Replace(pMPinKF); else pMPinKF->Replace(pMP); } } else// 如果这个点没有对应的MapPoint { pMP->AddObservation(pKF,bestIdx); pKF->AddMapPoint(pMP,bestIdx); } nFused++; } } return nFused; } 

1)当前帧所有点地图点 是否在该帧中
2)找到在投影在该帧 阈值范围内的所有特征点,找到**特征点
3)**特征点投影地图点 和 原本地图点比较 被看到多的胜出
如果**特征点没有对应投影地图点,增加投影点

跳出fuse 接上面
4)当前帧的地图点 与所有一级二级帧的所有地图点 融合
5)融合选择后的点 建立联系,该帧的新地图点


讯享网

Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpMap); 局部位姿优化
// 优化的是局部图 局部图中包括一种地图点:共视关键帧的地图点 两种关键帧: 1 共视关键帧 2 可以看到共视关键帧地图点的其他非共视关键帧 // 优化的是共视关键帧位姿和共视关键帧的地图点坐标 void Optimizer::LocalBundleAdjustment(KeyFrame *pKF, bool* pbStopFlag, Map* pMap) { 
    // Local KeyFrames: First Breath Search from Current Keyframe  // 步骤1: 初步的局部关键帧 当前帧的共视关键帧 //共视大于15地图点的帧 list<KeyFrame*> lLocalKeyFrames; lLocalKeyFrames.push_back(pKF); pKF->mnBALocalForKF = pKF->mnId; const vector<KeyFrame*> vNeighKFs = pKF->GetVectorCovisibleKeyFrames(); //共视大于15 for(int i=0, iend=vNeighKFs.size(); i<iend; i++) { 
    KeyFrame* pKFi = vNeighKFs[i]; pKFi->mnBALocalForKF = pKF->mnId; if(!pKFi->isBad()) lLocalKeyFrames.push_back(pKFi); } // Local MapPoints seen in Local KeyFrames  // 步骤2: 局部关键帧的局部地图点 把地图点放入 lLocalMapPoints //共视大于15地图点的帧的所有地图点 list<MapPoint*> lLocalMapPoints; for(list<KeyFrame*>::iterator lit=lLocalKeyFrames.begin() , lend=lLocalKeyFrames.end(); lit!=lend; lit++) { 
    vector<MapPoint*> vpMPs = (*lit)->GetMapPointMatches(); for(vector<MapPoint*>::iterator vit=vpMPs.begin(), vend=vpMPs.end(); vit!=vend; vit++) { 
    MapPoint* pMP = *vit; if(pMP) if(!pMP->isBad()) if(pMP->mnBALocalForKF!=pKF->mnId) { 
    lLocalMapPoints.push_back(pMP); pMP->mnBALocalForKF=pKF->mnId; } } } // Fixed Keyframes. Keyframes that see Local MapPoints but that are not Local Keyframes // 步骤3: 修正关键帧,可以看到局部地图点但不在局部关键帧中 注意图优化的关键帧节点分为两部分vNeighKFs和lFixedCameras都有 //所有能看到当前帧共视大于15的关键帧的所有地图点的 关键帧( list<KeyFrame*> lFixedCameras; for(list<MapPoint*>::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++) { 
    map<KeyFrame*,size_t> observations = (*lit)->GetObservations(); for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) { 
    KeyFrame* pKFi = mit->first; if(pKFi->mnBALocalForKF!=pKF->mnId && pKFi->mnBAFixedForKF!=pKF->mnId) // 此条件是为了将局部关键帧排除在外  { 
    pKFi->mnBAFixedForKF=pKF->mnId; if(!pKFi->isBad()) lFixedCameras.push_back(pKFi); } } } // Setup optimizer // 步骤4: 设置优化器 g2o::SparseOptimizer optimizer; g2o::BlockSolver_6_3::LinearSolverType * linearSolver; linearSolver = new g2o::LinearSolverEigen<g2o::BlockSolver_6_3::PoseMatrixType>(); g2o::BlockSolver_6_3 * solver_ptr = new g2o::BlockSolver_6_3(linearSolver); g2o::OptimizationAlgorithmLevenberg* solver = new g2o::OptimizationAlgorithmLevenberg(solver_ptr); optimizer.setAlgorithm(solver); if(pbStopFlag) optimizer.setForceStopFlag(pbStopFlag); //待优化帧的最大帧id unsigned long maxKFid = 0; // Set Local KeyFrame vertices  // 步骤5: 设置局部关键帧节点 for(list<KeyFrame*>::iterator lit=lLocalKeyFrames.begin(), lend=lLocalKeyFrames.end(); lit!=lend; lit++) { 
    KeyFrame* pKFi = *lit; g2o::VertexSE3Expmap * vSE3 = new g2o::VertexSE3Expmap(); vSE3->setEstimate(Converter::toSE3Quat(pKFi->GetPose())); vSE3->setId(pKFi->mnId); vSE3->setFixed(pKFi->mnId==0); // 只有初始关键帧是固定位姿单位矩阵的 其余的关键帧位姿都可以根据图优化位姿进行调整 optimizer.addVertex(vSE3); if(pKFi->mnId>maxKFid) //关键帧最大id maxKFid=pKFi->mnId; } // Set Fixed KeyFrame vertices  // 步骤6: 设置观察到局部地图点的非局部关键帧集作为图优化的帧节点 for(list<KeyFrame*>::iterator lit=lFixedCameras.begin(), lend=lFixedCameras.end(); lit!=lend; lit++) { 
    KeyFrame* pKFi = *lit; g2o::VertexSE3Expmap * vSE3 = new g2o::VertexSE3Expmap(); //帧节点 vSE3->setEstimate(Converter::toSE3Quat(pKFi->GetPose())); vSE3->setId(pKFi->mnId); vSE3->setFixed(true); optimizer.addVertex(vSE3); if(pKFi->mnId>maxKFid) maxKFid=pKFi->mnId; } // Set MapPoint vertices // 步骤7: 设置地图点节点 const int nExpectedSize = (lLocalKeyFrames.size()+lFixedCameras.size())*lLocalMapPoints.size(); vector<g2o::EdgeSE3ProjectXYZ*> vpEdgesMono; vpEdgesMono.reserve(nExpectedSize); vector<KeyFrame*> vpEdgeKFMono; vpEdgeKFMono.reserve(nExpectedSize); vector<MapPoint*> vpMapPointEdgeMono; vpMapPointEdgeMono.reserve(nExpectedSize); vector<g2o::EdgeStereoSE3ProjectXYZ*> vpEdgesStereo; vpEdgesStereo.reserve(nExpectedSize); vector<KeyFrame*> vpEdgeKFStereo; vpEdgeKFStereo.reserve(nExpectedSize); vector<MapPoint*> vpMapPointEdgeStereo; vpMapPointEdgeStereo.reserve(nExpectedSize); const float thHuberMono = sqrt(5.991); const float thHuberStereo = sqrt(7.815); for(list<MapPoint*>::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++) { 
    MapPoint* pMP = *lit; g2o::VertexSBAPointXYZ* vPoint = new g2o::VertexSBAPointXYZ(); //地图点 节点 vPoint->setEstimate(Converter::toVector3d(pMP->GetWorldPos())); int id = pMP->mnId+maxKFid+1; vPoint->setId(id); vPoint->setMarginalized(true); optimizer.addVertex(vPoint); const map<KeyFrame*,size_t> observations = pMP->GetObservations(); //Set edges  // 步骤8: 设置边 for(map<KeyFrame*,size_t>::const_iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) { 
    //该点的所有观测帧 KeyFrame* pKFi = mit->first; if(!pKFi->isBad()) { 
    const cv::KeyPoint &kpUn = pKFi->mvKeysUn[mit->second]; // Monocular observation 单目 if(pKFi->mvuRight[mit->second]<0) { 
    Eigen::Matrix<double,2,1> obs; obs << kpUn.pt.x, kpUn.pt.y; g2o::EdgeSE3ProjectXYZ* e = new g2o::EdgeSE3ProjectXYZ(); e->setVertex(0, dynamic_cast<g2o::OptimizableGraph::Vertex*>(optimizer.vertex(id))); //地图点 e->setVertex(1, dynamic_cast<g2o::OptimizableGraph::Vertex*>(optimizer.vertex(pKFi->mnId))); //帧 e->setMeasurement(obs); const float &invSigma2 = pKFi->mvInvLevelSigma2[kpUn.octave]; e->setInformation(Eigen::Matrix2d::Identity()*invSigma2); g2o::RobustKernelHuber* rk = new g2o::RobustKernelHuber; e->setRobustKernel(rk); rk->setDelta(thHuberMono); e->fx = pKFi->fx; e->fy = pKFi->fy; e->cx = pKFi->cx; e->cy = pKFi->cy; optimizer.addEdge(e); vpEdgesMono.push_back(e); vpEdgeKFMono.push_back(pKFi); vpMapPointEdgeMono.push_back(pMP); } else // Stereo observation 双目 { 
    Eigen::Matrix<double,3,1> obs; const float kp_ur = pKFi->mvuRight[mit->second]; // 待优化帧 obs << kpUn.pt.x, kpUn.pt.y, kp_ur; g2o::EdgeStereoSE3ProjectXYZ* e = new g2o::EdgeStereoSE3ProjectXYZ(); e->setVertex(0, dynamic_cast<g2o::OptimizableGraph::Vertex*>(optimizer.vertex(id))); //帧位姿 e->setVertex(1, dynamic_cast<g2o::OptimizableGraph::Vertex*>(optimizer.vertex(pKFi->mnId))); //地图点 e->setMeasurement(obs); const float &invSigma2 = pKFi->mvInvLevelSigma2[kpUn.octave]; Eigen::Matrix3d Info = Eigen::Matrix3d::Identity()*invSigma2; e->setInformation(Info); g2o::RobustKernelHuber* rk = new g2o::RobustKernelHuber; e->setRobustKernel(rk); rk->setDelta(thHuberStereo); e->fx = pKFi->fx; e->fy = pKFi->fy; e->cx = pKFi->cx; e->cy = pKFi->cy; e->bf = pKFi->mbf; optimizer.addEdge(e); vpEdgesStereo.push_back(e); vpEdgeKFStereo.push_back(pKFi); vpMapPointEdgeStereo.push_back(pMP); } } } } if(pbStopFlag) if(*pbStopFlag) return; // 步骤9: 优化一次,筛选内点后再优化一次进一步筛选内点,得到最终的结果 optimizer.initializeOptimization(); optimizer.optimize(5); bool bDoMore= true; if(pbStopFlag) if(*pbStopFlag) bDoMore = false; if(bDoMore) { 
    // Check inlier observations 检测内点 for(size_t i=0, iend=vpEdgesMono.size(); i<iend;i++) { 
    g2o::EdgeSE3ProjectXYZ* e = vpEdgesMono[i]; MapPoint* pMP = vpMapPointEdgeMono[i]; if(pMP->isBad()) continue; if(e->chi2()>5.991 || !e->isDepthPositive()) { 
    e->setLevel(1); } e->setRobustKernel(0); } for(size_t i=0, iend=vpEdgesStereo.size(); i<iend;i++) { 
    g2o::EdgeStereoSE3ProjectXYZ* e = vpEdgesStereo[i]; MapPoint* pMP = vpMapPointEdgeStereo[i]; if(pMP->isBad()) continue; if(e->chi2()>7.815 || !e->isDepthPositive()) { 
    e->setLevel(1); } e->setRobustKernel(0); } // Optimize again without the outliers 去除外点之后进行进一步的优化 optimizer.initializeOptimization(0); optimizer.optimize(10); } vector<pair<KeyFrame*,MapPoint*> > vToErase; vToErase.reserve(vpEdgesMono.size()+vpEdgesStereo.size()); // Check inlier observations 再次检测内点 for(size_t i=0, iend=vpEdgesMono.size(); i<iend;i++) { 
    g2o::EdgeSE3ProjectXYZ* e = vpEdgesMono[i]; MapPoint* pMP = vpMapPointEdgeMono[i]; if(pMP->isBad()) continue; if(e->chi2()>5.991 || !e->isDepthPositive()) { 
    KeyFrame* pKFi = vpEdgeKFMono[i]; vToErase.push_back(make_pair(pKFi,pMP)); } } for(size_t i=0, iend=vpEdgesStereo.size(); i<iend;i++) { 
    g2o::EdgeStereoSE3ProjectXYZ* e = vpEdgesStereo[i]; MapPoint* pMP = vpMapPointEdgeStereo[i]; if(pMP->isBad()) continue; if(e->chi2()>7.815 || !e->isDepthPositive()) { 
    KeyFrame* pKFi = vpEdgeKFStereo[i]; vToErase.push_back(make_pair(pKFi,pMP)); } } // Get Map Mutex unique_lock<mutex> lock(pMap->mMutexMapUpdate); if(!vToErase.empty()) { 
    for(size_t i=0;i<vToErase.size();i++) { 
    KeyFrame* pKFi = vToErase[i].first; MapPoint* pMPi = vToErase[i].second; pKFi->EraseMapPointMatch(pMPi); pMPi->EraseObservation(pKFi); } } // Recover optimized data 恢复优化数据 包括关键帧的位姿和地图点的三维坐标 //Keyframes for(list<KeyFrame*>::iterator lit=lLocalKeyFrames.begin(), lend=lLocalKeyFrames.end(); lit!=lend; lit++) { 
    KeyFrame* pKF = *lit; g2o::VertexSE3Expmap* vSE3 = static_cast<g2o::VertexSE3Expmap*>(optimizer.vertex(pKF->mnId)); g2o::SE3Quat SE3quat = vSE3->estimate(); pKF->SetPose(Converter::toCvMat(SE3quat)); } //Points for(list<MapPoint*>::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++) { 
    MapPoint* pMP = *lit; g2o::VertexSBAPointXYZ* vPoint = static_cast<g2o::VertexSBAPointXYZ*>(optimizer.vertex(pMP->mnId+maxKFid+1)); pMP->SetWorldPos(Converter::toCvMat(vPoint->estimate())); pMP->UpdateNormalAndDepth(); } } 

1)当前帧共视大于15的所有关键帧
2)共视关键帧的所有地图点lLocalMapPoints
3)能看到lLocalMapPoints的所有关键帧 lFixedCameras

讯享网for(list<MapPoint*>::iterator lit=lLocalMapPoints.begin(), lend=lLocalMapPoints.end(); lit!=lend; lit++) { 
    map<KeyFrame*,size_t> observations = (*lit)->GetObservations(); for(map<KeyFrame*,size_t>::iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) { 
    KeyFrame* pKFi = mit->first; if(pKFi->mnBALocalForKF!=pKF->mnId && pKFi->mnBAFixedForKF!=pKF->mnId) // 此条件是为了将局部关键帧排除在外  { 
    pKFi->mnBAFixedForKF=pKF->mnId; if(!pKFi->isBad()) lFixedCameras.push_back(pKFi); } } } 

4)lLocalKeyFrames lFixedCameras 帧 lLocalMapPoints 地图点都优化了

KeyFrameCulling 检查冗余

mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame); 插入回环检测

小讯
上一篇 2025-01-14 11:17
下一篇 2025-02-19 20:26

相关推荐

版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容,请联系我们,一经查实,本站将立刻删除。
如需转载请保留出处:https://51itzy.com/kjqy/19587.html