LocalMapping.h
/**
* This file is part of ORB-SLAM2.
*
* Copyright (C) 2014-2016 Raúl Mur-Artal (University of Zaragoza)
* For more information see
*
* ORB-SLAM2 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-SLAM2 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-SLAM2. If not, see .
*/
#ifndef LOCALMAPPING_H
#define LOCALMAPPING_H
#include "KeyFrame.h"
#include "Map.h"
#include "LoopClosing.h"
#include "Tracking.h"
#include "KeyFrameDatabase.h"
#include
namespace ORB_SLAM2
{
class Tracking;
class LoopClosing;
class Map;
/**
* 创建局部地图
* 这里的LocalMapping::Run函数在单独的一个线程中运行
*/
class LocalMapping
{
public:
LocalMapping(Map* pMap, const float bMonocular);
///设置回环的对象指针
void SetLoopCloser(LoopClosing* pLoopCloser);
///设置Tracker对象的指针
void SetTracker(Tracking* pTracker);
// Main function
void Run();
void InsertKeyFrame(KeyFrame* pKF);
// Thread Synch
void RequestStop();
void RequestReset();
bool Stop();
void Release();
/// If Local Mapping is freezed by a Loop Closure do not insert keyframes
bool isStopped();
bool stopRequested();
/// is local mapper busying, false: local mapper busy, cannot accept key frame
bool AcceptKeyFrames();
/// false: localMapping cannot accept keyframe now, true: local mapping can accept keyframe now
void SetAcceptKeyFrames(bool flag);
bool SetNotStop(bool flag);
void InterruptBA();
void RequestFinish();
bool isFinished();
int KeyframesInQueue(){
unique_lock<std::mutex> lock(mMutexNewKFs);
return mlNewKeyFrames.size();
}
protected:
/// Check if there are keyframes in the queue
bool CheckNewKeyFrames();
void ProcessNewKeyFrame();
void CreateNewMapPoints();
void MapPointCulling();
void SearchInNeighbors();
void KeyFrameCulling();
cv::Mat ComputeF12(KeyFrame* &pKF1, KeyFrame* &pKF2);
cv::Mat SkewSymmetricMatrix(const cv::Mat &v);
bool mbMonocular;
void ResetIfRequested();
bool mbResetRequested;
std::mutex mMutexReset;
bool CheckFinish();
void SetFinish();
bool mbFinishRequested;
bool mbFinished;
std::mutex mMutexFinish;
Map* mpMap;
LoopClosing* mpLoopCloser;
Tracking* mpTracker;
//关键帧队列
std::list<KeyFrame*> mlNewKeyFrames;
KeyFrame* mpCurrentKeyFrame;
std::list<MapPoint*> mlpRecentAddedMapPoints;
std::mutex mMutexNewKFs;
bool mbAbortBA;
bool mbStopped;
bool mbStopRequested;
bool mbNotStop;
std::mutex mMutexStop;
bool mbAcceptKeyFrames;
std::mutex mMutexAccept;
};
} //namespace ORB_SLAM
#endif // LOCALMAPPING_H
LocalMapping.cpp
/**
* This file is part of ORB-SLAM2.
*
* Copyright (C) 2014-2016 Raúl Mur-Artal (University of Zaragoza)
* For more information see
*
* ORB-SLAM2 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-SLAM2 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-SLAM2. If not, see .
*/
#include "LocalMapping.h"
#include "LoopClosing.h"
#include "ORBmatcher.h"
#include "Optimizer.h"
#include
namespace ORB_SLAM2
{
LocalMapping::LocalMapping(Map *pMap, const float bMonocular) : mbMonocular(bMonocular), mbResetRequested(false), mbFinishRequested(false), mbFinished(true), mpMap(pMap),
mbAbortBA(false), mbStopped(false), mbStopRequested(false), mbNotStop(false), mbAcceptKeyFrames(true)
{
}
void LocalMapping::SetLoopCloser(LoopClosing *pLoopCloser)
{
mpLoopCloser = pLoopCloser;
}
void LocalMapping::SetTracker(Tracking *pTracker)
{
mpTracker = pTracker;
}
/**
* LocalMapping
* while循环里面不断循环执行判断是否有新的关键帧,然后处理关键帧,
* 然后剔除不合理的地图点,然后三角化新的关键帧创建更多地图点,
* 然后进行LocalBA优化
*/
void LocalMapping::Run()
{
mbFinished = false;
while (1)
{
// Tracking will see that Local Mapping is busy
/// false: localMapping cannot accept keyframe now, true: local mapping can accept keyframe now
SetAcceptKeyFrames(false);
// Check if there are keyframes in the queue
if (CheckNewKeyFrames())
{
// BoW conversion and insertion in Map
ProcessNewKeyFrame();
// Check recent MapPoints
MapPointCulling();
// Triangulate new MapPoints
CreateNewMapPoints();
if (!CheckNewKeyFrames())
{
// Find more matches in neighbor keyframes and fuse point duplications
SearchInNeighbors();
}
mbAbortBA = false;
if (!CheckNewKeyFrames() && !stopRequested())
{
// Local BA
if (mpMap->KeyFramesInMap() > 2)
Optimizer::LocalBundleAdjustment(mpCurrentKeyFrame, &mbAbortBA, mpMap);
// Check redundant local Keyframes
KeyFrameCulling();
}
mpLoopCloser->InsertKeyFrame(mpCurrentKeyFrame);
}
else if (Stop())
{
// Safe area to stop
while (isStopped() && !CheckFinish())
{
usleep(3000);
}
if (CheckFinish())
break;
}
ResetIfRequested();
// Tracking will see that Local Mapping is busy
SetAcceptKeyFrames(true);
if (CheckFinish())
break;
usleep(3000);
}//while
SetFinish();
}
/// insert a key frame to local map, and stop BA when insert a key frame
///插入新的关键帧到LocalMapping,这个时候立马停止BA优化,等这帧
///处理好之后再进行优化
void LocalMapping::InsertKeyFrame(KeyFrame *pKF)
{
unique_lock<mutex> lock(mMutexNewKFs);
mlNewKeyFrames.push_back(pKF);
mbAbortBA = true;
}
///检测是否由新的关键帧
bool LocalMapping::CheckNewKeyFrames()
{
unique_lock<mutex> lock(mMutexNewKFs);
return (!mlNewKeyFrames.empty());
}
/// 1.Associate MapPoints to the new keyframe and update normal and descriptor
/// 2.Insert key frame into map
/**
* 1.取出最新的关键帧作为当前关键帧;
* 2.计算当前关键帧的Bow;
* 3.取出当前关键帧的所有特征点对应的地图点;
* 4.遍历所有地图点,给地图点添加新的能够观测到该地图点的关键帧;
* 5.更新Normal,平均的观测方向和深度信息;
* 6.更新描述子;
* 7.更新当前帧的共视图;
* 8.将当前帧添加到Map中.
*/
void LocalMapping::ProcessNewKeyFrame()
{
{
/// get latest NewKeyFrame
unique_lock<mutex> 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
/// get MapPoints associated to keypoints
const vector<MapPoint *> vpMapPointMatches = mpCurrentKeyFrame->GetMapPointMatches();
/// handle every map point, update it's normal, depth, observation, descriptor and so on
for (size_t i = 0; i < vpMapPointMatches.size(); i++)
{
MapPoint *pMP = vpMapPointMatches[i];
///is valid pointer
if (pMP)
{
/// is map point good
if (!pMP->isBad())
{
/// if current key frame not in key frame
if (!pMP->IsInKeyFrame(mpCurrentKeyFrame))
{
/// add current key frame to observation
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
mpMap->AddKeyFrame(mpCurrentKeyFrame);
}
/// delete some map point uncorrect
void LocalMapping::MapPointCulling()
{
// Check Recent Added MapPoints
list<MapPoint *>::iterator lit = mlpRecentAddedMapPoints.begin();
const unsigned long int nCurrentKFid = mpCurrentKeyFrame->mnId;
int nThObs;
if (mbMonocular)
nThObs = 2;
else
nThObs = 3;
const int cnThObs = nThObs;
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);
}
///1.curr key frame's id minus map point's First key frame's id large than 2, but
/// keyframe number observer this map point less than cnThObs
else if (((int)nCurrentKFid - (int)pMP->mnFirstKFid) >= 2 && pMP->Observations() <= cnThObs)
{
pMP->SetBadFlag();
lit = mlpRecentAddedMapPoints.erase(lit);
}
/// 1.have more than 3 KeyFrame observe the map point, but the map point still there
/// will not set bag flag, but erase from recent add Map Points queue
else if (((int)nCurrentKFid - (int)pMP->mnFirstKFid) >= 3)
lit = mlpRecentAddedMapPoints.erase(lit);
else
lit++;
}
}
///create new map points
void LocalMapping::CreateNewMapPoints()
{
// Retrieve neighbor keyframes in covisibility graph
int nn = 10;
if (mbMonocular)
nn = 20;
/// find the best nn number key frame in current frame's covisibility key frame
//找到最共视的nn帧关键帧
const vector<KeyFrame *> vpNeighKFs = mpCurrentKeyFrame->GetBestCovisibilityKeyFrames(nn);
ORBmatcher matcher(0.6, 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;
int nnew = 0;
// Search matches with epipolar restriction and triangulate
/// loop neighbody key frame
//遍历共视的关键帧,并且进行极限搜索,和三角化
for (size_t i = 0; i < vpNeighKFs.size(); i++)
{
/// if i > 0 and have new key frame, stop create map point
if (i > 0 && CheckNewKeyFrames())
return;
KeyFrame *pKF2 = vpNeighKFs[i];
// Check first that baseline is not too short
cv::Mat Ow2 = pKF2->GetCameraCenter();
cv::Mat vBaseline = Ow2 - Ow1;
const float baseline = cv::norm(vBaseline);
/// is stereo camera, two short distance between two key frame's center
/// do not generate map point
if (!mbMonocular)
{
if (baseline < pKF2->mb)
continue;
}
else
{
/// get scene median depth
const float medianDepthKF2 = pKF2->ComputeSceneMedianDepth(2);
/// ratio of base_line and median depth
const float ratioBaselineDepth = baseline / medianDepthKF2;
/// if ratio too small , then don't generate 3D point
/// if depth is large enougth ,then don't need generate 3D point
if (ratioBaselineDepth < 0.01)
continue;
}
// Compute Fundamental Matrix
//计算两帧之间的F矩阵
cv::Mat F12 = ComputeF12(mpCurrentKeyFrame, pKF2);
// Search matches that fullfil epipolar constraint
//利用极限搜索进行匹配
vector<pair<size_t, size_t>> vMatchedIndices;
matcher.SearchForTriangulation(mpCurrentKeyFrame, pKF2, F12, vMatchedIndices, false);
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 < nmatches; ikp++)
{
const int &idx1 = vMatchedIndices[ikp].first;
const int &idx2 = vMatchedIndices[ikp].second;
const cv::KeyPoint &kp1 = mpCurrentKeyFrame->mvKeysUn[idx1];
const float kp1_ur = mpCurrentKeyFrame->mvuRight[idx1];
bool bStereo1 = kp1_ur >= 0;
const cv::KeyPoint &kp2 = pKF2->mvKeysUn[idx2];
const float kp2_ur = pKF2->mvuRight[idx2];
bool bStereo2 = kp2_ur >= 0;
// Check parallax between rays
/// u1 = fx1*x1*invz1+cx1;
/// ray from camera center to pixel kp1 and ray from camera center to pixel kp2
cv::Mat xn1 = (cv::Mat_<float>(3, 1) << (kp1.pt.x - cx1) * invfx1, (kp1.pt.y - cy1) * invfy1, 1.0);
cv::Mat xn2 = (cv::Mat_<float>(3, 1) << (kp2.pt.x - cx2) * invfx2, (kp2.pt.y - cy2) * invfy2, 1.0);
/// translate xn1 from camera coordinate to world coordinate
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);
/// the 3D map point
cv::Mat x3D;
if (cosParallaxRays < cosParallaxStereo && cosParallaxRays > 0 && (bStereo1 || bStereo2 || cosParallaxRays < 0.9998))
{
// Linear Triangulation Method
//三角化特征点,这里跟单目初始化中的的三角化一样
cv::Mat A(4, 4, CV_32F);
A.row(0) = xn1.at<float>(0) * Tcw1.row(2) - Tcw1.row(0);
A.row(1) = xn1.at<float>(1) * Tcw1.row(2) - Tcw1.row(1);
A.row(2) = xn2.at<float>(0) * Tcw2.row(2) - Tcw2.row(0);
A.row(3) = xn2.at<float>(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<float>(3) == 0)
continue;
// Euclidean coordinates
x3D = x3D.rowRange(0, 3) / x3D.at<float>(3);
}
else if (bStereo1 && cosParallaxStereo1 < cosParallaxStereo2)
{
x3D = mpCurrentKeyFrame->UnprojectStereo(idx1);
}
else if (bStereo2 && cosParallaxStereo2 < cosParallaxStereo1)
{
x3D = pKF2->UnprojectStereo(idx2);
}
else
continue; //No stereo and very low parallax
cv::Mat x3Dt = x3D.t();
//Check triangulation in front of cameras
float z1 = Rcw1.row(2).dot(x3Dt) + tcw1.at<float>(2);
if (z1 <= 0)
continue;
float z2 = Rcw2.row(2).dot(x3Dt) + tcw2.at<float>(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<float>(0);
const float y1 = Rcw1.row(1).dot(x3Dt) + tcw1.at<float>(1);
const float invz1 = 1.0 / z1;
if (!bStereo1)
{
float u1 = fx1 * x1 * invz1 + cx1;
float v1 = fy1 * y1 * invz1 + cy1;
float errX1 = u1 - kp1.pt.x;
float errY1 = v1 - 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<float>(0);
const float y2 = Rcw2.row(1).dot(x3Dt) + tcw2.at<float>(1);
const float invz2 = 1.0 / z2;
if (!bStereo2)
{
float u2 = fx2 * x2 * invz2 + cx2;
float v2 = fy2 * y2 * invz2 + cy2;
float errX2 = u2 - kp2.pt.x;
float errY2 = v2 - 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;
//到光心的距离的比例
const float ratioDist = dist2 / dist1;
//特征点所在四叉树层的缩放比例
const float ratioOctave = mpCurrentKeyFrame->mvScaleFactors[kp1.octave] / pKF2->mvScaleFactors[kp2.octave];
/*if(fabs(ratioDist-ratioOctave)>ratioFactor)
continue;*/
//这里还是利用特征点所在的金字塔层次和特征点距离光心的距离的关系
//ratioDist < ratioOctave / ratioFactor ;
//ratioDist > ratioOctave * ratioFactor
if (ratioDist * ratioFactor < ratioOctave || ratioDist > ratioOctave * ratioFactor)
continue;
// Triangulation is succesfull
//三角化成功,创建新的地图点
MapPoint *pMP = new MapPoint(x3D, mpCurrentKeyFrame, mpMap);
pMP->AddObservation(mpCurrentKeyFrame, idx1);
pMP->AddObservation(pKF2, idx2);
mpCurrentKeyFrame->AddMapPoint(pMP, idx1);
pKF2->AddMapPoint(pMP, idx2);
pMP->ComputeDistinctiveDescriptors();
pMP->UpdateNormalAndDepth();
mpMap->AddMapPoint(pMP);
mlpRecentAddedMapPoints.push_back(pMP);
nnew++;
}
}//for
}
// Find more matches in neighbor keyframes and fuse point duplications
//在相邻的关键帧中找到更多的匹配,并融合重复的特征点
void LocalMapping::SearchInNeighbors()
{
// Retrieve neighbor keyframes
int nn = 10;
if (mbMonocular)
nn = 20;
/// retrieve best covisibility key frames
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;
/// KeyFrame is bad or already marked
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;
/// fush current key frame's map point with pKF frame's map point, replace duplicate map point
//将当前帧的地图点和关键帧的地图点进行融合,去除重复的地图点
matcher.Fuse(pKFi, vpMapPointMatches);
}
// Search matches by projection from target KFs in current KF
vector<MapPoint *> vpFuseCandidates;
vpFuseCandidates.reserve(vpTargetKFs.size() * vpMapPointMatches.size());
/// loop all surround KeyFrames,
///获取相邻关键帧的MapPoint
for (vector<KeyFrame *>::iterator vitKF = vpTargetKFs.begin(), vendKF = vpTargetKFs.end(); vitKF != vendKF; vitKF++)
{
/// KeyFrame
KeyFrame *pKFi = *vitKF;
/// get KeyFrame's all MapPoint
vector<MapPoint *> vpMapPointsKFi = pKFi->GetMapPointMatches();
/// loop all MapPoint
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);
}
}
//融合当前帧和相邻关键帧的MapPoint
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();
}
/// 利用公式:F = K^-T * t^ * R * K^-1计算F矩阵
cv::Mat LocalMapping::ComputeF12(KeyFrame *&pKF1, KeyFrame *&pKF2)
{
/// R1w means rotation from pKF1 frame coordinate to world coordinate
/// right multiple R1w means transform point from pKF1 frame coordinate to world coordinate
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->mK;
const cv::Mat &K2 = pKF2->mK;
return K1.t().inv() * t12x * R12 * K2.inv();
}
void LocalMapping::RequestStop()
{
unique_lock<mutex> lock(mMutexStop);
mbStopRequested = true;
unique_lock<mutex> lock2(mMutexNewKFs);
mbAbortBA = true;
}
bool LocalMapping::Stop()
{
unique_lock<mutex> lock(mMutexStop);
if (mbStopRequested && !mbNotStop)
{
mbStopped = true;
cout << "Local Mapping STOP" << endl;
return true;
}
return false;
}
bool LocalMapping::isStopped()
{
unique_lock<mutex> lock(mMutexStop);
return mbStopped;
}
bool LocalMapping::stopRequested()
{
unique_lock<mutex> lock(mMutexStop);
return mbStopRequested;
}
void LocalMapping::Release()
{
unique_lock<mutex> lock(mMutexStop);
unique_lock<mutex> lock2(mMutexFinish);
if (mbFinished)
return;
mbStopped = false;
mbStopRequested = false;
for (list<KeyFrame *>::iterator lit = mlNewKeyFrames.begin(), lend = mlNewKeyFrames.end(); lit != lend; lit++)
delete *lit;
mlNewKeyFrames.clear();
cout << "Local Mapping RELEASE" << endl;
}
bool LocalMapping::AcceptKeyFrames()
{
unique_lock<mutex> lock(mMutexAccept);
return mbAcceptKeyFrames;
}
void LocalMapping::SetAcceptKeyFrames(bool flag)
{
unique_lock<mutex> lock(mMutexAccept);
mbAcceptKeyFrames = flag;
}
bool LocalMapping::SetNotStop(bool flag)
{
unique_lock<mutex> lock(mMutexStop);
if (flag && mbStopped)
return false;
mbNotStop = flag;
return true;
}
void LocalMapping::InterruptBA()
{
mbAbortBA = true;
}
/**
* 剔除冗余的关键帧
* 当一个关键帧90%的MapPoint在至少其它三个关键帧中被观测到,
* 那么这个关键帧被视为冗余的,我们值考虑近点
*/
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
//遍历当前帧的共视帧
vector<KeyFrame *> vpLocalKeyFrames = mpCurrentKeyFrame->GetVectorCovisibleKeyFrames();
for (vector<KeyFrame *>::iterator vit = vpLocalKeyFrames.begin(), vend = vpLocalKeyFrames.end(); vit != vend; vit++)
{
KeyFrame *pKF = *vit;
if (pKF->mnId == 0)
continue;
//得到共视帧的地图点
const vector<MapPoint *> vpMapPoints = pKF->GetMapPointMatches();
int nObs = 3;
const int thObs = nObs;
int nRedundantObservations = 0;
//关键帧中好的地图点的数目
int nMPs = 0;
//遍历地图点
for (size_t i = 0, iend = vpMapPoints.size(); i < iend; i++)
{
MapPoint *pMP = vpMapPoints[i];
if (pMP)
{
if (!pMP->isBad())
{
if (!mbMonocular)
{
if (pKF->mvDepth[i] > pKF->mThDepth || pKF->mvDepth[i] < 0)
continue;
}
nMPs++;
//地图点的观测帧的数目大于3
if (pMP->Observations() > thObs)
{
//提取的特征点所在的四叉树的层级
const int &scaleLevel = pKF->mvKeysUn[i].octave;
const map<KeyFrame *, size_t> observations = pMP->GetObservations();
int nObs = 0;
//遍历获取地图点的观测帧
for (map<KeyFrame *, size_t>::const_iterator mit = observations.begin(), mend = observations.end(); mit != mend; mit++)
{
KeyFrame *pKFi = mit->first;
if (pKFi == pKF)
continue;
const int &scaleLeveli = pKFi->mvKeysUn[mit->second].octave;
//在低于scaleLevel + 1的缩放层级观测到该点
if (scaleLeveli <= scaleLevel + 1)
{
//观测到该点的计数+1
nObs++;
if (nObs >= thObs)
break;
}
}
//由至少其它三帧观测到该点, 冗余观测计数+1,意味这该MapPoint点可以在其它帧中被观测到.
if (nObs >= thObs)
{
nRedundantObservations++;
}
}//if
}//if
}//for
}//for
//如果有冗余备份观测帧的MapPoint的数目大于90%,那么删除该关键帧
if (nRedundantObservations > 0.9 * nMPs)
pKF->SetBadFlag();
}//for
}
cv::Mat LocalMapping::SkewSymmetricMatrix(const cv::Mat &v)
{
return (cv::Mat_<float>(3, 3) << 0, -v.at<float>(2), v.at<float>(1),
v.at<float>(2), 0, -v.at<float>(0),
-v.at<float>(1), v.at<float>(0), 0);
}
void LocalMapping::RequestReset()
{
{
unique_lock<mutex> lock(mMutexReset);
mbResetRequested = true;
}
while (1)
{
{
unique_lock<mutex> lock2(mMutexReset);
if (!mbResetRequested)
break;
}
usleep(3000);
}
}
void LocalMapping::ResetIfRequested()
{
unique_lock<mutex> lock(mMutexReset);
if (mbResetRequested)
{
mlNewKeyFrames.clear();
mlpRecentAddedMapPoints.clear();
mbResetRequested = false;
}
}
void LocalMapping::RequestFinish()
{
unique_lock<mutex> lock(mMutexFinish);
mbFinishRequested = true;
}
bool LocalMapping::CheckFinish()
{
unique_lock<mutex> lock(mMutexFinish);
return mbFinishRequested;
}
void LocalMapping::SetFinish()
{
unique_lock<mutex> lock(mMutexFinish);
mbFinished = true;
unique_lock<mutex> lock2(mMutexStop);
mbStopped = true;
}
bool LocalMapping::isFinished()
{
unique_lock<mutex> lock(mMutexFinish);
return mbFinished;
}
} // namespace ORB_SLAM2