/** * This file is part of ORB-SLAM3 * * Copyright (C) 2017-2020 Carlos Campos, Richard Elvira, Juan J. Gómez José M.M. Montiel and Juan D. Tardós, University of Zaragoza. * Copyright (C) 2014-2016 Raúl Mur-Artal, José M.M. Montiel and Juan D. Tardós, University of Zaragoza. * * ORB-SLAM3 is free software: you can redistribute it and/or modify it under the terms of the GNU General Public * License as published by the Free Software Foundation, either version 3 of the License, or * (at your option) any later version. * * ORB-SLAM3 is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even * the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along with ORB-SLAM3. * If not, see . */ #include "LocalMapping.h" #include "LoopClosing.h" #include "ORBmatcher.h" #include "Optimizer.h" #include "Converter.h" #include #include namespace ORB_SLAM3 { LocalMapping::LocalMapping(System* pSys, Atlas *pAtlas, const float bMonocular, bool bInertial, const string &_strSeqName): mpSystem(pSys), mbMonocular(bMonocular), mbInertial(bInertial), mbResetRequested(false), mbResetRequestedActiveMap(false), mbFinishRequested(false), mbFinished(true), mpAtlas(pAtlas), bInitializing(false), mbAbortBA(false), mbStopped(false), mbStopRequested(false), mbNotStop(false), mbAcceptKeyFrames(true), mbNewInit(false), mIdxInit(0), mScale(1.0), mInitSect(0), mbNotBA1(true), mbNotBA2(true), mIdxIteration(0), infoInertial(Eigen::MatrixXd::Zero(9,9)) { mnMatchesInliers = 0; mbBadImu = false; mTinit = 0.f; mNumLM = 0; mNumKFCulling=0; //DEBUG: times and data from LocalMapping in each frame strSequence = "";//_strSeqName; //f_lm.open("localMapping_times" + strSequence + ".txt"); /*f_lm.open("localMapping_times.txt"); f_lm << "# Timestamp KF, Num CovKFs, Num KFs, Num RecentMPs, Num MPs, processKF, MPCulling, CreateMP, SearchNeigh, BA, KFCulling, [numFixKF_LBA]" << endl; f_lm << fixed;*/ } void LocalMapping::SetLoopCloser(LoopClosing* pLoopCloser) { mpLoopCloser = pLoopCloser; } void LocalMapping::SetTracker(Tracking *pTracker) { mpTracker=pTracker; } void LocalMapping::Run() { mbFinished = false; while(1) { // Tracking will see that Local Mapping is busy SetAcceptKeyFrames(false); // Check if there are keyframes in the queue if(CheckNewKeyFrames() && !mbBadImu) { // std::cout << "LM" << std::endl; std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); // BoW conversion and insertion in Map ProcessNewKeyFrame(); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); // Check recent MapPoints MapPointCulling(); std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now(); // Triangulate new MapPoints CreateNewMapPoints(); std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now(); // Save here: // # Cov KFs // # tot Kfs // # recent added MPs // # tot MPs // # localMPs in LBA // # fixedKFs in LBA mbAbortBA = false; if(!CheckNewKeyFrames()) { // Find more matches in neighbor keyframes and fuse point duplications SearchInNeighbors(); } std::chrono::steady_clock::time_point t4 = std::chrono::steady_clock::now(); std::chrono::steady_clock::time_point t5 = t4, t6 = t4; // mbAbortBA = false; //DEBUG-- /*f_lm << setprecision(0); f_lm << mpCurrentKeyFrame->mTimeStamp*1e9 << ","; f_lm << mpCurrentKeyFrame->GetVectorCovisibleKeyFrames().size() << ","; f_lm << mpCurrentKeyFrame->GetMap()->GetAllKeyFrames().size() << ","; f_lm << mlpRecentAddedMapPoints.size() << ","; f_lm << mpCurrentKeyFrame->GetMap()->GetAllMapPoints().size() << ",";*/ //-- int num_FixedKF_BA = 0; if(!CheckNewKeyFrames() && !stopRequested()) { if(mpAtlas->KeyFramesInMap()>2) { if(mbInertial && mpCurrentKeyFrame->GetMap()->isImuInitialized()) { float dist = cv::norm(mpCurrentKeyFrame->mPrevKF->GetCameraCenter() - mpCurrentKeyFrame->GetCameraCenter()) + cv::norm(mpCurrentKeyFrame->mPrevKF->mPrevKF->GetCameraCenter() - mpCurrentKeyFrame->mPrevKF->GetCameraCenter()); if(dist>0.05) mTinit += mpCurrentKeyFrame->mTimeStamp - mpCurrentKeyFrame->mPrevKF->mTimeStamp; if(!mpCurrentKeyFrame->GetMap()->GetIniertialBA2()) { if((mTinit<10.f) && (dist<0.02)) { cout << "Not enough motion for initializing. Reseting..." << endl; unique_lock lock(mMutexReset); mbResetRequestedActiveMap = true; mpMapToReset = mpCurrentKeyFrame->GetMap(); mbBadImu = true; } } bool bLarge = ((mpTracker->GetMatchesInliers()>75)&&mbMonocular)||((mpTracker->GetMatchesInliers()>100)&&!mbMonocular); Optimizer::LocalInertialBA(mpCurrentKeyFrame, &mbAbortBA, mpCurrentKeyFrame->GetMap(), bLarge, !mpCurrentKeyFrame->GetMap()->GetIniertialBA2()); } else { std::chrono::steady_clock::time_point begin = std::chrono::steady_clock::now(); Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame,&mbAbortBA, mpCurrentKeyFrame->GetMap(),num_FixedKF_BA); std::chrono::steady_clock::time_point end = std::chrono::steady_clock::now(); } } t5 = std::chrono::steady_clock::now(); // Initialize IMU here if(!mpCurrentKeyFrame->GetMap()->isImuInitialized() && mbInertial) { if (mbMonocular) InitializeIMU(1e2, 1e10, true); else InitializeIMU(1e2, 1e5, true); } // Check redundant local Keyframes KeyFrameCulling(); t6 = std::chrono::steady_clock::now(); if ((mTinit<100.0f) && mbInertial) { if(mpCurrentKeyFrame->GetMap()->isImuInitialized() && mpTracker->mState==Tracking::OK) // Enter here everytime local-mapping is called { if(!mpCurrentKeyFrame->GetMap()->GetIniertialBA1()){ if (mTinit>5.0f) { cout << "start VIBA 1" << endl; mpCurrentKeyFrame->GetMap()->SetIniertialBA1(); if (mbMonocular) InitializeIMU(1.f, 1e5, true); // 1.f, 1e5 else InitializeIMU(1.f, 1e5, true); // 1.f, 1e5 cout << "end VIBA 1" << endl; } } //else if (mbNotBA2){ else if(!mpCurrentKeyFrame->GetMap()->GetIniertialBA2()){ if (mTinit>15.0f){ // 15.0f cout << "start VIBA 2" << endl; mpCurrentKeyFrame->GetMap()->SetIniertialBA2(); if (mbMonocular) InitializeIMU(0.f, 0.f, true); // 0.f, 0.f else InitializeIMU(0.f, 0.f, true); cout << "end VIBA 2" << endl; } } // scale refinement if (((mpAtlas->KeyFramesInMap())<=100) && ((mTinit>25.0f && mTinit<25.5f)|| (mTinit>35.0f && mTinit<35.5f)|| (mTinit>45.0f && mTinit<45.5f)|| (mTinit>55.0f && mTinit<55.5f)|| (mTinit>65.0f && mTinit<65.5f)|| (mTinit>75.0f && mTinit<75.5f))){ cout << "start scale ref" << endl; if (mbMonocular) ScaleRefinement(); cout << "end scale ref" << endl; } } } } std::chrono::steady_clock::time_point t7 = std::chrono::steady_clock::now(); mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame); std::chrono::steady_clock::time_point t8 = std::chrono::steady_clock::now(); double t_procKF = std::chrono::duration_cast >(t1 - t0).count(); double t_MPcull = std::chrono::duration_cast >(t2 - t1).count(); double t_CheckMP = std::chrono::duration_cast >(t3 - t2).count(); double t_searchNeigh = std::chrono::duration_cast >(t4 - t3).count(); double t_Opt = std::chrono::duration_cast >(t5 - t4).count(); double t_KF_cull = std::chrono::duration_cast >(t6 - t5).count(); double t_Insert = std::chrono::duration_cast >(t8 - t7).count(); //DEBUG-- /*f_lm << setprecision(6); f_lm << t_procKF << ","; f_lm << t_MPcull << ","; f_lm << t_CheckMP << ","; f_lm << t_searchNeigh << ","; f_lm << t_Opt << ","; f_lm << t_KF_cull << ","; f_lm << setprecision(0) << num_FixedKF_BA << "\n";*/ //-- } else if(Stop() && !mbBadImu) { // Safe area to stop while(isStopped() && !CheckFinish()) { // cout << "LM: usleep if is stopped" << endl; usleep(3000); } if(CheckFinish()) break; } ResetIfRequested(); // Tracking will see that Local Mapping is busy SetAcceptKeyFrames(true); if(CheckFinish()) break; // cout << "LM: normal usleep" << endl; usleep(3000); } //f_lm.close(); SetFinish(); } void LocalMapping::InsertKeyFrame(KeyFrame *pKF) { unique_lock lock(mMutexNewKFs); mlNewKeyFrames.push_back(pKF); mbAbortBA=true; } bool LocalMapping::CheckNewKeyFrames() { unique_lock lock(mMutexNewKFs); return(!mlNewKeyFrames.empty()); } void LocalMapping::ProcessNewKeyFrame() { //cout << "ProcessNewKeyFrame: " << mlNewKeyFrames.size() << endl; { unique_lock lock(mMutexNewKFs); mpCurrentKeyFrame = mlNewKeyFrames.front(); mlNewKeyFrames.pop_front(); } // Compute Bags of Words structures mpCurrentKeyFrame->ComputeBoW(); // Associate MapPoints to the new keyframe and update normal and descriptor const vector vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches(); for(size_t i=0; iisBad()) { if(!pMP->IsInKeyFrame(mpCurrentKeyFrame)) { pMP->AddObservation(mpCurrentKeyFrame, i); pMP->UpdateNormalAndDepth(); pMP->ComputeDistinctiveDescriptors(); } else // this can only happen for new stereo points inserted by the Tracking { mlpRecentAddedMapPoints.push_back(pMP); } } } } // Update links in the Covisibility Graph mpCurrentKeyFrame->UpdateConnections(); // Insert Keyframe in Map mpAtlas->AddKeyFrame(mpCurrentKeyFrame); } void LocalMapping::EmptyQueue() { while(CheckNewKeyFrames()) ProcessNewKeyFrame(); } void LocalMapping::MapPointCulling() { // Check Recent Added MapPoints list::iterator lit = mlpRecentAddedMapPoints.begin(); const unsigned long int nCurrentKFid = mpCurrentKeyFrame->mnId; int nThObs; if(mbMonocular) nThObs = 2; else nThObs = 3; // MODIFICATION_STEREO_IMU here 3 const int cnThObs = nThObs; int borrar = mlpRecentAddedMapPoints.size(); while(lit!=mlpRecentAddedMapPoints.end()) { MapPoint* pMP = *lit; if(pMP->isBad()) lit = mlpRecentAddedMapPoints.erase(lit); else if(pMP->GetFoundRatio()<0.25f) { pMP->SetBadFlag(); lit = mlpRecentAddedMapPoints.erase(lit); } else if(((int)nCurrentKFid-(int)pMP->mnFirstKFid)>=2 && pMP->Observations()<=cnThObs) { pMP->SetBadFlag(); lit = mlpRecentAddedMapPoints.erase(lit); } else if(((int)nCurrentKFid-(int)pMP->mnFirstKFid)>=3) lit = mlpRecentAddedMapPoints.erase(lit); else { lit++; borrar--; } } //cout << "erase MP: " << borrar << endl; } void LocalMapping::CreateNewMapPoints() { // Retrieve neighbor keyframes in covisibility graph int nn = 10; // For stereo inertial case if(mbMonocular) nn=20; vector vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn); if (mbInertial) { KeyFrame* pKF = mpCurrentKeyFrame; int count=0; while((vpNeighKFs.size()<=nn)&&(pKF->mPrevKF)&&(count++::iterator it = std::find(vpNeighKFs.begin(), vpNeighKFs.end(), pKF->mPrevKF); if(it==vpNeighKFs.end()) vpNeighKFs.push_back(pKF->mPrevKF); pKF = pKF->mPrevKF; } } float th = 0.6f; ORBmatcher matcher(th,false); cv::Mat Rcw1 = mpCurrentKeyFrame->GetRotation(); cv::Mat Rwc1 = Rcw1.t(); cv::Mat tcw1 = mpCurrentKeyFrame->GetTranslation(); cv::Mat Tcw1(3,4,CV_32F); Rcw1.copyTo(Tcw1.colRange(0,3)); tcw1.copyTo(Tcw1.col(3)); cv::Mat Ow1 = mpCurrentKeyFrame->GetCameraCenter(); const float &fx1 = mpCurrentKeyFrame->fx; const float &fy1 = mpCurrentKeyFrame->fy; const float &cx1 = mpCurrentKeyFrame->cx; const float &cy1 = mpCurrentKeyFrame->cy; const float &invfx1 = mpCurrentKeyFrame->invfx; const float &invfy1 = mpCurrentKeyFrame->invfy; const float ratioFactor = 1.5f*mpCurrentKeyFrame->mfScaleFactor; // Search matches with epipolar restriction and triangulate for(size_t i=0; i0 && CheckNewKeyFrames())// && (mnMatchesInliers>50)) return; KeyFrame* pKF2 = vpNeighKFs[i]; GeometricCamera* pCamera1 = mpCurrentKeyFrame->mpCamera, *pCamera2 = pKF2->mpCamera; // Check first that baseline is not too short cv::Mat Ow2 = pKF2->GetCameraCenter(); cv::Mat vBaseline = Ow2-Ow1; const float baseline = cv::norm(vBaseline); if(!mbMonocular) { if(baselinemb) continue; } else { const float medianDepthKF2 = pKF2->ComputeSceneMedianDepth(2); const float ratioBaselineDepth = baseline/medianDepthKF2; if(ratioBaselineDepth<0.01) continue; } // Compute Fundamental Matrix cv::Mat F12 = ComputeF12(mpCurrentKeyFrame,pKF2); // Search matches that fullfil epipolar constraint vector > vMatchedIndices; bool bCoarse = mbInertial && ((!mpCurrentKeyFrame->GetMap()->GetIniertialBA2() && mpCurrentKeyFrame->GetMap()->GetIniertialBA1())|| mpTracker->mState==Tracking::RECENTLY_LOST); matcher.SearchForTriangulation(mpCurrentKeyFrame,pKF2,F12,vMatchedIndices,false,bCoarse); cv::Mat Rcw2 = pKF2->GetRotation(); cv::Mat Rwc2 = Rcw2.t(); cv::Mat tcw2 = pKF2->GetTranslation(); cv::Mat Tcw2(3,4,CV_32F); Rcw2.copyTo(Tcw2.colRange(0,3)); tcw2.copyTo(Tcw2.col(3)); const float &fx2 = pKF2->fx; const float &fy2 = pKF2->fy; const float &cx2 = pKF2->cx; const float &cy2 = pKF2->cy; const float &invfx2 = pKF2->invfx; const float &invfy2 = pKF2->invfy; // Triangulate each match const int nmatches = vMatchedIndices.size(); for(int ikp=0; ikp NLeft == -1) ? mpCurrentKeyFrame->mvKeysUn[idx1] : (idx1 < mpCurrentKeyFrame -> NLeft) ? mpCurrentKeyFrame -> mvKeys[idx1] : mpCurrentKeyFrame -> mvKeysRight[idx1 - mpCurrentKeyFrame -> NLeft]; const float kp1_ur=mpCurrentKeyFrame->mvuRight[idx1]; bool bStereo1 = (!mpCurrentKeyFrame->mpCamera2 && kp1_ur>=0); const bool bRight1 = (mpCurrentKeyFrame -> NLeft == -1 || idx1 < mpCurrentKeyFrame -> NLeft) ? false : true; const cv::KeyPoint &kp2 = (pKF2 -> NLeft == -1) ? pKF2->mvKeysUn[idx2] : (idx2 < pKF2 -> NLeft) ? pKF2 -> mvKeys[idx2] : pKF2 -> mvKeysRight[idx2 - pKF2 -> NLeft]; const float kp2_ur = pKF2->mvuRight[idx2]; bool bStereo2 = (!pKF2->mpCamera2 && kp2_ur>=0); const bool bRight2 = (pKF2 -> NLeft == -1 || idx2 < pKF2 -> NLeft) ? false : true; if(mpCurrentKeyFrame->mpCamera2 && pKF2->mpCamera2){ if(bRight1 && bRight2){ Rcw1 = mpCurrentKeyFrame->GetRightRotation(); Rwc1 = Rcw1.t(); tcw1 = mpCurrentKeyFrame->GetRightTranslation(); Tcw1 = mpCurrentKeyFrame->GetRightPose(); Ow1 = mpCurrentKeyFrame->GetRightCameraCenter(); Rcw2 = pKF2->GetRightRotation(); Rwc2 = Rcw2.t(); tcw2 = pKF2->GetRightTranslation(); Tcw2 = pKF2->GetRightPose(); Ow2 = pKF2->GetRightCameraCenter(); pCamera1 = mpCurrentKeyFrame->mpCamera2; pCamera2 = pKF2->mpCamera2; } else if(bRight1 && !bRight2){ Rcw1 = mpCurrentKeyFrame->GetRightRotation(); Rwc1 = Rcw1.t(); tcw1 = mpCurrentKeyFrame->GetRightTranslation(); Tcw1 = mpCurrentKeyFrame->GetRightPose(); Ow1 = mpCurrentKeyFrame->GetRightCameraCenter(); Rcw2 = pKF2->GetRotation(); Rwc2 = Rcw2.t(); tcw2 = pKF2->GetTranslation(); Tcw2 = pKF2->GetPose(); Ow2 = pKF2->GetCameraCenter(); pCamera1 = mpCurrentKeyFrame->mpCamera2; pCamera2 = pKF2->mpCamera; } else if(!bRight1 && bRight2){ Rcw1 = mpCurrentKeyFrame->GetRotation(); Rwc1 = Rcw1.t(); tcw1 = mpCurrentKeyFrame->GetTranslation(); Tcw1 = mpCurrentKeyFrame->GetPose(); Ow1 = mpCurrentKeyFrame->GetCameraCenter(); Rcw2 = pKF2->GetRightRotation(); Rwc2 = Rcw2.t(); tcw2 = pKF2->GetRightTranslation(); Tcw2 = pKF2->GetRightPose(); Ow2 = pKF2->GetRightCameraCenter(); pCamera1 = mpCurrentKeyFrame->mpCamera; pCamera2 = pKF2->mpCamera2; } else{ Rcw1 = mpCurrentKeyFrame->GetRotation(); Rwc1 = Rcw1.t(); tcw1 = mpCurrentKeyFrame->GetTranslation(); Tcw1 = mpCurrentKeyFrame->GetPose(); Ow1 = mpCurrentKeyFrame->GetCameraCenter(); Rcw2 = pKF2->GetRotation(); Rwc2 = Rcw2.t(); tcw2 = pKF2->GetTranslation(); Tcw2 = pKF2->GetPose(); Ow2 = pKF2->GetCameraCenter(); pCamera1 = mpCurrentKeyFrame->mpCamera; pCamera2 = pKF2->mpCamera; } } // Check parallax between rays cv::Mat xn1 = pCamera1->unprojectMat(kp1.pt); cv::Mat xn2 = pCamera2->unprojectMat(kp2.pt); cv::Mat ray1 = Rwc1*xn1; cv::Mat ray2 = Rwc2*xn2; const float cosParallaxRays = ray1.dot(ray2)/(cv::norm(ray1)*cv::norm(ray2)); float cosParallaxStereo = cosParallaxRays+1; float cosParallaxStereo1 = cosParallaxStereo; float cosParallaxStereo2 = cosParallaxStereo; if(bStereo1) cosParallaxStereo1 = cos(2*atan2(mpCurrentKeyFrame->mb/2,mpCurrentKeyFrame->mvDepth[idx1])); else if(bStereo2) cosParallaxStereo2 = cos(2*atan2(pKF2->mb/2,pKF2->mvDepth[idx2])); cosParallaxStereo = min(cosParallaxStereo1,cosParallaxStereo2); cv::Mat x3D; if(cosParallaxRays0 && (bStereo1 || bStereo2 || (cosParallaxRays<0.9998 && mbInertial) || (cosParallaxRays<0.9998 && !mbInertial))) { // Linear Triangulation Method cv::Mat A(4,4,CV_32F); A.row(0) = xn1.at(0)*Tcw1.row(2)-Tcw1.row(0); A.row(1) = xn1.at(1)*Tcw1.row(2)-Tcw1.row(1); A.row(2) = xn2.at(0)*Tcw2.row(2)-Tcw2.row(0); A.row(3) = xn2.at(1)*Tcw2.row(2)-Tcw2.row(1); cv::Mat w,u,vt; cv::SVD::compute(A,w,u,vt,cv::SVD::MODIFY_A| cv::SVD::FULL_UV); x3D = vt.row(3).t(); if(x3D.at(3)==0) continue; // Euclidean coordinates x3D = x3D.rowRange(0,3)/x3D.at(3); } else if(bStereo1 && cosParallaxStereo1UnprojectStereo(idx1); } else if(bStereo2 && cosParallaxStereo2UnprojectStereo(idx2); } else { continue; //No stereo and very low parallax } cv::Mat x3Dt = x3D.t(); if(x3Dt.empty()) continue; //Check triangulation in front of cameras float z1 = Rcw1.row(2).dot(x3Dt)+tcw1.at(2); if(z1<=0) continue; float z2 = Rcw2.row(2).dot(x3Dt)+tcw2.at(2); if(z2<=0) continue; //Check reprojection error in first keyframe const float &sigmaSquare1 = mpCurrentKeyFrame->mvLevelSigma2[kp1.octave]; const float x1 = Rcw1.row(0).dot(x3Dt)+tcw1.at(0); const float y1 = Rcw1.row(1).dot(x3Dt)+tcw1.at(1); const float invz1 = 1.0/z1; if(!bStereo1) { cv::Point2f uv1 = pCamera1->project(cv::Point3f(x1,y1,z1)); float errX1 = uv1.x - kp1.pt.x; float errY1 = uv1.y - kp1.pt.y; if((errX1*errX1+errY1*errY1)>5.991*sigmaSquare1) continue; } else { float u1 = fx1*x1*invz1+cx1; float u1_r = u1 - mpCurrentKeyFrame->mbf*invz1; float v1 = fy1*y1*invz1+cy1; float errX1 = u1 - kp1.pt.x; float errY1 = v1 - kp1.pt.y; float errX1_r = u1_r - kp1_ur; if((errX1*errX1+errY1*errY1+errX1_r*errX1_r)>7.8*sigmaSquare1) continue; } //Check reprojection error in second keyframe const float sigmaSquare2 = pKF2->mvLevelSigma2[kp2.octave]; const float x2 = Rcw2.row(0).dot(x3Dt)+tcw2.at(0); const float y2 = Rcw2.row(1).dot(x3Dt)+tcw2.at(1); const float invz2 = 1.0/z2; if(!bStereo2) { cv::Point2f uv2 = pCamera2->project(cv::Point3f(x2,y2,z2)); float errX2 = uv2.x - kp2.pt.x; float errY2 = uv2.y - kp2.pt.y; if((errX2*errX2+errY2*errY2)>5.991*sigmaSquare2) continue; } else { float u2 = fx2*x2*invz2+cx2; float u2_r = u2 - mpCurrentKeyFrame->mbf*invz2; float v2 = fy2*y2*invz2+cy2; float errX2 = u2 - kp2.pt.x; float errY2 = v2 - kp2.pt.y; float errX2_r = u2_r - kp2_ur; if((errX2*errX2+errY2*errY2+errX2_r*errX2_r)>7.8*sigmaSquare2) continue; } //Check scale consistency cv::Mat normal1 = x3D-Ow1; float dist1 = cv::norm(normal1); cv::Mat normal2 = x3D-Ow2; float dist2 = cv::norm(normal2); if(dist1==0 || dist2==0) continue; if(mbFarPoints && (dist1>=mThFarPoints||dist2>=mThFarPoints)) // MODIFICATION continue; const float ratioDist = dist2/dist1; const float ratioOctave = mpCurrentKeyFrame->mvScaleFactors[kp1.octave]/pKF2->mvScaleFactors[kp2.octave]; if(ratioDist*ratioFactorratioOctave*ratioFactor) continue; // Triangulation is succesfull MapPoint* pMP = new MapPoint(x3D,mpCurrentKeyFrame,mpAtlas->GetCurrentMap()); pMP->AddObservation(mpCurrentKeyFrame,idx1); pMP->AddObservation(pKF2,idx2); mpCurrentKeyFrame->AddMapPoint(pMP,idx1); pKF2->AddMapPoint(pMP,idx2); pMP->ComputeDistinctiveDescriptors(); pMP->UpdateNormalAndDepth(); mpAtlas->AddMapPoint(pMP); mlpRecentAddedMapPoints.push_back(pMP); } } } void LocalMapping::SearchInNeighbors() { // Retrieve neighbor keyframes int nn = 10; if(mbMonocular) nn=20; const vector vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn); vector vpTargetKFs; for(vector::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; } // Add some covisible of covisible // Extend to some second neighbors if abort is not requested for(int i=0, imax=vpTargetKFs.size(); i vpSecondNeighKFs = vpTargetKFs[i]->GetBestCovisibilityKeyFrames(20); for(vector::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); pKFi2->mnFuseTargetForKF=mpCurrentKeyFrame->mnId; } if (mbAbortBA) break; } // Extend to temporal neighbors if(mbInertial) { KeyFrame* pKFi = mpCurrentKeyFrame->mPrevKF; while(vpTargetKFs.size()<20 && pKFi) { if(pKFi->isBad() || pKFi->mnFuseTargetForKF==mpCurrentKeyFrame->mnId) { pKFi = pKFi->mPrevKF; continue; } vpTargetKFs.push_back(pKFi); pKFi->mnFuseTargetForKF=mpCurrentKeyFrame->mnId; pKFi = pKFi->mPrevKF; } } // Search matches by projection from current KF in target KFs ORBmatcher matcher; vector vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches(); for(vector::iterator vit=vpTargetKFs.begin(), vend=vpTargetKFs.end(); vit!=vend; vit++) { KeyFrame* pKFi = *vit; matcher.Fuse(pKFi,vpMapPointMatches); if(pKFi->NLeft != -1) matcher.Fuse(pKFi,vpMapPointMatches,true); } if (mbAbortBA) return; // Search matches by projection from target KFs in current KF vector vpFuseCandidates; vpFuseCandidates.reserve(vpTargetKFs.size()*vpMapPointMatches.size()); for(vector::iterator vitKF=vpTargetKFs.begin(), vendKF=vpTargetKFs.end(); vitKF!=vendKF; vitKF++) { KeyFrame* pKFi = *vitKF; vector vpMapPointsKFi = pKFi->GetMapPointMatches(); for(vector::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); if(mpCurrentKeyFrame->NLeft != -1) matcher.Fuse(mpCurrentKeyFrame,vpFuseCandidates,true); // Update points vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches(); for(size_t i=0, iend=vpMapPointMatches.size(); iisBad()) { pMP->ComputeDistinctiveDescriptors(); pMP->UpdateNormalAndDepth(); } } } // Update connections in covisibility graph mpCurrentKeyFrame->UpdateConnections(); } cv::Mat LocalMapping::ComputeF12(KeyFrame *&pKF1, KeyFrame *&pKF2) { cv::Mat R1w = pKF1->GetRotation(); cv::Mat t1w = pKF1->GetTranslation(); cv::Mat R2w = pKF2->GetRotation(); cv::Mat t2w = pKF2->GetTranslation(); cv::Mat R12 = R1w*R2w.t(); cv::Mat t12 = -R1w*R2w.t()*t2w+t1w; cv::Mat t12x = SkewSymmetricMatrix(t12); const cv::Mat &K1 = pKF1->mpCamera->toK(); const cv::Mat &K2 = pKF2->mpCamera->toK(); return K1.t().inv()*t12x*R12*K2.inv(); } void LocalMapping::RequestStop() { unique_lock lock(mMutexStop); mbStopRequested = true; unique_lock lock2(mMutexNewKFs); mbAbortBA = true; } bool LocalMapping::Stop() { unique_lock lock(mMutexStop); if(mbStopRequested && !mbNotStop) { mbStopped = true; cout << "Local Mapping STOP" << endl; return true; } return false; } bool LocalMapping::isStopped() { unique_lock lock(mMutexStop); return mbStopped; } bool LocalMapping::stopRequested() { unique_lock lock(mMutexStop); return mbStopRequested; } void LocalMapping::Release() { unique_lock lock(mMutexStop); unique_lock lock2(mMutexFinish); if(mbFinished) return; mbStopped = false; mbStopRequested = false; for(list::iterator lit = mlNewKeyFrames.begin(), lend=mlNewKeyFrames.end(); lit!=lend; lit++) delete *lit; mlNewKeyFrames.clear(); cout << "Local Mapping RELEASE" << endl; } bool LocalMapping::AcceptKeyFrames() { unique_lock lock(mMutexAccept); return mbAcceptKeyFrames; } void LocalMapping::SetAcceptKeyFrames(bool flag) { unique_lock lock(mMutexAccept); mbAcceptKeyFrames=flag; } bool LocalMapping::SetNotStop(bool flag) { unique_lock lock(mMutexStop); if(flag && mbStopped) return false; mbNotStop = flag; return true; } void LocalMapping::InterruptBA() { mbAbortBA = true; } void LocalMapping::KeyFrameCulling() { // Check redundant keyframes (only local keyframes) // A keyframe is considered redundant if the 90% of the MapPoints it sees, are seen // in at least other 3 keyframes (in the same or finer scale) // We only consider close stereo points const int Nd = 21; // MODIFICATION_STEREO_IMU 20 This should be the same than that one from LIBA mpCurrentKeyFrame->UpdateBestCovisibles(); vector vpLocalKeyFrames = mpCurrentKeyFrame->GetVectorCovisibleKeyFrames(); float redundant_th; if(!mbInertial) redundant_th = 0.9; else if (mbMonocular) redundant_th = 0.9; else redundant_th = 0.5; const bool bInitImu = mpAtlas->isImuInitialized(); int count=0; // Compoute last KF from optimizable window: unsigned int last_ID; if (mbInertial) { int count = 0; KeyFrame* aux_KF = mpCurrentKeyFrame; while(countmPrevKF) { aux_KF = aux_KF->mPrevKF; count++; } last_ID = aux_KF->mnId; } for(vector::iterator vit=vpLocalKeyFrames.begin(), vend=vpLocalKeyFrames.end(); vit!=vend; vit++) { count++; KeyFrame* pKF = *vit; if((pKF->mnId==pKF->GetMap()->GetInitKFid()) || pKF->isBad()) continue; const vector vpMapPoints = pKF->GetMapPointMatches(); int nObs = 3; const int thObs=nObs; int nRedundantObservations=0; int nMPs=0; for(size_t i=0, iend=vpMapPoints.size(); iisBad()) { if(!mbMonocular) { if(pKF->mvDepth[i]>pKF->mThDepth || pKF->mvDepth[i]<0) continue; } nMPs++; if(pMP->Observations()>thObs) { const int &scaleLevel = (pKF -> NLeft == -1) ? pKF->mvKeysUn[i].octave : (i < pKF -> NLeft) ? pKF -> mvKeys[i].octave : pKF -> mvKeysRight[i].octave; const map> observations = pMP->GetObservations(); int nObs=0; for(map>::const_iterator mit=observations.begin(), mend=observations.end(); mit!=mend; mit++) { KeyFrame* pKFi = mit->first; if(pKFi==pKF) continue; tuple indexes = mit->second; int leftIndex = get<0>(indexes), rightIndex = get<1>(indexes); int scaleLeveli = -1; if(pKFi -> NLeft == -1) scaleLeveli = pKFi->mvKeysUn[leftIndex].octave; else { if (leftIndex != -1) { scaleLeveli = pKFi->mvKeys[leftIndex].octave; } if (rightIndex != -1) { int rightLevel = pKFi->mvKeysRight[rightIndex - pKFi->NLeft].octave; scaleLeveli = (scaleLeveli == -1 || scaleLeveli > rightLevel) ? rightLevel : scaleLeveli; } } if(scaleLeveli<=scaleLevel+1) { nObs++; if(nObs>thObs) break; } } if(nObs>thObs) { nRedundantObservations++; } } } } } if(nRedundantObservations>redundant_th*nMPs) { if (mbInertial) { if (mpAtlas->KeyFramesInMap()<=Nd) continue; if(pKF->mnId>(mpCurrentKeyFrame->mnId-2)) continue; if(pKF->mPrevKF && pKF->mNextKF) { const float t = pKF->mNextKF->mTimeStamp-pKF->mPrevKF->mTimeStamp; if((bInitImu && (pKF->mnIdmNextKF->mpImuPreintegrated->MergePrevious(pKF->mpImuPreintegrated); pKF->mNextKF->mPrevKF = pKF->mPrevKF; pKF->mPrevKF->mNextKF = pKF->mNextKF; pKF->mNextKF = NULL; pKF->mPrevKF = NULL; pKF->SetBadFlag(); } else if(!mpCurrentKeyFrame->GetMap()->GetIniertialBA2() && (cv::norm(pKF->GetImuPosition()-pKF->mPrevKF->GetImuPosition())<0.02) && (t<3)) { pKF->mNextKF->mpImuPreintegrated->MergePrevious(pKF->mpImuPreintegrated); pKF->mNextKF->mPrevKF = pKF->mPrevKF; pKF->mPrevKF->mNextKF = pKF->mNextKF; pKF->mNextKF = NULL; pKF->mPrevKF = NULL; pKF->SetBadFlag(); } } } else { pKF->SetBadFlag(); } } if((count > 20 && mbAbortBA) || count>100) // MODIFICATION originally 20 for mbabortBA check just 10 keyframes { break; } } } cv::Mat LocalMapping::SkewSymmetricMatrix(const cv::Mat &v) { return (cv::Mat_(3,3) << 0, -v.at(2), v.at(1), v.at(2), 0,-v.at(0), -v.at(1), v.at(0), 0); } void LocalMapping::RequestReset() { { unique_lock lock(mMutexReset); cout << "LM: Map reset recieved" << endl; mbResetRequested = true; } cout << "LM: Map reset, waiting..." << endl; while(1) { { unique_lock lock2(mMutexReset); if(!mbResetRequested) break; } usleep(3000); } cout << "LM: Map reset, Done!!!" << endl; } void LocalMapping::RequestResetActiveMap(Map* pMap) { { unique_lock lock(mMutexReset); cout << "LM: Active map reset recieved" << endl; mbResetRequestedActiveMap = true; mpMapToReset = pMap; } cout << "LM: Active map reset, waiting..." << endl; while(1) { { unique_lock lock2(mMutexReset); if(!mbResetRequestedActiveMap) break; } usleep(3000); } cout << "LM: Active map reset, Done!!!" << endl; } void LocalMapping::ResetIfRequested() { bool executed_reset = false; { unique_lock lock(mMutexReset); if(mbResetRequested) { executed_reset = true; cout << "LM: Reseting Atlas in Local Mapping..." << endl; mlNewKeyFrames.clear(); mlpRecentAddedMapPoints.clear(); mbResetRequested=false; mbResetRequestedActiveMap = false; // Inertial parameters mTinit = 0.f; mbNotBA2 = true; mbNotBA1 = true; mbBadImu=false; mIdxInit=0; cout << "LM: End reseting Local Mapping..." << endl; } if(mbResetRequestedActiveMap) { executed_reset = true; cout << "LM: Reseting current map in Local Mapping..." << endl; mlNewKeyFrames.clear(); mlpRecentAddedMapPoints.clear(); // Inertial parameters mTinit = 0.f; mbNotBA2 = true; mbNotBA1 = true; mbBadImu=false; mbResetRequestedActiveMap = false; cout << "LM: End reseting Local Mapping..." << endl; } } if(executed_reset) cout << "LM: Reset free the mutex" << endl; } void LocalMapping::RequestFinish() { unique_lock lock(mMutexFinish); mbFinishRequested = true; } bool LocalMapping::CheckFinish() { unique_lock lock(mMutexFinish); return mbFinishRequested; } void LocalMapping::SetFinish() { unique_lock lock(mMutexFinish); mbFinished = true; unique_lock lock2(mMutexStop); mbStopped = true; } bool LocalMapping::isFinished() { unique_lock lock(mMutexFinish); return mbFinished; } void LocalMapping::InitializeIMU(float priorG, float priorA, bool bFIBA) { if (mbResetRequested) return; float minTime; int nMinKF; if (mbMonocular) { minTime = 2.0; nMinKF = 10; } else { minTime = 1.0; nMinKF = 10; } if(mpAtlas->KeyFramesInMap() lpKF; KeyFrame* pKF = mpCurrentKeyFrame; while(pKF->mPrevKF) { lpKF.push_front(pKF); pKF = pKF->mPrevKF; } lpKF.push_front(pKF); vector vpKF(lpKF.begin(),lpKF.end()); if(vpKF.size()mTimeStamp; if(mpCurrentKeyFrame->mTimeStamp-mFirstTsGetMap()->isImuInitialized()) { cv::Mat cvRwg; cv::Mat dirG = cv::Mat::zeros(3,1,CV_32F); for(vector::iterator itKF = vpKF.begin(); itKF!=vpKF.end(); itKF++) { if (!(*itKF)->mpImuPreintegrated) continue; if (!(*itKF)->mPrevKF) continue; dirG -= (*itKF)->mPrevKF->GetImuRotation()*(*itKF)->mpImuPreintegrated->GetUpdatedDeltaVelocity(); cv::Mat _vel = ((*itKF)->GetImuPosition() - (*itKF)->mPrevKF->GetImuPosition())/(*itKF)->mpImuPreintegrated->dT; (*itKF)->SetVelocity(_vel); (*itKF)->mPrevKF->SetVelocity(_vel); } dirG = dirG/cv::norm(dirG); cv::Mat gI = (cv::Mat_(3,1) << 0.0f, 0.0f, -1.0f); cv::Mat v = gI.cross(dirG); const float nv = cv::norm(v); const float cosg = gI.dot(dirG); const float ang = acos(cosg); cv::Mat vzg = v*ang/nv; cvRwg = IMU::ExpSO3(vzg); mRwg = Converter::toMatrix3d(cvRwg); mTinit = mpCurrentKeyFrame->mTimeStamp-mFirstTs; } else { mRwg = Eigen::Matrix3d::Identity(); mbg = Converter::toVector3d(mpCurrentKeyFrame->GetGyroBias()); mba = Converter::toVector3d(mpCurrentKeyFrame->GetAccBias()); } mScale=1.0; mInitTime = mpTracker->mLastFrame.mTimeStamp-vpKF.front()->mTimeStamp; std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); Optimizer::InertialOptimization(mpAtlas->GetCurrentMap(), mRwg, mScale, mbg, mba, mbMonocular, infoInertial, false, false, priorG, priorA); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); /*cout << "scale after inertial-only optimization: " << mScale << endl; cout << "bg after inertial-only optimization: " << mbg << endl; cout << "ba after inertial-only optimization: " << mba << endl;*/ if (mScale<1e-1) { cout << "scale too small" << endl; bInitializing=false; return; } // Before this line we are not changing the map unique_lock lock(mpAtlas->GetCurrentMap()->mMutexMapUpdate); std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now(); if ((fabs(mScale-1.f)>0.00001)||!mbMonocular) { mpAtlas->GetCurrentMap()->ApplyScaledRotation(Converter::toCvMat(mRwg).t(),mScale,true); mpTracker->UpdateFrameIMU(mScale,vpKF[0]->GetImuBias(),mpCurrentKeyFrame); } std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now(); // Check if initialization OK if (!mpAtlas->isImuInitialized()) for(int i=0;ibImu = true; } /*cout << "Before GIBA: " << endl; cout << "ba: " << mpCurrentKeyFrame->GetAccBias() << endl; cout << "bg: " << mpCurrentKeyFrame->GetGyroBias() << endl;*/ std::chrono::steady_clock::time_point t4 = std::chrono::steady_clock::now(); if (bFIBA) { if (priorA!=0.f) Optimizer::FullInertialBA(mpAtlas->GetCurrentMap(), 100, false, 0, NULL, true, priorG, priorA); else Optimizer::FullInertialBA(mpAtlas->GetCurrentMap(), 100, false, 0, NULL, false); } std::chrono::steady_clock::time_point t5 = std::chrono::steady_clock::now(); // If initialization is OK mpTracker->UpdateFrameIMU(1.0,vpKF[0]->GetImuBias(),mpCurrentKeyFrame); if (!mpAtlas->isImuInitialized()) { cout << "IMU in Map " << mpAtlas->GetCurrentMap()->GetId() << " is initialized" << endl; mpAtlas->SetImuInitialized(); mpTracker->t0IMU = mpTracker->mCurrentFrame.mTimeStamp; mpCurrentKeyFrame->bImu = true; } mbNewInit=true; mnKFs=vpKF.size(); mIdxInit++; for(list::iterator lit = mlNewKeyFrames.begin(), lend=mlNewKeyFrames.end(); lit!=lend; lit++) { (*lit)->SetBadFlag(); delete *lit; } mlNewKeyFrames.clear(); mpTracker->mState=Tracking::OK; bInitializing = false; /*cout << "After GIBA: " << endl; cout << "ba: " << mpCurrentKeyFrame->GetAccBias() << endl; cout << "bg: " << mpCurrentKeyFrame->GetGyroBias() << endl; double t_inertial_only = std::chrono::duration_cast >(t1 - t0).count(); double t_update = std::chrono::duration_cast >(t3 - t2).count(); double t_viba = std::chrono::duration_cast >(t5 - t4).count(); cout << t_inertial_only << ", " << t_update << ", " << t_viba << endl;*/ mpCurrentKeyFrame->GetMap()->IncreaseChangeIndex(); return; } void LocalMapping::ScaleRefinement() { // Minimum number of keyframes to compute a solution // Minimum time (seconds) between first and last keyframe to compute a solution. Make the difference between monocular and stereo // unique_lock lock0(mMutexImuInit); if (mbResetRequested) return; // Retrieve all keyframes in temporal order list lpKF; KeyFrame* pKF = mpCurrentKeyFrame; while(pKF->mPrevKF) { lpKF.push_front(pKF); pKF = pKF->mPrevKF; } lpKF.push_front(pKF); vector vpKF(lpKF.begin(),lpKF.end()); while(CheckNewKeyFrames()) { ProcessNewKeyFrame(); vpKF.push_back(mpCurrentKeyFrame); lpKF.push_back(mpCurrentKeyFrame); } const int N = vpKF.size(); mRwg = Eigen::Matrix3d::Identity(); mScale=1.0; std::chrono::steady_clock::time_point t0 = std::chrono::steady_clock::now(); Optimizer::InertialOptimization(mpAtlas->GetCurrentMap(), mRwg, mScale); std::chrono::steady_clock::time_point t1 = std::chrono::steady_clock::now(); if (mScale<1e-1) // 1e-1 { cout << "scale too small" << endl; bInitializing=false; return; } // Before this line we are not changing the map unique_lock lock(mpAtlas->GetCurrentMap()->mMutexMapUpdate); std::chrono::steady_clock::time_point t2 = std::chrono::steady_clock::now(); if ((fabs(mScale-1.f)>0.00001)||!mbMonocular) { mpAtlas->GetCurrentMap()->ApplyScaledRotation(Converter::toCvMat(mRwg).t(),mScale,true); mpTracker->UpdateFrameIMU(mScale,mpCurrentKeyFrame->GetImuBias(),mpCurrentKeyFrame); } std::chrono::steady_clock::time_point t3 = std::chrono::steady_clock::now(); for(list::iterator lit = mlNewKeyFrames.begin(), lend=mlNewKeyFrames.end(); lit!=lend; lit++) { (*lit)->SetBadFlag(); delete *lit; } mlNewKeyFrames.clear(); double t_inertial_only = std::chrono::duration_cast >(t1 - t0).count(); // To perform pose-inertial opt w.r.t. last keyframe mpCurrentKeyFrame->GetMap()->IncreaseChangeIndex(); return; } bool LocalMapping::IsInitializing() { return bInitializing; } double LocalMapping::GetCurrKFTime() { if (mpCurrentKeyFrame) { return mpCurrentKeyFrame->mTimeStamp; } else return 0.0; } KeyFrame* LocalMapping::GetCurrKF() { return mpCurrentKeyFrame; } } //namespace ORB_SLAM