ORB-SLAM2初步(Tracking.cpp)
今天主要是分析一下Tracking.cpp这个文件,它是实现跟踪过程的主要文件,这里主要针对单目,并且只是截取了部分代码片段。
一、跟踪过程分析
- 首先构造函数中使用初始化列表对跟踪状态mState(NO_IMAGES_YET), 传感器类型mSensor(sensor), 是否只进行定位mbOnlyTracking(false)等变量进行了初始化(注意:一些const关键字或者指针类的变量只能使用初始化列表进行初始化),同时在构造函数的函数体内通过OpenCV的FileStorage从文件中读取了Camera标定参数,ORB特征提取的相关参数等,并用其对相关变量进行了初始化。(由于这一段比较简单,很容易看懂,就不再赘述。)
- Tracking.cpp文件的调用接口函数是:
cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im, const double ×tamp) 它完成了对一帧的初始化,并转入Track过程: if(mState==NOT_INITIALIZED || mState==NO_IMAGES_YET) 
 mCurrentFrame = Frame(mImGray,timestamp,mpIniORBextractor,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth);
 else
 mCurrentFrame = Frame(mImGray,timestamp,mpORBextractorLeft,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth); Track();
- Track()实现了跟踪的主要逻辑过程:(1)第一步首先就是判断是否进行了初始化,关于初始化先暂且不表,只知道它通过调用一个初始化函数进行了初始化:
if(mState==NOT_INITIALIZED) 
 {
 //根据双目或RGBD或单目分别进行初始化,调用不同的函数;
 if(mSensor==System::STEREO || mSensor==System::RGBD)
 StereoInitialization();
 else
 MonocularInitialization(); mpFrameDrawer->Update(this); //如何初始化没有完成,需要返回重新进入线程进行初始化,成功了继续执行;
 if(mState!=OK)
 return;
 }(2)接下来也是判断,这里是同时跟踪和建图的跟踪过程,其实只有跟踪的时候也很有意思: 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
 CheckReplacedInLastFrame(); //判定速度是否为空,是则根据参考帧进行跟踪,否则根据运动模型进行跟踪,或者距离上一次重定位过去少于2帧;
 if(mVelocity.empty() || mCurrentFrame.mnId<mnLastRelocFrameId+)
 {
 bOK = TrackReferenceKeyFrame();
 }
 else
 {
 bOK = TrackWithMotionModel();
 //如果运动模型跟踪失败,使用参考帧模型进行跟踪;
 if(!bOK)
 bOK = TrackReferenceKeyFrame();
 }
 }
 //如果跟踪状态为丢失,则使用重定位找回当前相机的位姿;
 else
 {
 bOK = Relocalization();
 }
 }(3)到这里三种跟踪模型都已经出现了,它们分别是:运动模型、参考帧模型、重定位,这里先暂时跳过,后面单独分析这三种模型 TrackWithMotionModel(); 
 TrackReferenceKeyFrame();
 Relocalization()从上面的过程可以看出,如果初始化成功或上一帧的状态为成功(mState==OK),同时速度矩阵非空(mVelocity.empty()),则优先使用运动模型进行跟踪(从后面的分析可以看出这种跟踪方式速度最快),否则使用参考帧模型进行跟踪,如果上一帧跟踪状态为失败,就需要直接进行重定位找回相机位姿。 
- 假设不管使用哪种方法,跟踪状态显示成功了,同时返回了一个初始的相机位姿,下面就是要进行局部地图的跟踪过程,可以理解为三种模型获取一个初始相机位姿,然后使用跟踪局部地图的方式对位姿进行优化:
bOK = TrackLocalMap(); 我认为只要前面三种模型跟踪成功了,对局部地图的跟踪就会成功,所以这里bOK的状态不会改变(没有考虑其它特殊情况),其结果相当于获得了一个相对精确的相机位姿。 
- 下面就是一些扫尾工作,如果不知道运动模型是什么一种跟踪模型,那对前面的速度矩阵肯定很感兴趣了:
if(!mLastFrame.mTcw.empty()) 
 {
 cv::Mat LastTwc = cv::Mat::eye(,,CV_32F);
 mLastFrame.GetRotationInverse().copyTo(LastTwc.rowRange(,).colRange(,));
 mLastFrame.GetCameraCenter().copyTo(LastTwc.rowRange(,).col());
 //这里的速度矩阵存储的具体内容是当前帧的位姿乘以上一帧的位姿;
 mVelocity = mCurrentFrame.mTcw*LastTwc;
 }
 else
 //把速度矩阵设置为空。
 mVelocity = cv::Mat();结合后面的运动模型可以得知,它假设的是相机运动速度不变(就是假设下一帧的位姿矩阵和这一帧一样,但是相机的位置是不一样的): //更新当前帧的位姿:速度乘以上一帧的位姿; 
 mCurrentFrame.SetPose(mVelocity*mLastFrame.mTcw);其它的工作包括判断是否插入关键帧,删除一些外点,把当前帧置位上一帧等,如果为跟丢,且关键帧总数小于5(初始化不久就丢了),则需要进行重置。 
二、子函数分析
- 首先是运动模型:
//设置匹配器; 
 ORBmatcher matcher(0.9,true);
 //更新上一帧信息,对单目只更新了相机位姿;
 UpdateLastFrame();
 //更新当前帧的位姿:速度乘以上一帧的位姿;
 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=;
 else
 th=;
 int nmatches = matcher.SearchByProjection(mCurrentFrame,mLastFrame,th,mSensor==System::MONOCULAR);
 
 //如果匹配数小于20,则扩大搜索范围;
 if(nmatches<)
 {
 fill(mCurrentFrame.mvpMapPoints.begin(),mCurrentFrame.mvpMapPoints.end(),static_cast<MapPoint*>(NULL));
 nmatches = matcher.SearchByProjection(mCurrentFrame,mLastFrame,*th,mSensor==System::MONOCULAR);
 } //如果还是匹配数小于20,则判定运动模型跟踪失败;
 if(nmatches<)
 return false; //如果匹配数大于20了,就优化相机位姿;
 // Optimize frame pose with all matches
 Optimizer::PoseOptimization(&mCurrentFrame);后面就是根据不同情况对跟踪结果进行返回,还有当前帧特征中的地图点的判定等。 
- 参考帧模型:
//计算当前帧的Bow向量 
 mCurrentFrame.ComputeBoW();
 //设定匹配器;
 ORBmatcher matcher(0.7,true);
 vector<MapPoint*> vpMapPointMatches; //统计当前帧和参考关键帧之间匹配点数,使用BoW加速匹配过程;
 int nmatches = matcher.SearchByBoW(mpReferenceKF,mCurrentFrame,vpMapPointMatches);
 //这里将上一帧的位姿赋给了当前帧
 mCurrentFrame.SetPose(mLastFrame.mTcw);//优化当前位姿; 
 Optimizer::PoseOptimization(&mCurrentFrame);后面的过程跟运动模型类似。但是这里直接将上一帧位姿作为初值进行优化,并没有使用PnP求解,保留疑问。 
- 重定位:
//计算BoW向量; 
 mCurrentFrame.ComputeBoW();
 //在关键帧数据库中搜索当前帧的候选关键帧;
 vector<KeyFrame*> vpCandidateKFs = mpKeyFrameDB->DetectRelocalizationCandidates(&mCurrentFrame);
 if(vpCandidateKFs.empty())
 return false;
 const int nKFs = vpCandidateKFs.size();
 //设置匹配器;
 ORBmatcher matcher(0.75,true); vector<PnPsolver*> vpPnPsolvers;
 vpPnPsolvers.resize(nKFs); vector<vector<MapPoint*> > vvpMapPointMatches;
 vvpMapPointMatches.resize(nKFs); vector<bool> vbDiscarded;
 vbDiscarded.resize(nKFs); int nCandidates=; //对每一个关键帧进行PnP求解;
 //首先进行BoW匹配,匹配达到15个点的就进行进一步求解,并作为候选关键帧;
 for(int i=; i<nKFs; i++)
 {
 KeyFrame* pKF = vpCandidateKFs[i];
 if(pKF->isBad())
 vbDiscarded[i] = true;
 else
 {
 int nmatches = matcher.SearchByBoW(pKF,mCurrentFrame,vvpMapPointMatches[i]);
 if(nmatches<)
 {
 vbDiscarded[i] = true;
 continue;
 }
 else
 {
 PnPsolver* pSolver = new PnPsolver(mCurrentFrame,vvpMapPointMatches[i]);
 pSolver->SetRansacParameters(0.99,,,,0.5,5.991);
 vpPnPsolvers[i] = pSolver;
 nCandidates++;
 }
 }
 }
 //再后面一个大循环是上面的匹配结果进行优化求精,进行RANSAC迭代,如果有足够多的内点则跳出循环并返回重定位的过程至少在逻辑上是很好理解的,就是在已经生成的关键帧数据库中搜索看看当前帧和谁最相近,而方法就是先用BoW匹配,然后进行PnP求解,最后使用RANSAC迭代。 
- 还有一个重要的函数,就是局部地图跟踪:
//更新局部地图,包括关键帧和地图点的更新; 
 //它的主要作用就是通过关键帧和地图点的共视关系更新这两个变量:mvpLocalKeyFrames,mvpLocalMapPoints,它们中存储着局部地图中的关键帧和地图点;
 UpdateLocalMap();
 //这个函数就是搜索一下mvpLocalMapPoints中的点是否符合跟踪要求,并匹配当前帧和局部地图点;
 SearchLocalPoints();
 //然后就是优化位姿,需要注意的是,无论是匹配过程还是优化过程都会对地图点做一些修改
 Optimizer::PoseOptimization(&mCurrentFrame);
 //后面就是根据匹配和优化结果更新地图点的状态,并判断匹配的内点数量,最后返回实际上局部地图匹配的过程要比上面几行代码复杂的多,基本思想就是通过共视关系找出局部地图的关键帧和局部地图点,并用当前帧与之进行匹配优化。 
- 还有一些子函数,如判断是否插入关键帧,跟踪的重置,初始化过程,以及只进行跟踪不建图的跟踪过程等,以后有机会再说吧。
三、总结
通过梳理跟踪过程的代码,对ORB-SLAM的跟踪过程的算法和代码都有了更深入的理解,也体会到了写一个类似工程的知识量和工作量。
从前面的分析知道跟踪过程的时间消耗主要在局部地图的跟踪过程,提高效率的方法之一应该就是相应的减小局部地图的大小,具体来说就是mvpLocalKeyFrames,mvpLocalMapPoints这两个变量的大小,现在还没遇到这个问题,所以没有做相应实验。
ORB-SLAM2初步(Tracking.cpp)的更多相关文章
- ORB SLAM2在Ubuntu 16.04上的运行配置
		http://www.mamicode.com/info-detail-1773781.html 安装依赖 安装OpenGL 1. 安装opengl Library$sudo apt-get inst ... 
- orb slam2 双目摄像头
		主要参考了http://blog.csdn.net/awww797877/article/details/51171099这篇文章,其中需要添加的是:export ROS_PACKAGE_PATH=$ ... 
- 关于ORB SLAM2资源整理(持续更新)
		ORB SLAM2源码讲解(吴博) https://www.youtube.com/watch?v=2GVE7FTW7AU 泡泡机器人视频整理: http://space.bilibili.com/3 ... 
- Ubuntu14.04 使用本地摄像头跑ORB SLAM2(暂未完成)
		嗯 这个方法我暂时弄不出来,用了另外一个方法:SLAM14讲 第一次课 使用摄像头或视频运行 ORB-SLAM2 前面的准备: Ubuntu14.04安装 ROS 安装步骤和问题总结 Ubuntu14 ... 
- ORB SLAM2 学习笔记
		cd ~/Documents/demos/ORB_SLAM2 ./Examples/RGB-D/rgbd_tum Vocabulary/ORBvoc.txt Examples/RGB-D/TUM1.y ... 
- orb slam2
- 使用 evo 工具评测 VI ORB SLAM2 在 EuRoC 上的结果
		http://www.liuxiao.org/2017/11/%E4%BD%BF%E7%94%A8-evo-%E5%B7%A5%E5%85%B7%E8%AF%84%E6%B5%8B-vi-orb-sl ... 
- Ubuntu16.04+Ros+Usb_Cam ORB SLAM2
		转载自:https://www.jianshu.com/p/dbf39b9e4617亲测可用 1.其中编译ORB_SLAM2的 ./build.sh 和 ./build_ros.sh之前需要修改文 ... 
- ORB-SLAM2初步(源码逻辑分析)
		今天主要是梳理一下ORB-SLAM2源码的逻辑关系,GitHub和泡泡机器人上有很好的注释版本(吴博),大神请(轻)板砖. 一.文件 如图所示,Examples里面存放的分别是基于单目.双目.RGBD ... 
随机推荐
- 配置SQL Server维护计划-定时备份
			目录 创建维护计划 创建任务 配置维护计划的依赖环境 还原数据库 创建维护计划 打开SQL Server 2014 Management Studio,用SQL Server管理员账户登录. 展开Ma ... 
- Eclipse Memory Analyzer(MAT),内存泄漏插件,安装使用一条龙
			网上文档很多,但最初都有问题.整理一份,作为备份.使用过程:开发代码写完后,对可能出现内存溢出的代码,添加配置文件,生成.hprof文件,用memory Analyzer分析排查问题,且泄漏内存大小可 ... 
- springboot+jpa分库分表项目实例
			分库分表场景 关系型数据库本身比较容易成为系统瓶颈,单机存储容量.连接数.处理能力都有限.当单表的数据量达到1000W或100G以后,由于查询维度较多,即使添加从库.优化索引,做很多操作时性能仍下降严 ... 
- Linux 学习记录三(Vim 文书编辑器).
			所有的Unix Like系统都会内建vi文书编辑器,其他的文书编辑器不一定存在,vim是vi的升级版,具有程序编辑的能力,可以主动的以字体颜色辨别语法的正确性,方便程序设计.vim 里面加入了很 ... 
- 正确使用Spring Data JPA规范
			在优锐课的学习分享中探讨了关于,Spring Data JPA的创建主要是为了通过按方法名称生成查询来轻松创建查询. 但是,有时我们需要创建复杂的查询,而无法利用查询生成器.码了很多知识笔记分享给大家 ... 
- Containers vs Serverless:本质区别是什么?
			在云计算领域,容器和无服务器计算已经占据了发展前列. 作者 | Emra Samdan 翻译 | bocloudresearch 一点历史 在不久以前,应用程序的开发.部署和维护要比现在复杂得多,耗时 ... 
- JS基础语法---一元运算符
			* ++ -- 都是运算符 * ++ 和 -- 可以分为:前+ 和后+ and 前- 和后- * 如果++在后面:如: num++ +10参与 ... 
- HTML5新标签与特性---多媒体
			多媒体标签 embed:标签定义嵌入的内容 audio:播放音频 video:播放视频 多媒体 embed(会使用) embed可以用来插入各种多媒体,格式可以是 Midi.Wav.AIFF.AU.M ... 
- [转]Outlook API
			本文转自:https://www.cnblogs.com/yl153/p/6711519.html 1.Outlook简介 若要从Outlook 外控制Outlook对象,必须在编写代码的工程中建立对 ... 
- [转]Outlook VBA自动处理邮件
			本文转自:https://blog.csdn.net/hnwyllmm/article/details/44874331 需求描述公司里面每天都会有很多邮件,三分之一都是不需要看的,Outlook的过 ... 
