系统将图片交给Tracking::GrabImageMonocular()
后,先将图片转化为灰度图,然后使用图片构建了一个Frame
。
注意系统在初始化的时候使用了不同的ORBextractor
来构建Frame
,是应为在初始化阶段的帧需要跟多的特征点
然后将进入了Track()
,Tracking的大部分功能将在这里实现
Tracking
执行了4个任务:
TrackLocalMap()
) 求得位姿估计 T 3 T_3 T3。这个步骤回答当前帧的特征点和map中的哪些mappoint匹配。class Tracking
{
public:
Tracking(System* pSys, ORBVocabulary* pVoc, FrameDrawer* pFrameDrawer, MapDrawer* pMapDrawer, Map* pMap,
KeyFrameDatabase* pKFDB, const string &strSettingPath, const int sensor);
// Preprocess the input and call Track(). Extract features and performs stereo matching.
cv::Mat GrabImageStereo(const cv::Mat &imRectLeft,const cv::Mat &imRectRight, const double ×tamp);
cv::Mat GrabImageRGBD(const cv::Mat &imRGB,const cv::Mat &imD, const double ×tamp);
cv::Mat GrabImageMonocular(const cv::Mat &im, const double ×tamp);
void SetLocalMapper(LocalMapping* pLocalMapper);
void SetLoopClosing(LoopClosing* pLoopClosing);
void SetViewer(Viewer* pViewer);
// Load new settings
// The focal lenght should be similar or scale prediction will fail when projecting points
// TODO: Modify MapPoint::PredictScale to take into account focal lenght
void ChangeCalibration(const string &strSettingPath);
// Use this function if you have deactivated local mapping and you only want to localize the camera.
void InformOnlyTracking(const bool &flag);
public:
// Tracking states
enum eTrackingState{
SYSTEM_NOT_READY=-1,
NO_IMAGES_YET=0,
NOT_INITIALIZED=1,
OK=2,
LOST=3
};
eTrackingState mState;
eTrackingState mLastProcessedState;
// Input sensor
int mSensor;
// Current Frame
Frame mCurrentFrame;
cv::Mat mImGray;
// Initialization Variables (Monocular)
//这个没有用到
std::vector<int> mvIniLastMatches;
//初始化时得到的特征点匹配,大小是mInitialFrame的特征点数量,其值是当前帧特征点序号
std::vector<int> mvIniMatches;
//mInitialFrame中待匹配的特征点的像素位置
std::vector<cv::Point2f> mvbPrevMatched;
//初始化时三角化投影成功的匹配点对应的3d点
std::vector<cv::Point3f> mvIniP3D;
//初始化的第一帧,初始化需要两帧,世界坐标系就是这帧的坐标系
Frame mInitialFrame;
// Lists used to recover the full camera trajectory at the end of the execution.
// Basically we store the reference keyframe for each frame and its relative transformation
list<cv::Mat> mlRelativeFramePoses;
list<KeyFrame*> mlpReferences;
list<double> mlFrameTimes;
list<bool> mlbLost;
// True if local mapping is deactivated and we are performing only localization
bool mbOnlyTracking;
void Reset();
protected:
// Main tracking function. It is independent of the input sensor.
//跟踪
void Track();
// Map initialization for stereo and RGB-D
void StereoInitialization();
// Map initialization for monocular
/**
* @brief 单目的地图初始化
*
* 并行地计算基础矩阵和单应性矩阵,选取其中一个模型,恢复出最开始两帧之间的相对姿态以及点云
* 得到初始两帧的匹配、相对运动、初始MapPoints
*/
void MonocularInitialization();
//单目模式下初始化后,开始建图
//将mInitialFrame和mCurrentFrame都设置为关键帧
//新建mappoint
//更新共视关系
void CreateInitialMapMonocular();
void CheckReplacedInLastFrame();
/**
* 将将上一帧的位姿作为当前帧mCurrentFrame的初始位姿;
* 匹配参考帧关键帧中有对应mappoint的特征点与当前帧特征点,通过dbow加速匹配;
* 以上一帧的位姿态为初始值,优化3D点重投影误差,得到更精确的位姿以及剔除错误的特征点匹配;
* @return 如果匹配数大于10,返回true
*/
bool TrackReferenceKeyFrame();
/**
* 更新mLastFrame
* 更新mlpTemporalPoints
*/
void UpdateLastFrame();
/**
* @brief 根据匀速度模型对上一帧mLastFrame的MapPoints与当前帧mCurrentFrame进行特征点跟踪匹配
*
* 1. 非单目情况,需要对上一帧产生一些新的MapPoints(临时)
* 2. 将上一帧的MapPoints投影到当前帧的图像平面上,在投影的位置进行区域匹配
* 3. 根据匹配优化当前帧的姿态
* 4. 根据姿态剔除误匹配
* @return 如果匹配数大于10,返回true
*/
bool TrackWithMotionModel();
//BOW搜索候选关键帧,PnP求解位姿
bool Relocalization();
//更新局部地图,即更新局部地图关键帧,局部地图mappoint
void UpdateLocalMap();
//将mvpLocalKeyFrames中的mappoint,添加到局部地图关键点mvpLocalMapPoints中
void UpdateLocalPoints();
/**
* 更新mpReferenceKF,mCurrentFrame.mpReferenceKF
* 更新局部地图关键帧mvpLocalKeyFrames
*/
void UpdateLocalKeyFrames();
/**
* @brief 对mvpLocalKeyFrames,mvpLocalMapPoints进行跟踪
*
* 1. 更新局部地图,包括局部关键帧和关键点
* 2. 以局部地图的mappoint为范围和当前帧进行特征匹配
* 3. 根据匹配对通过BA估计当前帧的姿态
* 4. 更新当前帧的MapPoints被观测程度,并统计跟踪局部地图的效果
* @return 根据跟踪局部地图的效果判断当前帧的跟踪成功与否,返回其判断结果
* @see V-D track Local Map
*/
bool TrackLocalMap();
//在局部地图的mappoint中查找在当前帧视野范围内的点,将视野范围内的点和当前帧的特征点进行投影匹配
void SearchLocalPoints();
//判断是否需要添加新的keyframe
bool NeedNewKeyFrame();
/**
* @brief 创建新的关键帧
*
* 对于非单目的情况,同时创建新的MapPoints
*/
void CreateNewKeyFrame();
// In case of performing only localization, this flag is true when there are no matches to
// points in the map. Still tracking will continue if there are enough matches with temporal points.
// In that case we are doing visual odometry. The system will try to do relocalization to recover
// "zero-drift" localization to the map.
//在OnlyTracking模式中使用
//true表明在上一帧中匹配到了足够多的mappoint
bool mbVO;
//Other Thread Pointers
LocalMapping* mpLocalMapper;
LoopClosing* mpLoopClosing;
//ORB
ORBextractor* mpORBextractorLeft, *mpORBextractorRight;
ORBextractor* mpIniORBextractor;
//BoW
ORBVocabulary* mpORBVocabulary;
KeyFrameDatabase* mpKeyFrameDB;
// Initalization (only for monocular)
Initializer* mpInitializer;
//Local Map
//参考关键帧
//在CreateNewKeyFrame()中,为当前帧
//在UpdateLocalKeyFrames()中,为当前帧共视程度最高的关键帧
KeyFrame* mpReferenceKF;
std::vector<KeyFrame*> mvpLocalKeyFrames;
//mvpLocalKeyFrames的所有关键帧的所有匹配的mappoint集合
std::vector<MapPoint*> mvpLocalMapPoints;
// System
System* mpSystem;
//Drawers
Viewer* mpViewer;
FrameDrawer* mpFrameDrawer;
MapDrawer* mpMapDrawer;
//Map
Map* mpMap;
//Calibration matrix
cv::Mat mK;
cv::Mat mDistCoef;
float mbf;
//New KeyFrame rules (according to fps)
int mMinFrames;
//
int mMaxFrames;
// Threshold close/far points
// Points seen as close by the stereo/RGBD sensor are considered reliable
// and inserted from just one frame. Far points requiere a match in two keyframes.
float mThDepth;
// For RGB-D inputs only. For some datasets (e.g. TUM) the depthmap values are scaled.
float mDepthMapFactor;
//Current matches in frame
//当前的匹配
int mnMatchesInliers;
//Last Frame, KeyFrame and Relocalisation Info
//最近新插入的keyframe
KeyFrame* mpLastKeyFrame;
// 记录最近的一帧
Frame mLastFrame;
//tracking上一次插入mpLastKeyFrame的Frame的ID
unsigned int mnLastKeyFrameId;
//上一次Relocalization()使用的Frame ID,最近一次重定位帧的ID
unsigned int mnLastRelocFrameId;
//Motion Model
cv::Mat mVelocity;
//Color order (true RGB, false BGR, ignored if grayscale)
bool mbRGB;
//在UpdateLastFrame()更新
list<MapPoint*> mlpTemporalPoints;
};
void Tracking:: Track()
{
// 如果图像复位过、或者第一次运行,则为NO_IMAGE_YET状态
if(mState==NO_IMAGES_YET)
{
mState = NOT_INITIALIZED;
}
mLastProcessedState=mState;
// Get Map Mutex -> Map cannot be changed
unique_lock<mutex> lock(mpMap->mMutexMapUpdate);
//如果tracking没有初始化,则初始化
if(mState==NOT_INITIALIZED)
{
if(mSensor==System::STEREO || mSensor==System::RGBD)
StereoInitialization();
else
MonocularInitialization();
mpFrameDrawer->Update(this);
if(mState!=OK)
return;
}
else
//tracking初始化成功后
{
// System is initialized. Track Frame.
// bOK为临时变量,bOK==true现在tracking状态正常,能够及时的反应现在tracking的状态
bool bOK;
// Initial camera pose estimation using motion model or relocalization (if tracking is lost)
// 用户可以通过在viewer中的开关menuLocalizationMode,控制是否ActivateLocalizationMode,并最终管控mbOnlyTracking是否为true
// mbOnlyTracking等于false表示正常VO模式(有地图更新),mbOnlyTracking等于true表示用户手动选择定位模式
if(!mbOnlyTracking)
{
// Local Mapping is activated. This is the normal behaviour, unless
// you explicitly activate the "only tracking" mode.
if(mState==OK)
{
// Local Mapping might have changed some MapPoints tracked in last frame
//lastframe中可以看到的mappoint替换为lastframe储存的备胎mappoint点mpReplaced,也就是更新mappoint
CheckReplacedInLastFrame();
// 运动模型是空的或刚完成重定位
if(mVelocity.empty() || mCurrentFrame.mnId<mnLastRelocFrameId+2)
{
/**
* 将参考帧关键帧的位姿作为当前帧的初始位姿进行跟踪;
* 匹配参考帧关键帧中有对应mappoint的特征点与当前帧特征点,通过dbow加速匹配;
* 优化3D点重投影误差,得到更精确的位姿以及剔除错误的特征点匹配;
* @return 如果匹配数大于10,返回true
*/
bOK = TrackReferenceKeyFrame();
}
else
{
bOK = TrackWithMotionModel();
if(!bOK)
bOK = TrackReferenceKeyFrame();
}
}
else
{
//BOW搜索候选关键帧,PnP求解位姿
bOK = Relocalization();
}
}
// 只进行跟踪tracking,局部地图不工作
else
{
// Localization Mode: Local Mapping is deactivated
// tracking跟丢了
if(mState==LOST)
{
bOK = Relocalization();
}
else
{
// mbVO是mbOnlyTracking为true时的才有的一个变量
// mbVO为false表示此帧匹配了很多的MapPoints,跟踪很正常,
// mbVO为true表明此帧匹配了很少的MapPoints,少于10个,要跪的节奏
if(!mbVO)
{
// In last frame we tracked enough MapPoints in the map
if(!mVelocity.empty())
{
bOK = TrackWithMotionModel();
}
else
{
bOK = TrackReferenceKeyFrame();
}
}
else
{
// In last frame we tracked mainly "visual odometry" points.
// We compute two camera poses, one from motion model and one doing relocalization.
// If relocalization is sucessfull we choose that solution, otherwise we retain
// the "visual odometry" solution.
//我们跟踪和重定位都计算,如果重定位成功就选择重定位来计算位姿
bool bOKMM = false;
bool bOKReloc = false;
vector<MapPoint*> vpMPsMM;
vector<bool> vbOutMM;
cv::Mat TcwMM;
//如果运动模型非空
if(!mVelocity.empty())
{
//使用运动模型进行跟踪
bOKMM = TrackWithMotionModel();
vpMPsMM = mCurrentFrame.mvpMapPoints;
vbOutMM = mCurrentFrame.mvbOutlier;
TcwMM = mCurrentFrame.mTcw.clone();
}
//使用重定位计算位姿
bOKReloc = Relocalization();
//跟踪成功,重定位失败
if(bOKMM && !bOKReloc)
{
mCurrentFrame.SetPose(TcwMM);
mCurrentFrame.mvpMapPoints = vpMPsMM;
mCurrentFrame.mvbOutlier = vbOutMM;
//确认mbVO==1
if(mbVO)
{
for(int i =0; i<mCurrentFrame.N; i++)
{
if(mCurrentFrame.mvpMapPoints[i] && !mCurrentFrame.mvbOutlier[i])
{
mCurrentFrame.mvpMapPoints[i]->IncreaseFound();
}
}
}
}
//如果重定位成功
else if(bOKReloc)
{
mbVO = false;
}
bOK = bOKReloc || bOKMM;
}
}
}
mCurrentFrame.mpReferenceKF = mpReferenceKF;
// If we have an initial estimation of the camera pose and matching. Track the local map.
if(!mbOnlyTracking)
{
if(bOK)
bOK = TrackLocalMap();
}
else
{
// mbVO true means that there are few matches to MapPoints in the map. We cannot retrieve
// a local map and therefore we do not perform TrackLocalMap(). Once the system relocalizes
// the camera we will use the local map again.
if(bOK && !mbVO)
bOK = TrackLocalMap();
}
if(bOK)
mState = OK;
else
mState=LOST;
// Update drawer
mpFrameDrawer->Update(this);
// If tracking were good, check if we insert a keyframe
if(bOK)
{
// Update motion model
//更新运动模型
if(!mLastFrame.mTcw.empty())
{
//更新恒速运动模型TrackWithMotionModel中的mVelocity
cv::Mat LastTwc = cv::Mat::eye(4,4,CV_32F);
mLastFrame.GetRotationInverse().copyTo(LastTwc.rowRange(0,3).colRange(0,3));
mLastFrame.GetCameraCenter().copyTo(LastTwc.rowRange(0,3).col(3));
mVelocity = mCurrentFrame.mTcw*LastTwc;
}
else
mVelocity = cv::Mat();
mpMapDrawer->SetCurrentCameraPose(mCurrentFrame.mTcw);
// Clean VO matches
// 清除UpdateLastFrame中为当前帧临时添加的MapPoints
for(int i=0; i<mCurrentFrame.N; i++)
{
MapPoint* pMP = mCurrentFrame.mvpMapPoints[i];
if(pMP)
if(pMP->Observations()<1)
{
mCurrentFrame.mvbOutlier[i] = false;
mCurrentFrame.mvpMapPoints[i]=static_cast<MapPoint*>(NULL);
}
}
// Delete temporal MapPoints
// 清除临时的MapPoints,这些MapPoints在TrackWithMotionModel的UpdateLastFrame函数里生成(仅双目和rgbd)
// 这里生成的仅仅是为了提高双目或rgbd摄像头的帧间跟踪效果,用完以后就扔了,没有添加到地图中
for(list<MapPoint*>::iterator lit = mlpTemporalPoints.begin(), lend = mlpTemporalPoints.end(); lit!=lend; lit++)
{
MapPoint* pMP = *lit;
delete pMP;
}
mlpTemporalPoints.clear();
// Check if we need to insert a new keyframe
//判断是否插入keyframe
if(NeedNewKeyFrame())
CreateNewKeyFrame();
// We allow points with high innovation (considererd outliers by the Huber Function)
// pass to the new keyframe, so that bundle adjustment will finally decide
// if they are outliers or not. We don't want next frame to estimate its position
// with those points so we discard them in the frame.
// 删除那些在bundle adjustment中检测为outlier的3D map点
for(int i=0; i<mCurrentFrame.N;i++)
{
if(mCurrentFrame.mvpMapPoints[i] && mCurrentFrame.mvbOutlier[i])
mCurrentFrame.mvpMapPoints[i]=static_cast<MapPoint*>(NULL);
}
}
// Reset if the camera get lost soon after initialization
//如果mState==LOST,且mpMap->KeyFramesInMap()<=5(说明刚刚初始化),则reset;
//如果mState==LOST,且mpMap->KeyFramesInMap()>5,则会在下一帧中执行bOK = Relocalization();
if(mState==LOST)
{
if(mpMap->KeyFramesInMap()<=5)
{
cout << "Track lost soon after initialisation, reseting..." << endl;
mpSystem->Reset();
return;
}
}
if(!mCurrentFrame.mpReferenceKF)
mCurrentFrame.mpReferenceKF = mpReferenceKF;
mLastFrame = Frame(mCurrentFrame);
}
// Store frame pose information to retrieve the complete camera trajectory afterwards.
if(!mCurrentFrame.mTcw.empty())
{
cv::Mat Tcr = mCurrentFrame.mTcw*mCurrentFrame.mpReferenceKF->GetPoseInverse();
mlRelativeFramePoses.push_back(Tcr);
mlpReferences.push_back(mpReferenceKF);
mlFrameTimes.push_back(mCurrentFrame.mTimeStamp);
mlbLost.push_back(mState==LOST);
}
else
{
// This can happen if tracking is lost
mlRelativeFramePoses.push_back(mlRelativeFramePoses.back());
mlpReferences.push_back(mlpReferences.back());
mlFrameTimes.push_back(mlFrameTimes.back());
mlbLost.push_back(mState==LOST);
}
}
// Map initialization for monocular
/**
* @brief 单目的地图初始化
*
* 并行地计算基础矩阵和单应性矩阵,选取其中一个模型,恢复出最开始两帧之间的相对姿态以及点云
* 得到初始两帧的匹配、相对运动、初始MapPoints
*/
void Tracking::MonocularInitialization()
{
// 如果单目初始器还没有被创建,则创建单目初始器
if(!mpInitializer)
{
// Set Reference Frame
//如果如果当前帧特征点数量大于100
if(mCurrentFrame.mvKeys.size()>100)
{
//设置mInitialFrame,和mLastFrame
mInitialFrame = Frame(mCurrentFrame);
mLastFrame = Frame(mCurrentFrame);
// mvbPrevMatched最大的情况就是所有特征点都被跟踪上
mvbPrevMatched.resize(mCurrentFrame.mvKeysUn.size());
for(size_t i=0; i<mCurrentFrame.mvKeysUn.size(); i++)
mvbPrevMatched[i]=mCurrentFrame.mvKeysUn[i].pt;
//确认mpInitializer指向NULL
if(mpInitializer)
delete mpInitializer;
mpInitializer = new Initializer(mCurrentFrame,1.0,200);
//将mvIniMatches全部初始化为-1
fill(mvIniMatches.begin(),mvIniMatches.end(),-1);
return;
}
}
//如果指针mpInitializer没有指向NULL,也就是说我们在之前已经通过mInitialFrame新建过一个Initializer对象,并使 mpInitializer指向它了
else
{
// Try to initialize
//尝试初始化
//如果当前帧特征点数量<=100
if((int)mCurrentFrame.mvKeys.size()<=100)
{
//删除mpInitializer指针并指向NULL
delete mpInitializer;
mpInitializer = static_cast<Initializer*>(NULL);
fill(mvIniMatches.begin(),mvIniMatches.end(),-1);
return;
}
// Find correspondences
//新建一个ORBmatcher对象
ORBmatcher matcher(0.9,true);
//寻找特征点匹配
int nmatches = matcher.SearchForInitialization(mInitialFrame,mCurrentFrame,mvbPrevMatched,mvIniMatches,100);
// Check if there are enough correspondences
//如果匹配的点过少,则删除当前的初始化器
if(nmatches<100)
{
delete mpInitializer;
mpInitializer = static_cast<Initializer*>(NULL);
return;
}
//到这里说明初始化条件已经成熟
//开始要计算位姿R,t了!!
cv::Mat Rcw; // Current Camera Rotation
cv::Mat tcw; // Current Camera Translation
//初始化成功后,匹配点中三角化投影成功的情况
vector<bool> vbTriangulated; // Triangulated Correspondences (mvIniMatches)
// 通过H模型或F模型进行单目初始化,得到两帧间相对运动、初始MapPoints
if(mpInitializer->Initialize(mCurrentFrame, mvIniMatches, Rcw, tcw, mvIniP3D, vbTriangulated))
{
//ReconstructH,或者ReconstructF中解出RT后,会有一些点不能三角化重投影成功。
//在根据vbTriangulated中特征点三角化投影成功的情况,去除一些匹配点
for(size_t i=0, iend=mvIniMatches.size(); i<iend;i++)
{
if(mvIniMatches[i]>=0 && !vbTriangulated[i])
{
mvIniMatches[i]=-1;
nmatches--;
}
}
// Set Frame Poses
//初始化mInitialFrame的位姿
//将mInitialFrame位姿设置为世界坐标
mInitialFrame.SetPose(cv::Mat::eye(4,4,CV_32F));
cv::Mat Tcw = cv::Mat::eye(4,4,CV_32F);
Rcw.copyTo(Tcw.rowRange(0,3).colRange(0,3));
tcw.copyTo(Tcw.rowRange(0,3).col(3));
//将mpInitializer->Initialize算出的R和t拷贝到当前帧mCurrentFrame的位姿
mCurrentFrame.SetPose(Tcw);
CreateInitialMapMonocular();
}
}
}
//单目模式下初始化后,开始建图
//将mInitialFrame和mCurrentFrame都设置为关键帧
//新建mappoint
//更新共视关系
void Tracking::CreateInitialMapMonocular()
{
// Create KeyFrames
KeyFrame* pKFini = new KeyFrame(mInitialFrame,mpMap,mpKeyFrameDB);
KeyFrame* pKFcur = new KeyFrame(mCurrentFrame,mpMap,mpKeyFrameDB);
//计算关键帧的词袋bow和featurevector
pKFini->ComputeBoW();
pKFcur->ComputeBoW();
// Insert KFs in the map
mpMap->AddKeyFrame(pKFini);
mpMap->AddKeyFrame(pKFcur);
// Create MapPoints and asscoiate to keyframes
//遍历每一个初始化时得到的特征点匹配,将三角化重投影成功的特征点转化为mappoint
for(size_t i=0; i<mvIniMatches.size();i++)
{
if(mvIniMatches[i]<0)
continue;
//Create MapPoint.
cv::Mat worldPos(mvIniP3D[i]);
//新建mappoint对象,注意mappoint的参考帧是pKFcur
MapPoint* pMP = new MapPoint(worldPos,pKFcur,mpMap);
//给关键帧添加mappoint,让keyframe知道自己可以看到哪些mappoint
pKFini->AddMapPoint(pMP,i);
pKFcur->AddMapPoint(pMP,mvIniMatches[i]);
//让pMP知道自己可以被pKFini,pKFcur看到
pMP->AddObservation(pKFini,i);
pMP->AddObservation(pKFcur,mvIniMatches[i]);
//找出最能代表此mappoint的描述子
pMP->ComputeDistinctiveDescriptors();
//更新此mappoint参考帧光心到mappoint平均观测方向以及观测距离范围
pMP->UpdateNormalAndDepth();
//Fill Current Frame structure
//更新当前帧Frame能看到哪些mappoint
mCurrentFrame.mvpMapPoints[mvIniMatches[i]] = pMP;
//标记当前帧的特征点不是是Outlier
mCurrentFrame.mvbOutlier[mvIniMatches[i]] = false;
//Add to Map
//向map添加mappoint
mpMap->AddMapPoint(pMP);
}
// Update Connections
//更新共视图Covisibility graph,essential graph和spanningtree
pKFini->UpdateConnections();
pKFcur->UpdateConnections();
// Bundle Adjustment
cout << "New Map created with " << mpMap->MapPointsInMap() << " points" << endl;
//进行一次全局BA
Optimizer::GlobalBundleAdjustemnt(mpMap,20);
// Set median depth to 1
//返回mappoint集合在此帧的深度的中位数
// 将MapPoints的中值深度归一化到1,并归一化两帧之间变换
// 评估关键帧场景深度,q=2表示中值
float medianDepth = pKFini->ComputeSceneMedianDepth(2);
//
float invMedianDepth = 1.0f/medianDepth;
if(medianDepth<0 || pKFcur->TrackedMapPoints(1)<100)
{
cout << "Wrong initialization, reseting..." << endl;
Reset();
return;
}
// Scale initial baseline
cv::Mat Tc2w = pKFcur->GetPose();
// 利用invMedianDepth将z归一化到1
Tc2w.col(3).rowRange(0,3) = Tc2w.col(3).rowRange(0,3)*invMedianDepth;
pKFcur->SetPose(Tc2w);
// Scale points
// 把3D点的尺度也归一化到1
vector<MapPoint*> vpAllMapPoints = pKFini->GetMapPointMatches();
for(size_t iMP=0; iMP<vpAllMapPoints.size(); iMP++)
{
if(vpAllMapPoints[iMP])
{
MapPoint* pMP = vpAllMapPoints[iMP];
pMP->SetWorldPos(pMP->GetWorldPos()*invMedianDepth);
}
}
//向mpLocalMapper插入关键帧pKFini,pKFcur
mpLocalMapper->InsertKeyFrame(pKFini);
mpLocalMapper->InsertKeyFrame(pKFcur);
mCurrentFrame.SetPose(pKFcur->GetPose());
mnLastKeyFrameId=mCurrentFrame.mnId;
mpLastKeyFrame = pKFcur;
mvpLocalKeyFrames.push_back(pKFcur);
mvpLocalKeyFrames.push_back(pKFini);
mvpLocalMapPoints=mpMap->GetAllMapPoints();
mpReferenceKF = pKFcur;
mCurrentFrame.mpReferenceKF = pKFcur;
mLastFrame = Frame(mCurrentFrame);
mpMap->SetReferenceMapPoints(mvpLocalMapPoints);
mpMapDrawer->SetCurrentCameraPose(pKFcur->GetPose());
mpMap->mvpKeyFrameOrigins.push_back(pKFini);
mState=OK;
}
/**
* @brief 根据匀速度模型对上一帧mLastFrame的MapPoints与当前帧mCurrentFrame进行特征点跟踪匹配
*
* 1. 非单目情况,需要对上一帧产生一些新的MapPoints(临时)
* 2. 将上一帧的MapPoints投影到当前帧的图像平面上,在投影的位置进行区域匹配
* 3. 根据匹配优化当前帧的姿态
* 4. 根据姿态剔除误匹配
* @return 如果匹配数大于10,返回true
*/
bool Tracking::TrackWithMotionModel()
{
ORBmatcher matcher(0.9,true);
// Update last frame pose according to its reference keyframe
// Create "visual odometry" points if in Localization Mode
// 对于双目或rgbd摄像头,根据深度值为上一关键帧生成新的MapPoints
// (跟踪过程中需要将当前帧与上一帧进行特征点匹配,将上一帧的MapPoints投影到当前帧可以缩小匹配范围)
// 在跟踪过程中,去除outlier的MapPoint,如果不及时增加MapPoint会逐渐减少
// 这个函数的功能就是补充增加RGBD和双目相机上一帧的MapPoints数
UpdateLastFrame();
//根据Const Velocity Model(认为这两帧之间的相对运动和之前两帧间相对运动相同)估计当前帧的粗略位姿
mCurrentFrame.SetPose(mVelocity*mLastFrame.mTcw);
fill(mCurrentFrame.mvpMapPoints.begin(),mCurrentFrame.mvpMapPoints.end(),static_cast<MapPoint*>(NULL));
// Project points seen in previous frame
int th;
if(mSensor!=System::STEREO)
th=15;
else
th=7;
//对上一帧的MapPoints进行跟踪,看上一帧能看到的mappoint对应的当前帧哪些特征点
// 根据上一帧特征点对应的3D点投影的位置缩小特征点匹配范围
int nmatches = matcher.SearchByProjection(mCurrentFrame,mLastFrame,th,mSensor==System::MONOCULAR);
// If few matches, uses a wider window search
//匹配数量太少,扩大特征匹配搜索框重新进行mappoint跟踪
if(nmatches<20)
{
fill(mCurrentFrame.mvpMapPoints.begin(),mCurrentFrame.mvpMapPoints.end(),static_cast<MapPoint*>(NULL));
nmatches = matcher.SearchByProjection(mCurrentFrame,mLastFrame,2*th,mSensor==System::MONOCULAR);
}
if(nmatches<20)
return false;
// Optimize frame pose with all matches
// 优化位姿
Optimizer::PoseOptimization(&mCurrentFrame);
int nmatchesMap = 0;
// Discard outliers
//上一步的位姿优化更新了mCurrentFrame的outlier,需要将mCurrentFrame的mvpMapPoints更新
for(int i =0; i<mCurrentFrame.N; i++)
{
if(mCurrentFrame.mvpMapPoints[i])
{
if(mCurrentFrame.mvbOutlier[i])
{
MapPoint* pMP = mCurrentFrame.mvpMapPoints[i];
mCurrentFrame.mvpMapPoints[i]=static_cast<MapPoint*>(NULL);
mCurrentFrame.mvbOutlier[i]=false;
pMP->mbTrackInView = false;
pMP->mnLastFrameSeen = mCurrentFrame.mnId;
nmatches--;
}
//如果当前帧可以看到的mappoint同时能被其他keyframe看到
else if(mCurrentFrame.mvpMapPoints[i]->Observations()>0)
nmatchesMap++;
}
}
if(mbOnlyTracking)
{
mbVO = nmatchesMap<10;
return nmatches>20;
}
return nmatchesMap>=10;
}
bool Tracking::TrackLocalMap()
{
// We have an estimation of the camera pose and some map points tracked in the frame.
// We retrieve the local map and try to find matches to points in the local map.
//更新局部地图,即更新局部地图关键帧,局部地图mappoint
UpdateLocalMap();
//在局部地图的mappoint中查找在当前帧视野范围内的点,将视野范围内的点和当前帧的特征点进行投影匹配
SearchLocalPoints();
// 在这个函数之前,在Relocalization、TrackReferenceKeyFrame、TrackWithMotionModel中都有位姿优化,
//更新局部所有MapPoints后对位姿再次优化
// Optimize Pose
Optimizer::PoseOptimization(&mCurrentFrame);
mnMatchesInliers = 0;
// Update MapPoints Statistics
// 更新当前帧的MapPoints被观测程度,并统计跟踪局部地图的效果
for(int i=0; i<mCurrentFrame.N; i++)
{
if(mCurrentFrame.mvpMapPoints[i])
{
if(!mCurrentFrame.mvbOutlier[i])
{
//标记该mappoint点被当前帧观测
mCurrentFrame.mvpMapPoints[i]->IncreaseFound();
if(!mbOnlyTracking)
{
if(mCurrentFrame.mvpMapPoints[i]->Observations()>0)
mnMatchesInliers++;
}
else
mnMatchesInliers++;
}
else if(mSensor==System::STEREO)
mCurrentFrame.mvpMapPoints[i] = static_cast<MapPoint*>(NULL);
}
}
// Decide if the tracking was succesful
// More restrictive if there was a relocalization recently
// 决定是否跟踪成功
//如果当前帧和上一次重定位太近
//或者当前帧特征点与mappoint的匹配数太少
if(mCurrentFrame.mnId<mnLastRelocFrameId+mMaxFrames && mnMatchesInliers<50)
return false;
if(mnMatchesInliers<30)
return false;
else
return true;
}
/**
* 将将上一帧的位姿作为当前帧mCurrentFrame的初始位姿;
* 匹配参考帧关键帧中有对应mappoint的特征点与当前帧特征点,通过dbow加速匹配;
* 以上一帧的位姿态为初始值,优化3D点重投影误差,得到更精确的位姿以及剔除错误的特征点匹配;
* @return 如果匹配数大于10,返回true
*/
bool Tracking::TrackReferenceKeyFrame()
{
// Compute Bag of Words vector
//计算当前帧的Bow向量
mCurrentFrame.ComputeBoW();
// We perform first an ORB matching with the reference keyframe
// If enough matches are found we setup a PnP solver
ORBmatcher matcher(0.7,true);
vector<MapPoint*> vpMapPointMatches;
//通过特征点的BoW加速匹配当前帧与参考关键帧之间的特征点
int nmatches = matcher.SearchByBoW(mpReferenceKF,mCurrentFrame,vpMapPointMatches);
//匹配数小于15,表示跟踪失败
if(nmatches<15)
return false;
mCurrentFrame.mvpMapPoints = vpMapPointMatches;
//将上一帧的位姿作为当前帧位姿的初始值,在PoseOptimization可以收敛快一些
mCurrentFrame.SetPose(mLastFrame.mTcw);
//通过优化3D-2D的重投影误差来获得位姿
Optimizer::PoseOptimization(&mCurrentFrame);
// Discard outliers
int nmatchesMap = 0;
//剔除优化后的outlier匹配点
//遍历mCurrentFrame每个特征点
for(int i =0; i<mCurrentFrame.N; i++)
{
//如果这个特征点与相对应的mappoint
if(mCurrentFrame.mvpMapPoints[i])
{
//如果这个mappoint在上次优化中被标记为outlier,则剔除
if(mCurrentFrame.mvbOutlier[i])
{
MapPoint* pMP = mCurrentFrame.mvpMapPoints[i];
mCurrentFrame.mvpMapPoints[i]=static_cast<MapPoint*>(NULL);
mCurrentFrame.mvbOutlier[i]=false;
pMP->mbTrackInView = false;
pMP->mnLastFrameSeen = mCurrentFrame.mnId;
nmatches--;
}
else if(mCurrentFrame.mvpMapPoints[i]->Observations()>0)
nmatchesMap++;
}
}
return nmatchesMap>=10;
}
bool Tracking::Relocalization()
{
// Compute Bag of Words Vector
mCurrentFrame.ComputeBoW();
// Relocalization is performed when tracking is lost
// Track Lost: Query KeyFrame Database for keyframe candidates for relocalisation
//找到与当前帧相似F的候选关键帧
vector<KeyFrame*> vpCandidateKFs = mpKeyFrameDB->DetectRelocalizationCandidates(&mCurrentFrame);
//如果候选关键帧为空,则返回Relocalization失败
if(vpCandidateKFs.empty())
return false;
const int nKFs = vpCandidateKFs.size();
// We perform first an ORB matching with each candidate
// If enough matches are found we setup a PnP solver
ORBmatcher matcher(0.75,true);
vector<PnPsolver*> vpPnPsolvers;
vpPnPsolvers.resize(nKFs);
//表示各个候选帧的mappoint与和当前帧特征点的匹配
//现在你想把mCurrentFrame的特征点和mappoint进行匹配,有个便捷的方法就是,
//让mCurrentFrame特征点和候选关键帧的特征点进行匹配,然后我们是知道候选关键帧特征点与mappoint的匹配的
//这样就能够将mCurrentFrame特征点和mappoint匹配起来了,相当于通过和候选关键帧这个桥梁匹配上了mappoint
//vvpMapPointMatches[i][j]就表示mCurrentFrame的第j个特征点如果是经由第i个候选关键帧匹配mappoint,是哪个mappoint
vector<vector<MapPoint*> > vvpMapPointMatches;
vvpMapPointMatches.resize(nKFs);
//
vector<bool> vbDiscarded;
vbDiscarded.resize(nKFs);
int nCandidates=0;
//候选帧和当前帧进行特征匹配,剔除匹配数量少的候选关键帧
//为未被剔除的关键帧就新建PnPsolver,准备在后面进行epnp
for(int i=0; i<nKFs; i++)
{
//候选帧
KeyFrame* pKF = vpCandidateKFs[i];
if(pKF->isBad())
vbDiscarded[i] = true;
else
{
//mCurrentFrame与候选关键帧进行特征点匹配
int nmatches = matcher.SearchByBoW(pKF,mCurrentFrame,vvpMapPointMatches[i]);
if(nmatches<15)
{
vbDiscarded[i] = true;
continue;
}
else
{
PnPsolver* pSolver = new PnPsolver(mCurrentFrame,vvpMapPointMatches[i]);
pSolver->SetRansacParameters(0.99,10,300,4,0.5,5.991);
vpPnPsolvers[i] = pSolver;
nCandidates++;
}
}
}
// Alternatively perform some iterations of P4P RANSAC
// Until we found a camera pose supported by enough inliers
bool bMatch = false;
ORBmatcher matcher2(0.9,true);
//大概步骤是这样的,小循环for不断的遍历剩下的nCandidates个的候选帧,这些候选帧对应有各自的PnPsolvers
//第i次for循环所对应的vpPnPsolvers[i]就会执行5次RANSAC循环求解出5个位姿。
//通过计算5个位姿对应的匹配点的inliner数量来判断位姿的好坏。如果这5个位姿比记录中的最好位姿更好,更新最好位姿以及对应的匹配点哪些点是inliner
//如果最好的那个位姿inliner超过阈值,或者vpPnPsolvers[i]RANSAC累计迭代次数超过阈值,都会把位姿拷贝给Tcw。否则Tcw为空
//如果Tcw为空,那么就循环计算下一个vpPnPsolvers[i+1]
//通过5次RANSAC求解位姿后,如果Tcw不为空,这继续判断它是否和当前帧匹配。
while(nCandidates>0 && !bMatch)
{
//遍历候选帧
for(int i=0; i<nKFs; i++)
{
if(vbDiscarded[i])
continue;
// Perform 5 Ransac Iterations
//此次RANSAC会计算出一个位姿,在这个位姿下,mCurrentFrame中的特征点哪些是有mappoint匹配的,也就是哪些是inliner
//vbInliers大小是mCurrentFrame中的特征点数量大小
vector<bool> vbInliers;
//vbInliers大小
int nInliers;
bool bNoMore;
PnPsolver* pSolver = vpPnPsolvers[i];
//通过EPnP算法估计姿态,有5次RANSAC循环
cv::Mat Tcw = pSolver->iterate(5,bNoMore,vbInliers,nInliers);
// If Ransac reachs max. iterations discard keyframe
//如果RANSAC循环达到了最大
if(bNoMore)
{
vbDiscarded[i]=true;
nCandidates--;
//认真的虎注释:这里是不是应该加一个continue?
}
// If a Camera Pose is computed, optimize
//相机姿态算出来有两种情况,一种是在RANSAC累计迭代次数没有达到mRansacMaxIts之前,找到了一个复合要求的位姿
//另一种情况是RANSAC累计迭代次数到达了最大mRansacMaxIts
//如果相机姿态已经算出来了,优化它
if(!Tcw.empty())
{
Tcw.copyTo(mCurrentFrame.mTcw);
set<MapPoint*> sFound;
//np为mCurrentFrame的特征点数量
const int np = vbInliers.size();
//根据vbInliers更新mCurrentFrame.mvpMapPoints,也就是根据vbInliers更新mCurrentFrame的特征点与哪些mappoint匹配
//并记下当前mCurrentFrame与哪些mappoint匹配到sFound,以便后面快速查询
for(int j=0; j<np; j++)
{
if(vbInliers[j])
{
mCurrentFrame.mvpMapPoints[j]=vvpMapPointMatches[i][j];
sFound.insert(vvpMapPointMatches[i][j]);
}
else
mCurrentFrame.mvpMapPoints[j]=NULL;
}
//BA优化位姿
int nGood = Optimizer::PoseOptimization(&mCurrentFrame);
if(nGood<10)
continue;
//剔除PoseOptimization算出的mvbOutlier
for(int io =0; io<mCurrentFrame.N; io++)
if(mCurrentFrame.mvbOutlier[io])
mCurrentFrame.mvpMapPoints[io]=static_cast<MapPoint*>(NULL);
// If few inliers, search by projection in a coarse window and optimize again
// 如果内点较少
if(nGood<50)
{
// mCurrentFrame中特征点已经匹配好一些mappoint在sFound中,如果内点较少,mCurrentFrame想要更多的mappoint匹配
//于是通过matcher2.SearchByProjection函数将vpCandidateKFs[i]的mappoint悉数投影到CurrentFrame再就近搜索特征点进行匹配
//mCurrentFrame返回得到通过此函数匹配到的新mappoint的个数
int nadditional =matcher2.SearchByProjection(mCurrentFrame,vpCandidateKFs[i],sFound,10,100);
//如果目前mCurrentFrame匹配到的mappoint个数超过50
if(nadditional+nGood>=50)
{
//优化位姿,返回(nadditional+nGood)有多少点是inliner
nGood = Optimizer::PoseOptimization(&mCurrentFrame);
// If many inliers but still not enough, search by projection again in a narrower window
// the camera has been already optimized with many points
//如果nGood不够多,那缩小搜索框重复再匹配一次
if(nGood>30 && nGood<50)
{
//更新sFound,也就是目前mCurrentFrame与哪些mappoint匹配
sFound.clear();
for(int ip =0; ip<mCurrentFrame.N; ip++)
if(mCurrentFrame.mvpMapPoints[ip])
sFound.insert(mCurrentFrame.mvpMapPoints[ip]);
//缩小搜索框重复再匹配一次,返回这个新得到的匹配数
nadditional =matcher2.SearchByProjection(mCurrentFrame,vpCandidateKFs[i],sFound,3,64);
// Final optimization
//如果目前mCurrentFrame匹配到的mappoint个数超过20
if(nGood+nadditional>=50)
{
//位姿优化,可能又会有些匹配消失
nGood = Optimizer::PoseOptimization(&mCurrentFrame);
//将刚才位姿优化得到的outliner匹配更新
for(int io =0; io<mCurrentFrame.N; io++)
if(mCurrentFrame.mvbOutlier[io])
mCurrentFrame.mvpMapPoints[io]=NULL;
}
}
}
}
// If the pose is supported by enough inliers stop ransacs and continue
if(nGood>=50)
{
bMatch = true;
break;
}
}
}
}
if(!bMatch)
{
return false;
}
else
{
mnLastRelocFrameId = mCurrentFrame.mnId;
return true;
}
}
将mvpLocalKeyFrames中的mappoint,添加到局部地图关键点mvpLocalMapPoints中
void Tracking::UpdateLocalPoints()
{
//清空局部地图关键点
mvpLocalMapPoints.clear();
for(vector<KeyFrame*>::const_iterator itKF=mvpLocalKeyFrames.begin(), itEndKF=mvpLocalKeyFrames.end(); itKF!=itEndKF; itKF++)
{
KeyFrame* pKF = *itKF;
const vector<MapPoint*> vpMPs = pKF->GetMapPointMatches();
for(vector<MapPoint*>::const_iterator itMP=vpMPs.begin(), itEndMP=vpMPs.end(); itMP!=itEndMP; itMP++)
{
MapPoint* pMP = *itMP;
if(!pMP)
continue;
// mnTrackReferenceForFrame防止重复添加局部MapPoint
if(pMP->mnTrackReferenceForFrame==mCurrentFrame.mnId)
continue;
if(!pMP->isBad())
{
mvpLocalMapPoints.push_back(pMP);
pMP->mnTrackReferenceForFrame=mCurrentFrame.mnId;
}
}
}
}
/**
* 更新mpReferenceKF,mCurrentFrame.mpReferenceKF
* 更新局部地图关键帧mvpLocalKeyFrames
*/
void Tracking::UpdateLocalKeyFrames()
{
// Each map point vote for the keyframes in which it has been observed
//遍历当前帧的mappoint,将所有能观测到这些mappoint的keyframe,及其可以观测的这些mappoint数量存入keyframeCounter
map<KeyFrame*,int> keyframeCounter;
for(int i=0; i<mCurrentFrame.N; i++)
{
if(mCurrentFrame.mvpMapPoints[i])
{
MapPoint* pMP = mCurrentFrame.mvpMapPoints[i];
if(!pMP->isBad())
{
const map<KeyFrame*,size_t> observations = pMP->GetObservations();
for(map<KeyFrame*,size_t>::const_iterator it=observations.begin(), itend=observations.end(); it!=itend; it++)
keyframeCounter[it->first]++;
}
else
{
mCurrentFrame.mvpMapPoints[i]=NULL;
}
}
}
if(keyframeCounter.empty())
return;
int max=0;
KeyFrame* pKFmax= static_cast<KeyFrame*>(NULL);
// 先清空局部地图关键帧
mvpLocalKeyFrames.clear();
mvpLocalKeyFrames.reserve(3*keyframeCounter.size());
// All keyframes that observe a map point are included in the local map. Also check which keyframe shares most points
//向mvpLocalKeyFrames添加能观测到当前帧MapPoints的关键帧
for(map<KeyFrame*,int>::const_iterator it=keyframeCounter.begin(), itEnd=keyframeCounter.end(); it!=itEnd; it++)
{
KeyFrame* pKF = it->first;
if(pKF->isBad())
continue;
//更新max,pKFmax,以寻找能看到最多mappoint的keyframe
if(it->second>max)
{
max=it->second;
pKFmax=pKF;
}
mvpLocalKeyFrames.push_back(it->first);
// mnTrackReferenceForFrame防止重复添加局部地图关键帧
pKF->mnTrackReferenceForFrame = mCurrentFrame.mnId;
}
// Include also some not-already-included keyframes that are neighbors to already-included keyframes
//遍历mvpLocalKeyFrames,以向mvpLocalKeyFrames添加更多的关键帧。有三种途径:
//1.取出此关键帧itKF在Covisibilitygraph中共视程度最高的10个关键帧;
//2.取出此关键帧itKF在Spanning tree中的子节点;
//3.取出此关键帧itKF在Spanning tree中的父节点;
for(vector<KeyFrame*>::const_iterator itKF=mvpLocalKeyFrames.begin(), itEndKF=mvpLocalKeyFrames.end(); itKF!=itEndKF; itKF++)
{
// Limit the number of keyframes
if(mvpLocalKeyFrames.size()>80)
break;
KeyFrame* pKF = *itKF;
//1.取出此关键帧itKF在essential graph中共视程度最高的10个关键帧
const vector<KeyFrame*> vNeighs = pKF->GetBestCovisibilityKeyFrames(10);
for(vector<KeyFrame*>::const_iterator itNeighKF=vNeighs.begin(), itEndNeighKF=vNeighs.end(); itNeighKF!=itEndNeighKF; itNeighKF++)
{
KeyFrame* pNeighKF = *itNeighKF;
if(!pNeighKF->isBad())
{
if(pNeighKF->mnTrackReferenceForFrame!=mCurrentFrame.mnId)
{
mvpLocalKeyFrames.push_back(pNeighKF);
pNeighKF->mnTrackReferenceForFrame=mCurrentFrame.mnId;
break;
}
}
}
//2.取出此关键帧itKF在Spanning tree中的子节点
//Spanning tree的节点为关键帧,共视程度最高的那个关键帧设置为节点在Spanning Tree中的父节点
const set<KeyFrame*> spChilds = pKF->GetChilds();
for(set<KeyFrame*>::const_iterator sit=spChilds.begin(), send=spChilds.end(); sit!=send; sit++)
{
KeyFrame* pChildKF = *sit;
if(!pChildKF->isBad())
{
if(pChildKF->mnTrackReferenceForFrame!=mCurrentFrame.mnId)
{
mvpLocalKeyFrames.push_back(pChildKF);
pChildKF->mnTrackReferenceForFrame=mCurrentFrame.mnId;
break;
}
}
}
//3.取出此关键帧itKF在Spanning tree中的父节点
KeyFrame* pParent = pKF->GetParent();
if(pParent)
{
if(pParent->mnTrackReferenceForFrame!=mCurrentFrame.mnId)
{
mvpLocalKeyFrames.push_back(pParent);
pParent->mnTrackReferenceForFrame=mCurrentFrame.mnId;
break;
}
}
}
if(pKFmax)
{
//更新参考关键帧为有共视的mappoint关键帧共视程度最高(共视的mappoint数量最多)的关键帧
mpReferenceKF = pKFmax;
mCurrentFrame.mpReferenceKF = mpReferenceKF;
}
}
/**
* @brief 对mvpLocalKeyFrames,mvpLocalMapPoints进行跟踪
*
* 1. 更新局部地图,包括局部关键帧和关键点
* 2. 以局部地图的mappoint为范围和当前帧进行特征匹配
* 3. 根据匹配对通过BA估计当前帧的姿态
* 4. 更新当前帧的MapPoints被观测程度,并统计跟踪局部地图的效果
* @return 根据跟踪局部地图的效果判断当前帧的跟踪成功与否,返回其判断结果
* @see V-D track Local Map
*/
bool Tracking::TrackLocalMap()
{
// We have an estimation of the camera pose and some map points tracked in the frame.
// We retrieve the local map and try to find matches to points in the local map.
//更新局部地图,即更新局部地图关键帧,局部地图mappoint
UpdateLocalMap();
//在局部地图的mappoint中查找在当前帧视野范围内的点,将视野范围内的点和当前帧的特征点进行投影匹配
SearchLocalPoints();
// 在这个函数之前,在Relocalization、TrackReferenceKeyFrame、TrackWithMotionModel中都有位姿优化,
//更新局部所有MapPoints后对位姿再次优化
// Optimize Pose
Optimizer::PoseOptimization(&mCurrentFrame);
mnMatchesInliers = 0;
// Update MapPoints Statistics
// 更新当前帧的MapPoints被观测程度,并统计跟踪局部地图的效果
for(int i=0; i<mCurrentFrame.N; i++)
{
if(mCurrentFrame.mvpMapPoints[i])
{
if(!mCurrentFrame.mvbOutlier[i])
{
//标记该mappoint点被当前帧观测
mCurrentFrame.mvpMapPoints[i]->IncreaseFound();
if(!mbOnlyTracking)
{
if(mCurrentFrame.mvpMapPoints[i]->Observations()>0)
mnMatchesInliers++;
}
else
mnMatchesInliers++;
}
else if(mSensor==System::STEREO)
mCurrentFrame.mvpMapPoints[i] = static_cast<MapPoint*>(NULL);
}
}
// Decide if the tracking was succesful
// More restrictive if there was a relocalization recently
// 决定是否跟踪成功
//如果当前帧和上一次重定位太近
//或者当前帧特征点与mappoint的匹配数太少
if(mCurrentFrame.mnId<mnLastRelocFrameId+mMaxFrames && mnMatchesInliers<50)
return false;
if(mnMatchesInliers<30)
return false;
else
return true;
}
在局部地图的mappoint中查找在当前帧视野范围内的点,将视野范围内的点和当前帧的特征点进行投影匹配
void Tracking::SearchLocalPoints()
{
// Do not search map points already matched
//当前帧mCurrentFrame匹配的mappoint点就不要匹配了
//这些匹配点都是在```TrackWithMotionModel()```,```TrackReferenceKeyFrame()```,```Relocalization()```中当前帧和mappoint的匹配
//它们都是被“预测”和当前帧匹配的mappoint点匹配
for(vector<MapPoint*>::iterator vit=mCurrentFrame.mvpMapPoints.begin(), vend=mCurrentFrame.mvpMapPoints.end(); vit!=vend; vit++)
{
MapPoint* pMP = *vit;
if(pMP)
{
if(pMP->isBad())
{
*vit = static_cast<MapPoint*>(NULL);
}
else
{
//预测这个mappoint会被匹配
pMP->IncreaseVisible();
// 标记该点被当前帧观测到
pMP->mnLastFrameSeen = mCurrentFrame.mnId;
// 标记该点将来在matcher.SearchByProjection()不被投影,因为已经匹配过
pMP->mbTrackInView = false;
}
}
}
int nToMatch=0;
// Project points in frame and check its visibility
//遍历刚才更新的mvpLocalMapPoints,筛选哪些不在视野范围内的mappoint
//在视野范围内的mappoint是被预测我们能够和当前帧匹配上的mappoint点
for(vector<MapPoint*>::iterator vit=mvpLocalMapPoints.begin(), vend=mvpLocalMapPoints.end(); vit!=vend; vit++)
{
MapPoint* pMP = *vit;
if(pMP->mnLastFrameSeen == mCurrentFrame.mnId)
continue;
if(pMP->isBad())
continue;
// Project (this fills MapPoint variables for matching)
//如果此mappoint点在视野范围内
if(mCurrentFrame.isInFrustum(pMP,0.5))
{
//预测这个mappoint会被匹配
pMP->IncreaseVisible();
nToMatch++;
}
}
if(nToMatch>0)
{
ORBmatcher matcher(0.8);
int th = 1;
if(mSensor==System::RGBD)
th=3;
// If the camera has been relocalised recently, perform a coarser search
if(mCurrentFrame.mnId<mnLastRelocFrameId+2)
th=5;
matcher.SearchByProjection(mCurrentFrame,mvpLocalMapPoints,th);
}
}
判断是否需要添加新的keyframe
bool Tracking::NeedNewKeyFrame()
{
if(mbOnlyTracking)
return false;
// If Local Mapping is freezed by a Loop Closure do not insert keyframes
if(mpLocalMapper->isStopped() || mpLocalMapper->stopRequested())
return false;
const int nKFs = mpMap->KeyFramesInMap();
// Do not insert keyframes if not enough frames have passed from last relocalisation
if(mCurrentFrame.mnId<mnLastRelocFrameId+mMaxFrames && nKFs>mMaxFrames)
return false;
// Tracked MapPoints in the reference keyframe
int nMinObs = 3;
if(nKFs<=2)
nMinObs=2;
int nRefMatches = mpReferenceKF->TrackedMapPoints(nMinObs);
// Local Mapping accept keyframes?
//查询局部地图管理器是否繁忙
bool bLocalMappingIdle = mpLocalMapper->AcceptKeyFrames();
// Check how many "close" points are being tracked and how many could be potentially created.
int nNonTrackedClose = 0;
int nTrackedClose= 0;
if(mSensor!=System::MONOCULAR)
{
for(int i =0; i<mCurrentFrame.N; i++)
{
if(mCurrentFrame.mvDepth[i]>0 && mCurrentFrame.mvDepth[i]<mThDepth)
{
if(mCurrentFrame.mvpMapPoints[i] && !mCurrentFrame.mvbOutlier[i])
nTrackedClose++;
else
nNonTrackedClose++;
}
}
}
bool bNeedToInsertClose = (nTrackedClose<100) && (nNonTrackedClose>70);
// Thresholds
// 设定inlier阈值,和之前帧特征点匹配的inlier比例
float thRefRatio = 0.75f;
if(nKFs<2)
thRefRatio = 0.4f;
if(mSensor==System::MONOCULAR)
thRefRatio = 0.9f;
// Condition 1a: More than "MaxFrames" have passed from last keyframe insertion
//和上一个关键帧间隔需要大于mMaxFrames
const bool c1a = mCurrentFrame.mnId>=mnLastKeyFrameId+mMaxFrames;
// Condition 1b: More than "MinFrames" have passed and Local Mapping is idle
//如果Local Mapping空闲,且和上一个关键帧间隔需要大于mMinFrames
const bool c1b = (mCurrentFrame.mnId>=mnLastKeyFrameId+mMinFrames && bLocalMappingIdle);
//Condition 1c: tracking is weak
const bool c1c = mSensor!=System::MONOCULAR && (mnMatchesInliers<nRefMatches*0.25 || bNeedToInsertClose) ;
// Condition 2: Few tracked points compared to reference keyframe. Lots of visual odometry compared to map matches.
const bool c2 = ((mnMatchesInliers<nRefMatches*thRefRatio|| bNeedToInsertClose) && mnMatchesInliers>15);
if((c1a||c1b||c1c)&&c2)
{
// If the mapping accepts keyframes, insert keyframe.
// Otherwise send a signal to interrupt BA
if(bLocalMappingIdle)
{
return true;
}
else
{
mpLocalMapper->InterruptBA();
if(mSensor!=System::MONOCULAR)
{
if(mpLocalMapper->KeyframesInQueue()<3)
return true;
else
return false;
}
else
return false;
}
}
else
return false;
}
创建新的关键帧,对于非单目的情况,同时创建新的MapPoints
void Tracking::CreateNewKeyFrame()
{
if(!mpLocalMapper->SetNotStop(true))
return;
// 步骤1:将当前帧构造成关键帧
KeyFrame* pKF = new KeyFrame(mCurrentFrame,mpMap,mpKeyFrameDB);
// 步骤2:将当前关键帧设置为当前帧的参考关键帧
// 在UpdateLocalKeyFrames函数中会将与当前关键帧共视程度最高的关键帧设定为当前帧的参考关键帧
mpReferenceKF = pKF;
mCurrentFrame.mpReferenceKF = pKF;
// 这段代码和UpdateLastFrame中的那一部分代码功能相同
// 步骤3:对于双目或rgbd摄像头,为当前帧生成新的MapPoints
if(mSensor!=System::MONOCULAR)
{
// 根据Tcw计算mRcw、mtcw和mRwc、mOw
mCurrentFrame.UpdatePoseMatrices();
// We sort points by the measured depth by the stereo/RGBD sensor.
// We create all those MapPoints whose depth < mThDepth.
// If there are less than 100 close points we create the 100 closest.
// 步骤3.1:得到当前帧深度小于阈值的特征点
// 创建新的MapPoint, depth < mThDepth
vector<pair<float,int> > vDepthIdx;
vDepthIdx.reserve(mCurrentFrame.N);
for(int i=0; i<mCurrentFrame.N; i++)
{
float z = mCurrentFrame.mvDepth[i];
if(z>0)
{
vDepthIdx.push_back(make_pair(z,i));
}
}
if(!vDepthIdx.empty())
{
// 步骤3.2:按照深度从小到大排序
sort(vDepthIdx.begin(),vDepthIdx.end());
// 步骤3.3:将距离比较近的点包装成MapPoints
int nPoints = 0;
for(size_t j=0; j<vDepthIdx.size();j++)
{
int i = vDepthIdx[j].second;
bool bCreateNew = false;
MapPoint* pMP = mCurrentFrame.mvpMapPoints[i];
if(!pMP)
bCreateNew = true;
else if(pMP->Observations()<1)
{
bCreateNew = true;
mCurrentFrame.mvpMapPoints[i] = static_cast<MapPoint*>(NULL);
}
if(bCreateNew)
{
cv::Mat x3D = mCurrentFrame.UnprojectStereo(i);
MapPoint* pNewMP = new MapPoint(x3D,pKF,mpMap);
// 这些添加属性的操作是每次创建MapPoint后都要做的
pNewMP->AddObservation(pKF,i);
pKF->AddMapPoint(pNewMP,i);
pNewMP->ComputeDistinctiveDescriptors();
pNewMP->UpdateNormalAndDepth();
//向map中添加mappoint
mpMap->AddMapPoint(pNewMP);
mCurrentFrame.mvpMapPoints[i]=pNewMP;
nPoints++;
}
else
{
nPoints++;
}
//如果深度大于阈值mThDepth,或者nPoints>100则停止添加mappoint点
if(vDepthIdx[j].first>mThDepth && nPoints>100)
break;
}
}
}
mpLocalMapper->InsertKeyFrame(pKF);
mpLocalMapper->SetNotStop(false);
mnLastKeyFrameId = mCurrentFrame.mnId;
mpLastKeyFrame = pKF;
}