首先要清楚ORB-SLAM视觉跟踪的原理,然后对tracking.cc中的函数逐个讲解

代码的前面部分是从配置文件中读取校准好的相机参数(内参和畸变参数,以及双目的深度测量设定),并且加载ORB特征点提取的参数(特征点数,金字塔层数,变化尺度,以及提取Fast关键点的阈值);以及四个线程之间锁的代码。

接下来是将从摄像头或者数据集读入的图像封装成Frame类型对象:

这里以单目为例,无论图片是RGB,BGR, 还是RGBA,BGRA,均转化为灰度图,放弃彩色信息。然后将当前读入帧封装为Frame类型的mCurrentFrame对象;为了让单目成功初始化(单目的初始化需要通过平移运动归一化尺度因子),初始化时mpIniORBextractor提取的特征点数量设定为普通帧的2倍。

mpIniORBextractor = new ORBextractor(*nFeatures,fScaleFactor,nLevels,fIniThFAST,fMinThFAST);

有了mCurrentFrame对象,就可以进入跟踪模块(tracking()函数), 经过一系列跟踪处理(重点),可以返回当前帧的位姿。

cv::Mat Tracking::GrabImageMonocular(const cv::Mat &im, const double &timestamp)
{
mImGray = im; if(mImGray.channels()==)
{
if(mbRGB)
cvtColor(mImGray,mImGray,CV_RGB2GRAY);
else
cvtColor(mImGray,mImGray,CV_BGR2GRAY);
}
else if(mImGray.channels()==)
{
if(mbRGB)
cvtColor(mImGray,mImGray,CV_RGBA2GRAY);
else
cvtColor(mImGray,mImGray,CV_BGRA2GRAY);
} 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(); return mCurrentFrame.mTcw.clone();
}

具体的tracking步骤如下:

(1)初始化

首先是初始化,分为双目、RGBD,以及单目两种不同的初始化过程,单目的初始化需要注意的较多,可以先看void Tracking::StereoInitialization()函数:

如果检测到的特征点数 N>500,则将当前帧构建为第一个关键帧,关键帧通过当前帧,地图点,以及BoW构建;同时,mpMap地图中也需要加入该关键帧(mpMap包含图像帧以及相应的地图点), 对每一个特征点,通过反投影得出3D地图点,地图点中通过3D位置信息,对应的关键帧,以及mpMap构建。

这其中的关系有点让人混乱,其实直观地去理解很容易:

mpMap就是我们整个位姿与地图(可以想象成ORB-SLAM运行时的那个界面世界),MapPoint和KeyFrame都被包含在这个mpMap中。因此创建这三者对象(地图,地图点,关键帧)时,三者之间的关系在构造函数中不能缺少。另外,由于一个关键帧提取出的特征点对应一个地图点集,因此需要记下每个地图点的在该帧中的编号;同理,一个地图点会被多帧关键帧观测到,也需要几下每个关键帧在该点中的编号。

地图点,还需要完成两个运算,第一个是在观测到该地图点的多个特征点中(对应多个关键帧),挑选出区分度最高的描述子,作为这个地图点的描述子;

pNewMP->ComputeDistinctiveDescriptors();

第二个是更新该地图点平均观测方向与观测距离的范围,这些都是为了后面做描述子融合做准备。

pNewMP->UpdateNormalAndDepth();

最后,还需要在局部地图中(为了实现局部Bundle Adjustment)插入当前关键帧,还需要初始化局部关键帧和局部地图点。将上一帧,上一关键帧,以及上一关键帧Id号初始化为当前帧。参考关键帧,当前帧的参考关键帧,当前地图中的参考地图点(集),并初始化当前相机姿态。

void Tracking::StereoInitialization()
{
if(mCurrentFrame.N>)
{
// Set Frame pose to the origin
mCurrentFrame.SetPose(cv::Mat::eye(,,CV_32F)); // Create KeyFrame
KeyFrame* pKFini = new KeyFrame(mCurrentFrame,mpMap,mpKeyFrameDB); // Insert KeyFrame in the map
mpMap->AddKeyFrame(pKFini); // Create MapPoints and asscoiate to KeyFrame
for(int i=; i<mCurrentFrame.N;i++)
{
float z = mCurrentFrame.mvDepth[i];
if(z>)
{
cv::Mat x3D = mCurrentFrame.UnprojectStereo(i);
MapPoint* pNewMP = new MapPoint(x3D,pKFini,mpMap);
pNewMP->AddObservation(pKFini,i);
pKFini->AddMapPoint(pNewMP,i);
pNewMP->ComputeDistinctiveDescriptors();
pNewMP->UpdateNormalAndDepth();
mpMap->AddMapPoint(pNewMP); mCurrentFrame.mvpMapPoints[i]=pNewMP;
}
} cout << "New map created with " << mpMap->MapPointsInMap() << " points" << endl; mpLocalMapper->InsertKeyFrame(pKFini); mLastFrame = Frame(mCurrentFrame);
mnLastKeyFrameId=mCurrentFrame.mnId;
mpLastKeyFrame = pKFini; mvpLocalKeyFrames.push_back(pKFini);
mvpLocalMapPoints=mpMap->GetAllMapPoints();
mpReferenceKF = pKFini;
mCurrentFrame.mpReferenceKF = pKFini; mpMap->SetReferenceMapPoints(mvpLocalMapPoints); mpMap->mvpKeyFrameOrigins.push_back(pKFini); mpMapDrawer->SetCurrentCameraPose(mCurrentFrame.mTcw); mState=OK;
}
}

单目的初始化则相对负责,放在下一篇笔记中去讲。

ORB-SLAM 代码笔记(四)tracking代码结构的更多相关文章

  1. SQL COOKBOOK SQL经典实例代码 笔记第一章代码

    -- SQL COOKBOOK CHAPTER1 -- 查看所有内容 select * from emp; -- 可以单列 select empno,ename,job,sal,mgr,hiredat ...

  2. HTML5学习笔记四:html5结构

    一.大纲:大纲即文档中各内容区块的结构编排 1. 显示编排内容区块:使用section等元素创建文档结构,每个内容区块使用标题(h1~h6,hgroup); 2. 隐式编排内容区块:根据页面所书写的各 ...

  3. 《OOC》笔记(4)——自动化地将C#代码转化为C代码(结构版)

    <OOC>笔记(4)——自动化地将C#代码转化为C代码(结构版) 我在<C表达面向对象语言的机制——C#版>中已经说明了从C#到C的转换方法.这次看<OOC>也是想 ...

  4. jQuery 学习笔记:jQuery 代码结构

    jQuery 学习笔记:jQuery 代码结构 这是我学习 jQuery 过程中整理的笔记,这一部分主要包括 jQuery 的代码最外层的结构,写出来整理自己的学习成果,有错误欢迎指出. jQuery ...

  5. 【hadoop代码笔记】Mapreduce shuffle过程之Map输出过程

    一.概要描述 shuffle是MapReduce的一个核心过程,因此没有在前面的MapReduce作业提交的过程中描述,而是单独拿出来比较详细的描述. 根据官方的流程图示如下: 本篇文章中只是想尝试从 ...

  6. 【hadoop代码笔记】hadoop作业提交之汇总

    一.概述 在本篇博文中,试图通过代码了解hadoop job执行的整个流程.即用户提交的mapreduce的jar文件.输入提交到hadoop的集群,并在集群中运行.重点在代码的角度描述整个流程,有些 ...

  7. Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果

    Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果 一.详细说明及代码 tc.py =============================================== ...

  8. 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁

    什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...

  9. 【Hadoop代码笔记】目录

    整理09年时候做的Hadoop的代码笔记. 开始. [Hadoop代码笔记]Hadoop作业提交之客户端作业提交 [Hadoop代码笔记]通过JobClient对Jobtracker的调用看详细了解H ...

  10. <Python Text Processing with NLTK 2.0 Cookbook>代码笔记

    如下是<Python Text Processing with NLTK 2.0 Cookbook>一书部分章节的代码笔记. Tokenizing text into sentences ...

随机推荐

  1. Android(java)学习笔记40:WindowManager 中LayoutParams的各种属性

    1. WindowManager 中LayoutParams的各种属性 WindowManager.LayoutParams 是 WindowManager 接口的嵌套类(内部类):它继承于 View ...

  2. SPOJ MUSKET - Musketeers

    黑书P117页. 要是不看解析,确实不要算和定义状态. 把环看成链,是指把这个1234512345,写两边,然后怎么表示一个人是否胜利了呢?其实就是其他人全部死光(好像等于没说): 考虑最后一次杀人, ...

  3. HDU 5675 智慧数

    题意:给一个n ,能否找到正整数x,y使得 x^2 -y^2 = n: 分析:打表可以找出规律,3,5,7,9....,8,12,16,20..... 和奇数,4的倍数有关. 数学证明:

  4. PS中会使用到的快捷键有那些?

    P.S:我刚刚在百度上,搜了一些关于PS的快捷键的使用. 我把它总结了一下.对我今后的P图有所帮助. PS的所有快捷键 1. 显示/隐藏选择区域 [Ctrl]+[H] 2. 取消当前命令:Esc: 工 ...

  5. PSROIAlign的代码实现

    https://github.com/afantideng/R-FCN-PSROIAlign

  6. caffe卷积层实现

    下图是jiayangqing在知乎上的回答,其实过程就是把image转换成矩阵,然后进行矩阵运算 卷积的实现在conv_layer层,conv_layer层继承了base_conv_layer层,ba ...

  7. c#用链表存储并读取配置文件(代码部分)

    //读取配置参数 private void loadcofig() { //List<param> camra1 = new List<param>(); List<st ...

  8. Tomcat 服务器体系结构

    connector 监听端口,监听到以后,交给 Engine 引擎 处理,引擎会根据请求找到对应的主机,找到主机后再去找对应的应用. 如果我们将 port 改为 80,那访问的时候就不用输入端口号,因 ...

  9. windows下搭建python

    windows下搭建python 下载python版本  https://www.python.org/   注意当前操作系统的位数,32位还是64位 同时   安装后  修改环境变量         ...

  10. Spring知识点总结(三)之Spring DI

    1. IOC(DI) - 控制反转(依赖注入) 所谓的IOC称之为控制反转,简单来说就是将对象的创建的权利及对象的生命周期的管理过程交由Spring框架来处理,从此在开发过程中不再需要关注对象的创建和 ...