前言
本文结合其余的ORBSLAM2的资料,对ORBLSAM2源码进行注释,感谢知识星球、泡泡机器人感谢吴博!
源码是知识星球小六等人的带注释版本。
1、Tracking线程主要是用来计算各个帧的位姿
在Tracking.cpp中将图片放进Tracking线程只要是下面的
GrabImageStereo()和GrabImageRGBD()、GrabImageMonocular()函数。
这三个函数的流程如下图所示:
/**
* 这里是双目的获取图片的函数、同时利用获得的灰度图构建当前帧,进行tracking过程,得到世界到相机的位姿变换
**/
// 输入左右目图像,可以为RGB、BGR、RGBA、GRAY
// 1、将图像转为mImGray和imGrayRight并初始化mCurrentFrame
// 2、进行tracking过程
// 输出世界坐标系到该帧相机坐标系的变换矩阵
cv::Mat Tracking::GrabImageStereo(
const cv::Mat &imRectLeft, //左侧图像
const cv::Mat &imRectRight, //右侧图像
const double ×tamp) //时间戳
{
mImGray = imRectLeft;
cv::Mat imGrayRight = imRectRight;
// step 1 :将RGB或RGBA图像转为灰度图像
if(mImGray.channels()==3)
{
if(mbRGB)
{
cvtColor(mImGray,mImGray,CV_RGB2GRAY);
cvtColor(imGrayRight,imGrayRight,CV_RGB2GRAY);
}
else
{
cvtColor(mImGray,mImGray,CV_BGR2GRAY);
cvtColor(imGrayRight,imGrayRight,CV_BGR2GRAY);
}
}
// 这里考虑得十分周全,甚至连四通道的图像都考虑到了 个人映像里四通道多了个alpha透明度吧
else if(mImGray.channels()==4)
{
if(mbRGB)
{
cvtColor(mImGray,mImGray,CV_RGBA2GRAY);
cvtColor(imGrayRight,imGrayRight,CV_RGBA2GRAY);
}
else
{
cvtColor(mImGray,mImGray,CV_BGRA2GRAY);
cvtColor(imGrayRight,imGrayRight,CV_BGRA2GRAY);
}
}
// Step 2 :构造Frame
mCurrentFrame = Frame(
mImGray, //左目图像
imGrayRight, //右目图像
timestamp, //时间戳
mpORBextractorLeft, //左目特征提取器
mpORBextractorRight, //右目特征提取器
mpORBVocabulary, //字典
mK, //内参矩阵
mDistCoef, //去畸变参数
mbf, //基线长度
mThDepth); //远点,近点的区分阈值
// Step 3 :跟踪
Track();//追踪就应该是计算位姿
//返回位姿
return mCurrentFrame.mTcw.clone();
}
/**
* 这里是RGBD的获取图片的函数、同时利用获得的灰度图构建当前帧,进行tracking过程,得到世界到相机的位姿变换
**/
// 输入左目RGB或RGBA图像和深度图
// 1、将图像转为mImGray和imDepth并初始化mCurrentFrame
// 2、进行tracking过程
// 输出世界坐标系到该帧相机坐标系的变换矩阵
cv::Mat Tracking::GrabImageRGBD(
const cv::Mat &imRGB, //彩色图像
const cv::Mat &imD, //深度图像
const double ×tamp) //时间戳
{
mImGray = imRGB;
cv::Mat imDepth = imD;
// step 1:将RGB或RGBA图像转为灰度图像
if(mImGray.channels()==3)
{
if(mbRGB)
cvtColor(mImGray,mImGray,CV_RGB2GRAY);
else
cvtColor(mImGray,mImGray,CV_BGR2GRAY);
}
else if(mImGray.channels()==4)
{
if(mbRGB)
cvtColor(mImGray,mImGray,CV_RGBA2GRAY);
else
cvtColor(mImGray,mImGray,CV_BGRA2GRAY);
}
// step 2 :将深度相机的disparity转为Depth , 也就是转换成为真正尺度下的深度
//这里的判断条件感觉有些尴尬
//前者和后者满足一个就可以了
//mDepthMapFactor--深度相机disparity转化为depth时的因子
//满足前者意味着,mDepthMapFactor 相对1来讲要足够大
//满足后者意味着,如果深度图像不是浮点型? 才会执行
//意思就是说,如果读取到的深度图像是浮点型,就不执行这个尺度的变换操作了呗? TODO
if((fabs(mDepthMapFactor-1.0f)>1e-5) || imDepth.type()!=CV_32F) //深度图得是CV_32F
imDepth.convertTo( //将图像转换成为另外一种数据类型,具有可选的数据大小缩放系数
imDepth, //输出图像
CV_32F, //输出图像的数据类型
mDepthMapFactor); //缩放系数
// 步骤3:构造Frame
mCurrentFrame = Frame(
mImGray, //灰度图像
imDepth, //深度图像
timestamp, //时间戳
mpORBextractorLeft, //ORB特征提取器
mpORBVocabulary, //词典
mK, //相机内参矩阵
mDistCoef, //相机的去畸变参数
mbf, //相机基线*相机焦距
mThDepth); //内外点区分深度阈值
// 步骤4:跟踪
Track();
//返回当前帧的位姿
return mCurrentFrame.mTcw.clone();
}
/**
* @brief
* 输入左目RGB或RGBA图像,输出世界坐标系到该帧相机坐标系的变换矩阵
*
* @param[in] im 单目图像
* @param[in] timestamp 时间戳
* @return cv::Mat
*
* Step 1 :将彩色图像转为灰度图像
* Step 2 :构造Frame
* Step 3 :跟踪
*/
cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im,const double ×tamp)
{
mImGray = im;
// Step 1 :将彩色图像转为灰度图像
//若图片是3、4通道的,还需要转化成灰度图
if(mImGray.channels()==3)
{
if(mbRGB)
cvtColor(mImGray,mImGray,CV_RGB2GRAY);
else
cvtColor(mImGray,mImGray,CV_BGR2GRAY);
}
else if(mImGray.channels()==4)
{
if(mbRGB)
cvtColor(mImGray,mImGray,CV_RGBA2GRAY);
else
cvtColor(mImGray,mImGray,CV_BGRA2GRAY);
}
// Step 2 :构造Frame
//判断该帧是不是初始化
if(mState==NOT_INITIALIZED || mState==NO_IMAGES_YET) //没有成功初始化的前一个状态就是NO_IMAGES_YET
mCurrentFrame = Frame(
mImGray,
timestamp,
mpIniORBextractor, //初始化ORB特征点提取器会提取2倍的指定特征点数目
mpORBVocabulary,
mK,
mDistCoef,
mbf,
mThDepth);
else
mCurrentFrame = Frame(
mImGray,
timestamp,
mpORBextractorLeft, //正常运行的时的ORB特征点提取器,提取指定数目特征点
mpORBVocabulary,
mK,
mDistCoef,
mbf,
mThDepth);
// Step 3 :跟踪
Track();
//返回当前帧的位姿
return mCurrentFrame.mTcw.clone();
}
通过上面三个函数,Mono 、双目、RGBD的数据就可以进入对应的Tracking线程
下面的Track函数才是真正意义上的Tracking线程
/*
* @brief Main tracking function. It is independent of the input sensor.
*
* track包含两部分:估计运动、跟踪局部地图
*
* Step 1:初始化
* Step 2:跟踪
* Step 3:记录位姿信息,用于轨迹复现
*/
/**
* NO_IMAGES_YET等同于NOT_INITIALIZED
* 首先判断状态,如果状态是NOT_INITIALIZED 那么要进行初始化
* step1 初始化 根据相机类型选择初始化函数 ---- StereoInitialization()-双目/RGBD MonocularInitialization()-单目;
*
* step2 系统初始化过后,跟踪帧---总之就是计算当前帧的位姿
* 跟踪分为两种
* 1、跟踪进入正常SLAM模式,有地图更新 不仅追踪 同时局部地图被激活
* 1.1 正常初始化成功
* 运动模型是空的或刚完成重定位,跟踪参考关键帧;否则恒速模型跟踪( 第一个条件,如果运动模型为空,说明是刚初始化开始,或者已经跟丢了
第二个条件,如果当前帧紧紧地跟着在重定位的帧的后面,我们将重定位帧来恢复位姿)
* 如果恒速模型跟踪失败那也要跟踪参考关键帧
* 1.2 如果跟踪状态不成功,那么就只能重定位了---BOW搜索,EPnP求解位姿----重定位的函数挺复杂的
* 2、只进行跟踪tracking,局部地图不工作
* 2.1 如果状态是跟踪丢失 只能重定位了---BOW搜索,EPnP求解位姿----重定位的函数挺复杂的
* 2.2 如果状态没有跟踪丢失(因为此时已经初始化了,状态没有跟踪丢失,就是跟踪正常)
* mbVO是mbOnlyTracking为true时的才有的一个变量
* mbVO为false表示此帧匹配了很多的MapPoints,跟踪很正常 (注意有点反直觉)
* mbVO为true表明此帧匹配了很少的MapPoints,少于10个,要跪的节奏
* 2.2.1 mbvO为false时,利用恒速模型或者参考帧计算当前帧位姿
* 2.2.2 mbvO为true时,这时候点不够多,恒速模型,重定位都用上,更相信重定位,通过这个得到位姿 ,重定位和恒速模型有一个成功就行
*
* Step 3 在跟踪得到当前帧初始姿态后,现在对local map进行跟踪得到更多的匹配,并优化当前位姿
* 前面只是跟踪一帧得到初始位姿,这里搜索局部关键帧、局部地图点,和当前帧进行投影匹配,得到更多匹配的MapPoints后进行Pose优化
* 3.1 跟踪进入正常SLAM模式,有地图更新 调用TrackLocalMap()函数,进行局部地图跟踪,得到优化的位姿
* 3.2 只进行跟踪tracking,局部地图不工作 这里是恒速模型,重定位都用到
*step3中两种情况都要追踪局部地图 最终 返回局部追踪后的状态 如果局部追踪成功,状态就是OK 否则就是 LOST
*
* Step 4 更新显示线程中的图像、特征点、地图点等信息----mpFrameDrawer->Update(this);
*
* 只有在成功追踪时才考虑生成关键帧的问题
*
* Step 5 跟踪成功,更新恒速运动模型----肯定要更新哦,因为得到当前帧的位姿,之前的恒速模型是上上帧到上帧的模型,追踪成功后,恒速模型肯定变成从上一帧到当前帧了
*
* 更新显示中的位姿----当前帧的位姿已经通过追踪得到啦!
*
* Step 6 清除观测不到的地图点----个人理解是,当前帧上的有些特征点在空间中没有与之对应的路标点(3d),就让这些点存空指针,
*
* Step 7 清除恒速模型跟踪中 UpdateLastFrame中为当前帧临时添加的MapPoints(仅双目和rgbd)---添加临时的地图点为了提高追踪精度吧
* 步骤6中只是在当前帧中将这些MapPoints剔除,这里从MapPoints数据库中删除
* 临时地图点仅仅是为了提高双目或rgbd摄像头的帧间跟踪效果,用完以后就扔了,没有添加到地图中
* 不仅仅是清除临时添加的MapPoints-mlpTemporalPoints,通过delete pMP还删除了指针指向的MapPoint--??不太懂
*
* Step 8 检测并插入关键帧,对于双目或RGB-D会产生新的地图点
*
* Step 9 删除那些在bundle adjustment中检测为outlier的地图点
* 作者这里说允许在BA中被Huber核函数判断为外点的传入新的关键帧中,让后续的BA来审判他们是不是真正的外点
* 但是估计下一帧位姿的时候我们不想用这些外点,所以删掉
* Step 10 如果初始化后不久就跟踪失败,并且relocation也没有搞定,只能重新Reset
*
* Step 11 记录位姿信息,用于最后保存所有的轨迹
* 11.1 如果当前帧跟踪好了,保存跟踪成功的位姿信息
* 计算相对位姿-Tcr = Tcw * Twr, Twr = Trw^-1
* 11.2 如果跟踪失败,则相对位姿使用上一次值
*
*/
void Tracking::Track()
{
// track包含两部分:估计运动、跟踪局部地图
// mState为tracking的状态,包括 SYSTME_NOT_READY, NO_IMAGE_YET, NOT_INITIALIZED, OK, LOST
// 如果图像复位过、或者第一次运行,则为NO_IMAGE_YET状态
if(mState==NO_IMAGES_YET)
{
mState = NOT_INITIALIZED;//如果没有图片也算是没有初始化
}
// mLastProcessedState 存储了Tracking最新的状态,用于FrameDrawer中的绘制
mLastProcessedState=mState;
// Get Map Mutex -> Map cannot be changed
// 上锁。保证地图不会发生变化
// 疑问:这样子会不会影响地图的更新?
// 回答:主要耗时在构造帧中特征点的提取和匹配部分,在那个时候地图是没有被上锁的,有足够的时间更新地图
unique_lock<mutex> lock(mpMap->mMutexMapUpdate);
// Step 1:初始化
if(mState==NOT_INITIALIZED)
{
if(mSensor==System::STEREO || mSensor==System::RGBD)
//双目RGBD相机的初始化共用一个函数
StereoInitialization();
else
//单目初始化
MonocularInitialization();
//更新帧绘制器中存储的最新状态
mpFrameDrawer->Update(this);
//这个状态量在上面的初始化函数中被更新
if(mState!=OK)
return;
}
else
{
//系统已经初始化 ,跟踪帧
// System is initialized. Track Frame.
// bOK为临时变量,用于表示每个函数是否执行成功
bool bOK;
// Initial camera pose estimation using motion model or relocalization (if tracking is lost)
// mbOnlyTracking等于false表示正常SLAM模式(定位+地图更新),mbOnlyTracking等于true表示仅定位模式
// tracking 类构造时默认为false。在viewer中有个开关ActivateLocalizationMode,可以控制是否开启mbOnlyTracking
if(!mbOnlyTracking)// Step 2:跟踪进入正常SLAM模式,有地图更新 不仅追踪 同时局部地图被激活
{
// Local Mapping is activated. This is the normal behaviour, unless
// you explicitly activate the "only tracking" mode.
// Step 2:跟踪进入正常SLAM模式,有地图更新
// 正常初始化成功
if(mState==OK)
{
// Local Mapping might have changed some MapPoints tracked in last frame
// Step 2.1 检查并更新上一帧被替换的MapPoints
// 局部建图线程则可能会对原有的地图点进行替换.在这里进行检查
CheckReplacedInLastFrame();
// Step 2.2 运动模型是空的或刚完成重定位,跟踪参考关键帧;否则恒速模型跟踪
// 第一个条件,如果运动模型为空,说明是刚初始化开始,或者已经跟丢了
// 第二个条件,如果当前帧紧紧地跟着在重定位的帧的后面,我们将重定位帧来恢复位姿
// mnLastRelocFrameId 上一次重定位的那一帧
if(mVelocity.empty() || mCurrentFrame.mnId<mnLastRelocFrameId+2)
{
// 用最近的关键帧来跟踪当前的普通帧
// 通过BoW的方式在参考帧中找当前帧特征点的匹配点
// 优化每个特征点都对应3D点重投影误差即可得到位姿
bOK = TrackReferenceKeyFrame();//跟踪参考帧
}
else
{
// 用最近的普通帧来跟踪当前的普通帧
// 根据恒速模型设定当前帧的初始位姿
// 通过投影的方式在参考帧中找当前帧特征点的匹配点
// 优化每个特征点所对应3D点的投影误差即可得到位姿
bOK = TrackWithMotionModel();
if(!bOK)
//根据恒速模型失败了,只能根据参考关键帧来跟踪
bOK = TrackReferenceKeyFrame();
}
}
else
{
// 如果跟踪状态不成功,那么就只能重定位了
// BOW搜索,EPnP求解位姿
bOK = Relocalization();
//在世界坐标系下选取N个点,然后选取质心、三个主方向为控制的4个点(world),求出四个控制点以及其他的点在当前帧下的坐标
}
}
else // Step 2:只进行跟踪tracking,局部地图不工作
// 当前帧匹配的点(mappoint)比较多的时候(mbVO=false)、跟踪正常
// 当前帧匹配的点(mappoint)比较少的时候(mbVO=true)<10、既要跟踪(恒速模型)又要重定位 ,我们更相信重定位,只要重定位成功,mbvO就是false
{
// Localization Mode: Local Mapping is deactivated
// Step 2:只进行跟踪tracking,局部地图不工作
if(mState==LOST)
{
// Step 2.1 如果跟丢了,只能重定位
bOK = Relocalization();
}
else
{
// mbVO是mbOnlyTracking为true时的才有的一个变量
// mbVO为false表示此帧匹配了很多的MapPoints,跟踪很正常 (注意有点反直觉)
// mbVO为true表明此帧匹配了很少的MapPoints,少于10个,要跪的节奏
if(!mbVO)
{
// Step 2.2 如果跟踪正常,使用恒速模型 或 参考关键帧跟踪
// In last frame we tracked enough MapPoints in the map
if(!mVelocity.empty())// !mVelocity.empty()表示运动模型不是空的
{
bOK = TrackWithMotionModel();
// ? 为了和前面模式统一,这个地方是不是应该加上
// if(!bOK)
// bOK = TrackReferenceKeyFrame();
}
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.
// mbVO为true,表明此帧匹配了很少(小于10)的地图点,要跪的节奏,既做跟踪又做重定位
//MM=Motion Model,通过运动模型进行跟踪的结果
bool bOKMM = false;
//通过重定位方法来跟踪的结果
bool bOKReloc = false;
//运动模型中构造的地图点
vector<MapPoint*> vpMPsMM;
//在追踪运动模型后发现的外点
vector<bool> vbOutMM;
//运动模型得到的位姿
cv::Mat TcwMM;
// Step 2.3 当运动模型有效的时候,根据运动模型计算位姿
if(!mVelocity.empty())
{
bOKMM = TrackWithMotionModel();
// 将恒速模型跟踪结果暂存到这几个变量中,因为后面重定位会改变这些变量
vpMPsMM = mCurrentFrame.mvpMapPoints;
vbOutMM = mCurrentFrame.mvbOutlier;
TcwMM = mCurrentFrame.mTcw.clone();
}
// Step 2.4 使用重定位的方法来得到当前帧的位姿
bOKReloc = Relocalization();
// Step 2.5 根据前面的恒速模型、重定位结果来更新状态
if(bOKMM && !bOKReloc)// 恒速模型成功、重定位失败,重新使用之前暂存的恒速模型结果
{
// 恒速模型成功、重定位失败,重新使用之前暂存的恒速模型结果
mCurrentFrame.SetPose(TcwMM);
mCurrentFrame.mvpMapPoints = vpMPsMM;
mCurrentFrame.mvbOutlier = vbOutMM;
//? 疑似bug!这段代码是不是重复增加了观测次数?后面 TrackLocalMap 函数中会有这些操作
// 如果当前帧匹配的3D点很少,增加当前可视地图点的被观测次数
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.
// Step 3:在跟踪得到当前帧初始姿态后,现在对local map进行跟踪得到更多的匹配,并优化当前位姿
// 前面只是跟踪一帧得到初始位姿,这里搜索局部关键帧、局部地图点,和当前帧进行投影匹配,得到更多匹配的MapPoints后进行Pose优化
if(!mbOnlyTracking)//跟踪进入正常SLAM模式,有地图更新
{
if(bOK)//bOK表示追踪成功与否
bOK = TrackLocalMap();
}
else//只进行跟踪tracking,局部地图不工作
{
// 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.
// 重定位成功??有点疑问,在只进行tracking的时候,也不一定一定使用重定位,如果初始化正常,用恒速模型/参考帧就行了啊!
if(bOK && !mbVO)//
bOK = TrackLocalMap();
}
//根据上面的操作来判断是否追踪成功
if(bOK)
mState = OK;
else
mState=LOST;
// Step 4:更新显示线程中的图像、特征点、地图点等信息
mpFrameDrawer->Update(this);
// If tracking were good, check if we insert a keyframe
//只有在成功追踪时才考虑生成关键帧的问题
if(bOK)
{
// Update motion model
// Step 5:跟踪成功,更新恒速运动模型
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 = Tcl = Tcw * Twl,表示上一帧到当前帧的变换, 其中 Twl = LastTwc
mVelocity = mCurrentFrame.mTcw*LastTwc;
}
else
//否则速度为空
mVelocity = cv::Mat();
//更新显示中的位姿
mpMapDrawer->SetCurrentCameraPose(mCurrentFrame.mTcw);
// Clean VO matches
// Step 6:清除观测不到的地图点
for(int i=0; i<mCurrentFrame.N; i++)
{
MapPoint* pMP = mCurrentFrame.mvpMapPoints[i];//遍历当前帧的特征点对应的mappoint 如果特征点没有对应的mappoint则存空指针
if(pMP)
if(pMP->Observations()<1)
{
mCurrentFrame.mvbOutlier[i] = false;
mCurrentFrame.mvpMapPoints[i]=static_cast<MapPoint*>(NULL);
}
}
// Delete temporal MapPoints
// Step 7:清除恒速模型跟踪中 UpdateLastFrame中为当前帧临时添加的MapPoints(仅双目和rgbd)
// 步骤6中只是在当前帧中将这些MapPoints剔除,这里从MapPoints数据库中删除
// 临时地图点仅仅是为了提高双目或rgbd摄像头的帧间跟踪效果,用完以后就扔了,没有添加到地图中
for(list<MapPoint*>::iterator lit = mlpTemporalPoints.begin(), lend = mlpTemporalPoints.end(); lit!=lend; lit++)
{
MapPoint* pMP = *lit;
delete pMP;
}
// 这里不仅仅是清除mlpTemporalPoints,通过delete pMP还删除了指针指向的MapPoint
// 不能够直接执行这个是因为其中存储的都是指针,之前的操作都是为了避免内存泄露
mlpTemporalPoints.clear();
// Check if we need to insert a new keyframe
// Step 8:检测并插入关键帧,对于双目或RGB-D会产生新的地图点
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.
// 作者这里说允许在BA中被Huber核函数判断为外点的传入新的关键帧中,让后续的BA来审判他们是不是真正的外点
// 但是估计下一帧位姿的时候我们不想用这些外点,所以删掉
// Step 9 删除那些在bundle adjustment中检测为outlier的地图点
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
// Step 10 如果初始化后不久就跟踪失败,并且relocation也没有搞定,只能重新Reset
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.
// Step 11:记录位姿信息,用于最后保存所有的轨迹
if(!mCurrentFrame.mTcw.empty())
{
// 计算相对姿态Tcr = Tcw * Twr, Twr = Trw^-1
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);
}
}// Tracking
下面是Tracking.cpp的全部内容,能看的下去的话就看吧,内容比较多。
Tracking.cpp