ORB-SLAM 代码笔记(四)tracking代码结构
首先要清楚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 ×tamp)
{
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代码结构的更多相关文章
- SQL COOKBOOK SQL经典实例代码 笔记第一章代码
-- SQL COOKBOOK CHAPTER1 -- 查看所有内容 select * from emp; -- 可以单列 select empno,ename,job,sal,mgr,hiredat ...
- HTML5学习笔记四:html5结构
一.大纲:大纲即文档中各内容区块的结构编排 1. 显示编排内容区块:使用section等元素创建文档结构,每个内容区块使用标题(h1~h6,hgroup); 2. 隐式编排内容区块:根据页面所书写的各 ...
- 《OOC》笔记(4)——自动化地将C#代码转化为C代码(结构版)
<OOC>笔记(4)——自动化地将C#代码转化为C代码(结构版) 我在<C表达面向对象语言的机制——C#版>中已经说明了从C#到C的转换方法.这次看<OOC>也是想 ...
- jQuery 学习笔记:jQuery 代码结构
jQuery 学习笔记:jQuery 代码结构 这是我学习 jQuery 过程中整理的笔记,这一部分主要包括 jQuery 的代码最外层的结构,写出来整理自己的学习成果,有错误欢迎指出. jQuery ...
- 【hadoop代码笔记】Mapreduce shuffle过程之Map输出过程
一.概要描述 shuffle是MapReduce的一个核心过程,因此没有在前面的MapReduce作业提交的过程中描述,而是单独拿出来比较详细的描述. 根据官方的流程图示如下: 本篇文章中只是想尝试从 ...
- 【hadoop代码笔记】hadoop作业提交之汇总
一.概述 在本篇博文中,试图通过代码了解hadoop job执行的整个流程.即用户提交的mapreduce的jar文件.输入提交到hadoop的集群,并在集群中运行.重点在代码的角度描述整个流程,有些 ...
- Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果
Python 1行代码实现文本分类(实战笔记),含代码详细说明及运行结果 一.详细说明及代码 tc.py =============================================== ...
- 0037 Java学习笔记-多线程-同步代码块、同步方法、同步锁
什么是同步 在上一篇0036 Java学习笔记-多线程-创建线程的三种方式示例代码中,实现Runnable创建多条线程,输出中的结果中会有错误,比如一张票卖了两次,有的票没卖的情况,因为线程对象被多条 ...
- 【Hadoop代码笔记】目录
整理09年时候做的Hadoop的代码笔记. 开始. [Hadoop代码笔记]Hadoop作业提交之客户端作业提交 [Hadoop代码笔记]通过JobClient对Jobtracker的调用看详细了解H ...
- <Python Text Processing with NLTK 2.0 Cookbook>代码笔记
如下是<Python Text Processing with NLTK 2.0 Cookbook>一书部分章节的代码笔记. Tokenizing text into sentences ...
随机推荐
- Android(java)学习笔记35:如何改变Spinner系统自带的字体和颜色
1. 首先我们要知道Spinner系统自带字体和颜色本质: 原生的Spring 控件是无法更改字体和颜色的... 从下面的代码可以看出...红色的标注显示使用的是Android默认的布局.. Spin ...
- 【转】 Android Fragment 真正的完全解析(下)
转载请标明出处:http://blog.csdn.net/lmj623565791/article/details/37992017 上篇博客中已经介绍了Fragment产生原因,以及一些基本的用法和 ...
- ASP.NET SignalR 与LayIM配合,轻松实现网站客服聊天室(七)之 图文,附件消息(2016-05-05 12:13)
上一篇介绍了加好友的流程,这里不再赘述,不过之前的聊天只能发送普通文字,那么本篇就教你如何实现发送附件和图片消息.我们先对功能进行分析: 发送图片,附件,需要实现上传图片和附件的功能. textare ...
- vue案列
<!DOCTYPE html> <html> <head> <meta charset="utf-8"> <title> ...
- 【洛谷P2296】[NOIP2014]寻找道路
寻找道路 题目链接 这道题非常的水,按照题意, 先反向建边,从终点搜索,标记出可以到达终点的点 然后枚举一遍,判断出符合条件1的点 再从起点搜索一遍就可以了 #include<iostream& ...
- plsql Developer11的工具栏没有了如何找回来
以前都是用的plsql developer7,最常用的工具类如下: 这次下载了12,发现风格变了,经常用的执行.提交.回滚按钮都在会话菜单下了 如何找回工具栏呢,如下操作:
- 关于css透明度的问题
先看background和background-color background:可以设置背景颜色,背景图片,还有定位.默认background:no-repeat; background-color ...
- Linux环境下利用句柄恢复Oracle误删除的数据文件
在误删除Oracle的数据文件后,如果未关闭数据库,文件句柄还没有释放,且被删除的数据文件占用的磁盘块未被复写,则可以利用句柄的方式来恢复数据文件.下面模拟恢复过程. (一)环境 OS版本:redha ...
- LCA最近公共祖先——Tarjan模板
LCA(Lowest Common Ancestors),即最近公共祖先,是指在有根树中,找出某两个结点u和v最近的公共祖先. Tarjan是一种离线算法,时间复杂度O(n+Q),Q表示询问次数,其中 ...
- 字符串拼接在Oracle和mysql中的用法
oracle拼接字符串 1.使用 '||' 或者 concat(参数1,参数2) select 'aa' || 'bb' || 'cc' from dual; 结果:aabbcc select co ...