讲解关于slam一系列文章汇总链接:史上最全slam从零开始,针对于本栏目讲解的(01)ORB-SLAM2源码无死角解析链接如下(本文内容来自计算机视觉life ORB-SLAM2 课程课件): (01)ORB-SLAM2源码无死角解析-(00)目录_最新无死角讲解:https://blog.csdn.net/weixin_43013761/article/details/123092196 文末正下方中心提供了本人 联系方式, 点击本人照片即可显示 W X → 官方认证 {\color{blue}{文末正下方中心}提供了本人 \color{red} 联系方式,\color{blue}点击本人照片即可显示WX→官方认证} 文末正下方中心提供了本人联系方式,点击本人照片即可显示WX→官方认证
一、前言通过前面的一系列博客,我们对 src/Frame.cc 中的 Frame 有了一定了解。那么我们回到 (01)ORB-SLAM2源码无死角解析-(04)单目追踪_总体框架讲解TrackMonocular→GrabImageMonocular 中讲解的 GrabImageMonocular() 函数。根据输入帧创建 Frame 变量的代码如下(在04章节博客已经提及过,位于 src/Tracking.cc):
/**
* @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();
}
对于 mCurrentFrame 的由来我们以及有了足够的了解, (01)ORB-SLAM2源码无死角解析-(04)单目追踪_总体框架讲解TrackMonocular→GrabImageMonocular 博客中提到,SLAM2系统中主要存在三个核心线程线程,于 src\System.cc 初始化函数中抗议看到:
//追踪器,负责追踪的一些相关操作
mpTracker = new Tracking(this,mpVocabulary,mpFrameDrawer,mpMapDrawer,mpMap,mpKeyFrameDatabase,strSettingsFile,mSensor);
//局部建图器,负责局部地图的构建
mpLocalMapper = new LocalMapping(mpMap,mSensor==MONOCULAR);
//闭环器,闭环检测以及闭环操作
mpLoopCloser = new LoopClosing(mpMap,mpKeyFrameDatabase,mpVocabulary,mSensor!=MONOCULAR);
我们现在主要讲解的是其中的追踪函数,那么我们在来看看后调用的 Track() 函数,其实现于 src/Tracking.cc 文件中: void Tracking::Track().
核心思想 : \color{red}{核心思想:} 核心思想: 当前帧与上一帧(或者最近关键帧)进行特征点匹配,如果匹配点足够,则能计算出上一帧到当前帧的位姿变换,同时能够获得该关键点对在三维空间的坐标,显然易知对应的地图点。依次循环即可。
但是大家需要注意一个点,只有关键帧产生的新关键点才会进行地图更新,普通帧(双目或者深度相机)生成新的地图点是临时地图点,主要用于优化位姿估算,不会参与到全局地图的更新。
二、代码流程
简单看一下即可,目前是比较难理解了,在后面的博客中,会对每个细节进行详细的讲解。
//如果地图没有初始化则进行初始化
if(mState==NOT_INITIALIZED){
StereoInitialization();或者MonocularInitialization();}
else{//如果已经完成初始化
if(!mbOnlyTracking)//非仅追踪模式
if(mState==OK)// 如果跟踪正常
//如果有必要则对地图点进行替换
CheckReplacedInLastFrame();
//刚完成初始化或者跟丢,逸或者上帧进行了重定位
if(mVelocity.empty() || mCurrentFrame.mnIdUpdate(this);
if(bOK) // 只有在成功追踪时才考虑生成关键帧的问题
if(!mLastFrame.mTcw.empty())// Step 5:跟踪成功,更新恒速运动模型
mLastFrame.GetRotationInverse().copyTo(LastTwc.rowRange(0,3).colRange(0,3));
mLastFrame.GetCameraCenter().copyTo(LastTwc.rowRange(0,3).col(3));
else
//否则速度为空
mVelocity = cv::Mat();
//更新显示中的位姿
mpMapDrawer->SetCurrentCameraPose(mCurrentFrame.mTcw);
// Step 8:检测并插入关键帧,对于双目或RGB-D会产生新的地图点
if(NeedNewKeyFrame())
CreateNewKeyFrame();
if(mState==LOST)
mpSystem->Reset();
}
上面大概的代码流程。源码注释在下面粘贴出来。
三、源码注释
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 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)
{
// 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.mnIdUpdate(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; iObservations()
关注
打赏
最近更新
- 深拷贝和浅拷贝的区别(重点)
- 【Vue】走进Vue框架世界
- 【云服务器】项目部署—搭建网站—vue电商后台管理系统
- 【React介绍】 一文带你深入React
- 【React】React组件实例的三大属性之state,props,refs(你学废了吗)
- 【脚手架VueCLI】从零开始,创建一个VUE项目
- 【React】深入理解React组件生命周期----图文详解(含代码)
- 【React】DOM的Diffing算法是什么?以及DOM中key的作用----经典面试题
- 【React】1_使用React脚手架创建项目步骤--------详解(含项目结构说明)
- 【React】2_如何使用react脚手架写一个简单的页面?