本科毕设所研究的是基于直接法的视觉里程计技术,采用的开源方案是DSO(Direct Sparse Odometry)。在引入光度校准和光度仿射变换之后,并且联合优化了所涉及的所有参数,DSO的效果很棒,被誉为目前效果最好的直接法的方案,但是它只是一个odometry,并不是一个完整视觉slam系统。因此,为了更好的研究视觉SLAM,对ORB-SLAM2的论文以及代码进行了研究,在这里写下自己的一些拙见,欢迎各位大神指出文中的不足和错误之处。

以ORB-SLAM2中传感器为单目相机运行EuRoc数据集为例分析流程。
首先分析运行参数,一共需要五个参数,并且需要按照特定的顺序排列,

argv[0] 可执行文件
argv[1] ORB词典文件 strVocFile
argv[2] 参数设置文件 strSettingsFile
argv[3] 图像文件 vstrImageFilenames
argv[4] 时间戳 vTimestamps

加载图片和曝光时间:LoadImages(string(argv[3]), string(argv[4]), vstrImageFilenames, vTimestamps);
系统初始化:ORB_SLAM2::System SLAM(argv[1],argv[2],ORB_SLAM2::System::MONOCULAR,true);

cv::FileStorage fsSettings(strSettingsFile.c_str(), cv::FileStorage::READ);   //读取配置文件
mpVocabulary = new ORBVocabulary();bool bVocLoad = mpVocabulary->loadFromTextFile(strVocFile);  //构建orb字典对象,读取orb字典
mpKeyFrameDatabase = new KeyFrameDatabase(*mpVocabulary);  //创建关键帧数据库
mpMap = new Map();  //创建地图
mpFrameDrawer = new FrameDrawer(mpMap);  mpMapDrawer = new MapDrawer(mpMap, strSettingsFile);  // 可视化部分
mpTracker = new Tracking(this, mpVocabulary, mpFrameDrawer, mpMapDrawer, mpMap, mpKeyFrameDatabase, strSettingsFile, mSensor);
//track线程,在这个线程会读取配置文件进行相机内参矩阵的构建,畸变向量的构建,还会根据配置文件设置一些参数。
//最重要的是会构建两个特征提取的对象:mpORBextractorLeft = new ORBextractor(nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);  mpIniORBextractor = new ORBextractor(2*nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);  //对于传感器为单目相机所特有,用于初始化部分的特征点提取,提取数量是设置的两倍。
另外此部分还会初始化另外两个线程,目前还未仔细去看,在分析完track线程之后再讨论

利用for循环遍历所有图像帧,图像帧处理入口:SLAM.TrackMonocular(im,tframe);
cv::Mat Tcw = mpTracker->GrabImageMonocular(im,timestamp);
如果是第一帧:(或者未初始化成功)
mCurrentFrame = Frame(mImGray,timestamp,mpIniORBextractor,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth);
参数:灰度图、时间戳、初始ORB特征提取对象、ORB词典对象、相机内参矩阵、畸变向量、剩下两个参数不清楚(看yaml文件里也没有,可能对于单目相机不重要)

ExtractORB(0,imGray);//  提取ORB特征(*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors);  //orb特征提取采用的是重载的运算符()。
UndistortKeyPoints();  //对特征点去畸变cv::undistortPoints(mat,mat,mK,mDistCoef,cv::Mat(),mK);  //利用opencv提供的函数去畸变
ComputeImageBounds(imGray)  //计算去畸变之后图像的边界,只对第一帧执行。
AssignFeaturesToGrid();  //将关键点划分到格子中

如果不是第一帧:(或者初始化成功)
mCurrentFrame = Frame(mImGray,timestamp,mpORBextractorLeft,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth);
将ORB提取对象换成了mpORBextractorLeft,其他基本不变。
在构建图像帧对象Frame()之后,开启跟踪。构建的对象为mCurrentFrame,此时该图像帧已经提取了特征点并计算了相应的描述子,具体的实现过程后续讨论。
开始跟踪:Track();如果还未进行初始化,首先进行初始化操作,初始化操作需要连续的两个帧,并且两个帧的特征点匹配对数要大于100对,之后在进行三角化获得初始深度,构建初始地图。如果不满足条件则初始化失败,等下后续满足条件的连续两帧。

MonocularInitialization(); //单目初始化对于第一帧:if(mCurrentFrame.mvKeys.size()>100)  //特征点个数要大于100个{mInitialFrame = Frame(mCurrentFrame);mLastFrame = Frame(mCurrentFrame);mvbPrevMatched.resize(mCurrentFrame.mvKeysUn.size());  //调整vector的大小for(size_t i=0; i<mCurrentFrame.mvKeysUn.size(); i++)mvbPrevMatched[i]=mCurrentFrame.mvKeysUn[i].pt;    //存储了mInitialFrame中哪些点将进行接下来的匹配if(mpInitializer)delete mpInitializer;mpInitializer =  new Initializer(mCurrentFrame,1.0,200);//这里实例化Initialize类的一个对象指针,初始化的值为选取的当前帧和测量误差1.0,RANSAC迭代次数200fill(mvIniMatches.begin(),mvIniMatches.end(),-1);return;}对于第二帧:if((int)mCurrentFrame.mvKeys.size()<=100)    特征点个数要大于100个,如果小于100,初始化失败,程序返回图像帧处理入口。{delete mpInitializer;mpInitializer = static_cast<Initializer*>(NULL);fill(mvIniMatches.begin(),mvIniMatches.end(),-1);return;}ORBmatcher matcher(0.9,true);//对两帧的特征点进行匹配,参数:第一帧(初始帧),第二帧(当前帧),前一帧的特征点,两帧匹配特征点的索引,窗口大小(此参数不太了解)int nmatches = matcher.SearchForInitialization(mInitialFrame,mCurrentFrame,mvbPrevMatched,mvIniMatches,100);if(nmatches<100)    //如果匹配对数小于100,不能初始化成功,即初始化失败,程序返回图像帧入口。{delete mpInitializer;mpInitializer = static_cast<Initializer*>(NULL);return;}mpInitializer->Initialize(mCurrentFrame, mvIniMatches, Rcw, tcw, mvIniP3D, vbTriangulated)  //当初始化的条件满足之后,执行初始化。//初始化成功之后,将会删除初始化操作中三角化未成功的匹配点对,然后建立初始地图。 CreateInitialMapMonocular();
//至此,单目初始化的流程已全部走完,具体实现后续讨论。

在初始化成功之后,后续到来的帧,利用下面的代码构建帧Frame对象(前面已经提到过,这里再讲一下)。

mCurrentFrame = Frame(mImGray,timestamp,mpORBextractorLeft,mpORBVocabulary,mK,mDistCoef,mbf,mThDepth);

构建了帧Frame的对象之后,执行Track()。
接下来进行跟踪ORB-SLAM中关于跟踪状态有两种选择(由mbOnlyTracking判断)
1 只进行跟踪不建图,此时mbOnlyTracking为true
2 同时跟踪和建图,此时mbOnlyTracking为false。
初始化之后ORB-SLAM有三种跟踪模型可供选择
(a) TrackWithMotionModel(); 运动模型:根据运动模型估计当前帧位姿,根据匀速运动模型对上一帧的地图点进行跟踪,优化位姿。
(b) TrackReferenceKeyFrame(); 关键帧模型:BoW搜索当前帧与参考帧的匹配点,将上一帧的位姿作为当前帧的初始值,通过优化3D-2D的重投影误差来获得位姿。
(c)Relocalization();重定位模型:计算当前帧的BoW,检测满足重定位条件的候选帧,通过BoW搜索当前帧与候选帧的匹配点大于15个点就进行PnP位姿估计并优化。

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();  // 检查并更新上一帧被替换的MapPoints,更新Fuse函数和SearchAndFuse函数替换的MapPointsif(mVelocity.empty() || mCurrentFrame.mnId<mnLastRelocFrameId+2)  //当运动模型是空的,或者刚刚使用重定位{bOK = TrackReferenceKeyFrame();   //使用参考关键帧模型跟踪}else{bOK = TrackWithMotionModel();  //使用运动模型跟踪if(!bOK)     //如果使用运动模型跟踪失败bOK = TrackReferenceKeyFrame();   //使用参考关键帧模型}}else   //{bOK = Relocalization();  //重定位}}
else    //只跟踪,不建图{if(mState==LOST){bOK = Relocalization();}else{if(!mbVO){if(!mVelocity.empty()){bOK = TrackWithMotionModel();}else{bOK = TrackReferenceKeyFrame();}}else   这一部分的内容在mbVO=true的时候执行,具体不是太清楚,后续在研究。{// 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;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;}  这一部分的内容在mbVO=true的时候执行,具体不是太清楚,后续在研究}}

在相应的跟踪状态下,采用相应的跟踪模型得到姿态初始估计之后,跟踪LocalMap,得到更多的匹配,并优化当前位姿。LocalMap:当前帧、当前帧的MapPoints、当前关键帧与其它关键帧共视关系,在步骤2.1中主要是两两跟踪(恒速模型跟踪上一帧、跟踪参考帧),这里搜索局部关键帧后搜集所有局部MapPoints,然后将局部MapPoints和当前帧进行投影匹配,得到更多匹配的MapPoints后进行Pose优化

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();
}

在TrackLocalMap()之后;更新恒速运动模型TrackWithMotionModel中的mVelocity。

if(!mLastFrame.mTcw.empty(){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;}

判断是否要新加关键帧。

if(NeedNewKeyFrame())CreateNewKeyFrame();

至此,orb-slam2的track线程基本走完,本文着重讨论的track线程的流程梳理。每个流程的具体实现的函数及代码在后续博客中讨论,其中包括:

///  ORBextracor的构造函数
mpORBextractorLeft = new ORBextractor(nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);
mpIniORBextractor = new ORBextractor(2*nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);
///  提取ORB特征的重载运算符()
(*mpORBextractorLeft)(im,cv::Mat(),mvKeys,mDescriptors);
///   特征点匹配函数
int nmatches = matcher.SearchForInitialization(mInitialFrame,mCurrentFrame,mvbPrevMatched,mvIniMatches,100);
// 初始化函数
mpInitializer->Initialize(mCurrentFrame, mvIniMatches, Rcw, tcw, mvIniP3D, vbTriangulated)
//建立初始单目地图
CreateInitialMapMonocular();
//   三种跟踪模型
TrackReferenceKeyFrame()
TrackWithMotionModel()Relocalization()
/// 跟踪局部地图
TrackLocalMap()
///  判断是否要加关键帧以及如何创建关键帧
if(NeedNewKeyFrame())CreateNewKeyFrame();

ORB-SLAM2梳理——track线程(一)相关推荐

  1. ORB_SLAM3 Track线程详解

    概述 ORB-SLAM3 是第一个同时具备纯视觉(visual)数据处理.视觉+惯性(visual-inertial)数据处理.和构建多地图(multi-map)功能,支持单目.双目以及 RGB-D ...

  2. ORB SLAM2源码解读(三):Frame类

    文章目录 前言 构造函数 双目相机 RGBD相机 单目相机 ExtractORB:提取特征点 ComputeBoW:计算词袋数据 SetPose:设置相机外参 isInFrustum:判断一个MapP ...

  3. orbslam2可视化_[Ubuntu] ORB SLAM2 编译调试

    ORB SLAM2 是 2015年比较受到关注的一篇文章,它的主要思想是借助 ORB 描述子改进了 Sparse SLAM 的性能,使得其在稳定性和速度上都达到了比较好的程度.从创新性上来讲,它的主要 ...

  4. Ubuntu下使用单目相机运行ORB SLAM2

    环境:Ubuntu16.04+ROS Kinetic+USB单目摄像头 虽然ORB SLAM2的官方说明中表示没有ROS也可以编译运行,但要实时的跑ORB SLAM2还是需要ROS平台的,所以之前没有 ...

  5. 新手入门新电脑安装配置orb slam2 一步到位不踩坑(ubutun18.04)

    目录 一.安装基础工具 二.安装Pangolin,作为可视化和用户界面 三.安装OpenCV,用于处理图像和特征 (1)下载OpenCV 3.4.1 (2)安装依赖项 (3)编译安装 (4)配置环境, ...

  6. Ubuntu 16.04~ORB SLAM2~Kinect v1

    额 Ubuntu16.04 ORB-SLAM2实现(kinect V1/ROS) ----------------------------------------------------------- ...

  7. Ubuntu14.04 使用本地摄像头跑ORB SLAM2

    嗯 这个方法我暂时弄不出来,用了另外一个方法:SLAM14讲 第一次课 使用摄像头或视频运行 ORB-SLAM2 前面的准备: Ubuntu14.04安装 ROS 安装步骤和问题总结 Ubuntu14 ...

  8. 视觉SLAM融合GPS尝试

    一.前言 最近在做无人机建图的相关工作,基本的方案是ORB SLAM2+Map2DFusion. 在调试好代码后,我利用大疆精灵4在附近的一个公园进行算法测试,得到的效果图如下: 但在一些细节上会有明 ...

  9. orb特征 稠密特征_一种基于ORB-SLAM2的双目三维稠密建图方法技术

    本发明专利技术公开了一种基于ORB‑SLAM2的双目稠密建图方法,涉及机器人同步定位与地图创建领域,该方法主要由跟踪线程.局部地图线程.闭环检测线程和稠密建图线程组成.其中稠密建图线程包含以下步骤:1 ...

最新文章

  1. 欧拉路径 之 poj 2513 Colored Sticks
  2. OpenKruise v0.5.0 版本发布,支持无损的流式分批发布策略
  3. oracle查询某个用户下的所有视图
  4. stanford-chinese-corenlp-yyyy-MM-dd-models.jar not exists解决
  5. Android 获取系统或SDCARD剩余空间信息(转)
  6. c oracle日志分析,oracle 日志分析
  7. [置顶文章]李迟读书记
  8. 如何实现手动指定AOP实现JDK代理模式到CGLIB的更改?
  9. Unity开发手游的实用插件
  10. 词干提取(stemming)和词形还原(lemmatization)比较
  11. Android开发工程师已难找工作
  12. 查看已下载的Docker镜像latest具体版本
  13. 清北毕业生5年来去向大数据:北大偏爱银行,清华更倾向国网,华为堪称最大黑洞-1
  14. java pdf替换内容_Java添加、提取、替换和删除PDF图片
  15. WIN7截图工具灵活使用
  16. Excel公式-文本查找函数
  17. python绘制旭日图
  18. lawson算法_案例研究:Lawson合并后整合架构的新方法
  19. 利用Python将csv文件按照某列分成小csv
  20. 2016 ACM ICPC Asia Region - Tehran

热门文章

  1. hive创建永久函数失败,Failed to register youmeng.finderrorcount using class com.jinghang.hive.MyCoustom
  2. MySQL使用索引的正确方式你知道吗?
  3. 2020同济大学计算机学院,同济大学2020年各省录取分数线
  4. 计算错题集(有错误就加入错题集,持续更新)
  5. Core Dump 程序故障分析
  6. SpringCloud工程搭建之业务微服务搭建(必选)
  7. python跨文件调用lambda函数_python基础-4 函数参数引用、lambda 匿名函数、内置函数、处理文件...
  8. 计算机光驱打不开是什么原因,电脑光驱打不开怎么办 电脑光驱打不开解决方法...
  9. Java:实训五 常用实用类应用
  10. 西门子S7系列PLC如何实现工业互联?(S7中间件)