void LoopClosing::CorrectLoop() { // Send a stop signal to Local Mapping // Avoid new keyframes are inserted while correcting the loop mpLocalMapper->RequestStop(); // Wait until Local Mapping has effectively stopped //ros::Rate r(1e4); //while(ros::ok() && !mpLocalMapper->isStopped()) while(!mpLocalMapper->isStopped()) { //r.sleep(); boost::this_thread::sleep(boost::posix_time::milliseconds(10000)); } // Ensure current keyframe is updated mpCurrentKF->UpdateConnections(); // Retrive keyframes connected to the current keyframe and compute corrected Sim3 pose by propagation mvpCurrentConnectedKFs = mpCurrentKF->GetVectorCovisibleKeyFrames(); mvpCurrentConnectedKFs.push_back(mpCurrentKF); KeyFrameAndPose CorrectedSim3, NonCorrectedSim3; CorrectedSim3[mpCurrentKF]=mg2oScw; cv::Mat Twc = mpCurrentKF->GetPoseInverse(); for(vector<KeyFrame*>::iterator vit=mvpCurrentConnectedKFs.begin(), vend=mvpCurrentConnectedKFs.end(); vit!=vend; vit++) { KeyFrame* pKFi = *vit; cv::Mat Tiw = pKFi->GetPose(); if(pKFi!=mpCurrentKF) { cv::Mat Tic = Tiw*Twc; cv::Mat Ric = Tic.rowRange(0,3).colRange(0,3); cv::Mat tic = Tic.rowRange(0,3).col(3); g2o::Sim3 g2oSic(Converter::toMatrix3d(Ric),Converter::toVector3d(tic),1.0); g2o::Sim3 g2oCorrectedSiw = g2oSic*mg2oScw; //Pose corrected with the Sim3 of the loop closure CorrectedSim3[pKFi]=g2oCorrectedSiw; } cv::Mat Riw = Tiw.rowRange(0,3).colRange(0,3); cv::Mat tiw = Tiw.rowRange(0,3).col(3); g2o::Sim3 g2oSiw(Converter::toMatrix3d(Riw),Converter::toVector3d(tiw),1.0); //Pose without correction NonCorrectedSim3[pKFi]=g2oSiw; } // Correct all MapPoints obsrved by current keyframe and neighbors, so that they align with the other side of the loop for(KeyFrameAndPose::iterator mit=CorrectedSim3.begin(), mend=CorrectedSim3.end(); mit!=mend; mit++) { KeyFrame* pKFi = mit->first; g2o::Sim3 g2oCorrectedSiw = mit->second; g2o::Sim3 g2oCorrectedSwi = g2oCorrectedSiw.inverse(); g2o::Sim3 g2oSiw =NonCorrectedSim3[pKFi]; vector<MapPoint*> vpMPsi = pKFi->GetMapPointMatches(); for(size_t iMP=0, endMPi = vpMPsi.size(); iMP<endMPi; iMP++) { MapPoint* pMPi = vpMPsi[iMP]; if(!pMPi) continue; if(pMPi->isBad()) continue; if(pMPi->mnCorrectedByKF==mpCurrentKF->mnId) continue; // Project with non-corrected pose and project back with corrected pose cv::Mat P3Dw = pMPi->GetWorldPos(); Eigen::Matrix<double,3,1> eigP3Dw = Converter::toVector3d(P3Dw); Eigen::Matrix<double,3,1> eigCorrectedP3Dw = g2oCorrectedSwi.map(g2oSiw.map(eigP3Dw)); cv::Mat cvCorrectedP3Dw = Converter::toCvMat(eigCorrectedP3Dw); pMPi->SetWorldPos(cvCorrectedP3Dw); pMPi->mnCorrectedByKF = mpCurrentKF->mnId; pMPi->mnCorrectedReference = pKFi->mnId; pMPi->UpdateNormalAndDepth(); } // Update keyframe pose with corrected Sim3. First transform Sim3 to SE3 (scale translation) Eigen::Matrix3d eigR = g2oCorrectedSiw.rotation().toRotationMatrix(); Eigen::Vector3d eigt = g2oCorrectedSiw.translation(); double s = g2oCorrectedSiw.scale(); eigt *=(1./s); //[R t/s;0 1] cv::Mat correctedTiw = Converter::toCvSE3(eigR,eigt); pKFi->SetPose(correctedTiw); // Make sure connections are updated pKFi->UpdateConnections(); } // Start Loop Fusion // Update matched map points and replace if duplicated for(size_t i=0; i<mvpCurrentMatchedPoints.size(); i++) { if(mvpCurrentMatchedPoints[i]) { MapPoint* pLoopMP = mvpCurrentMatchedPoints[i]; MapPoint* pCurMP = mpCurrentKF->GetMapPoint(i); if(pCurMP) pCurMP->Replace(pLoopMP); else { mpCurrentKF->AddMapPoint(pLoopMP,i); pLoopMP->AddObservation(mpCurrentKF,i); pLoopMP->ComputeDistinctiveDescriptors(); } } } // Project MapPoints observed in the neighborhood of the loop keyframe // into the current keyframe and neighbors using corrected poses. // Fuse duplications. SearchAndFuse(CorrectedSim3); // After the MapPoint fusion, new links in the covisibility graph will appear attaching both sides of the loop map<KeyFrame*, set<KeyFrame*> > LoopConnections; for(vector<KeyFrame*>::iterator vit=mvpCurrentConnectedKFs.begin(), vend=mvpCurrentConnectedKFs.end(); vit!=vend; vit++) { KeyFrame* pKFi = *vit; vector<KeyFrame*> vpPreviousNeighbors = pKFi->GetVectorCovisibleKeyFrames(); // Update connections. Detect new links. pKFi->UpdateConnections(); LoopConnections[pKFi]=pKFi->GetConnectedKeyFrames(); for(vector<KeyFrame*>::iterator vit_prev=vpPreviousNeighbors.begin(), vend_prev=vpPreviousNeighbors.end(); vit_prev!=vend_prev; vit_prev++) { LoopConnections[pKFi].erase(*vit_prev); } for(vector<KeyFrame*>::iterator vit2=mvpCurrentConnectedKFs.begin(), vend2=mvpCurrentConnectedKFs.end(); vit2!=vend2; vit2++) { LoopConnections[pKFi].erase(*vit2); } } mpTracker->ForceRelocalisation(); Optimizer::OptimizeEssentialGraph(mpMap, mpMatchedKF, mpCurrentKF, mg2oScw, NonCorrectedSim3, CorrectedSim3, LoopConnections); //Add edge mpMatchedKF->AddLoopEdge(mpCurrentKF); mpCurrentKF->AddLoopEdge(mpMatchedKF); std::cout << "Loop Closed!" << std::endl; // Loop closed. Release Local Mapping. mpLocalMapper->Release(); mpMap->SetFlagAfterBA(); mLastLoopKFid = mpCurrentKF->mnId; }
void KeyFrame::SetBadFlag() { { boost::mutex::scoped_lock lock(mMutexConnections); if(mnId==0) return; else if(mbNotErase) { mbToBeErased = true; return; } } for(map<KeyFrame*,int>::iterator mit = mConnectedKeyFrameWeights.begin(), mend=mConnectedKeyFrameWeights.end(); mit!=mend; mit++) mit->first->EraseConnection(this); for(size_t i=0; i<mvpMapPoints.size(); i++) if(mvpMapPoints[i]) mvpMapPoints[i]->EraseObservation(this); { boost::mutex::scoped_lock lock(mMutexConnections); boost::mutex::scoped_lock lock1(mMutexFeatures); mConnectedKeyFrameWeights.clear(); mvpOrderedConnectedKeyFrames.clear(); // Update Spanning Tree set<KeyFrame*> sParentCandidates; sParentCandidates.insert(mpParent); // Assign at each iteration one children with a parent (the pair with highest covisibility weight) // Include that children as new parent candidate for the rest while(!mspChildrens.empty()) { bool bContinue = false; int max = -1; KeyFrame* pC; KeyFrame* pP; for(set<KeyFrame*>::iterator sit=mspChildrens.begin(), send=mspChildrens.end(); sit!=send; sit++) { KeyFrame* pKF = *sit; if(pKF->isBad()) continue; // Check if a parent candidate is connected to the keyframe vector<KeyFrame*> vpConnected = pKF->GetVectorCovisibleKeyFrames(); for(size_t i=0, iend=vpConnected.size(); i<iend; i++) { for(set<KeyFrame*>::iterator spcit=sParentCandidates.begin(), spcend=sParentCandidates.end(); spcit!=spcend; spcit++) { if(vpConnected[i]->mnId == (*spcit)->mnId) { int w = pKF->GetWeight(vpConnected[i]); if(w>max) { pC = pKF; pP = vpConnected[i]; max = w; bContinue = true; } } } } } if(bContinue) { pC->ChangeParent(pP); sParentCandidates.insert(pC); mspChildrens.erase(pC); } else break; } // If a children has no covisibility links with any parent candidate, assign to the original parent of this KF if(!mspChildrens.empty()) for(set<KeyFrame*>::iterator sit=mspChildrens.begin(); sit!=mspChildrens.end(); sit++) { (*sit)->ChangeParent(mpParent); } mpParent->EraseChild(this); mbBad = true; } mpMap->EraseKeyFrame(this); mpKeyFrameDB->erase(this); }