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 ...
随机推荐
- 2018_MCM_ICM_C
- 动态规划(DP),压缩状态,插入字符构成回文字符串
题目链接:http://poj.org/problem?id=1159 解题报告: 1.LCS的状态转移方程为 if(str[i-1]==str[j-1]) dp[i][j]=dp[i-1][j-1] ...
- Visual Studio C++ Win32控制台应用程序,Win32项目,MFC的区别
背景 Visual Studio C++ 创建新项目蹦出来如下选项: Win32控制台应用程序,Win32项目,MFC有什么区别? 正文: Win32控制台,没有界面,命令行执行生成的文件则直接在后台 ...
- axis调用cxf的webservice注意事项
需要注意的是: 1.wsdl显示部分内容 <?xml version="1.0" ?> - <wsdl:definitions name="Archiv ...
- Android学习笔记_3_四种布局
Android布局是应用界面开发的重要一环,在Android中,共有四种布局方式, 分别是:FrameLayout( 帧布局 ).LinearLayout (线性布局).TableLayout(表格布 ...
- LINQ 方法
过滤操作符 Where 运算符(Linq扩展方法)根据给定条件过滤集合. 在其中扩展方法有以下两个重载.一个过载需要Func <TSource,bool>输入参数和第二个重载方法需要Fun ...
- win7 bat copy 一个文件 到另外的文件夹内,路径得用引号哦
win 7 的 用引号 把路径引起来 ,但是win10 的可以不用哦 !
- VSS使用方法详解
Microsoft Visual SourceSafe是美国微软公司出品的版本控制系统,简称VSS.它提供了还原点和并行协作功能,从而使应用程序开发组织能够同时处理软件的多个版本.该版本控制系统引入了 ...
- kindeditor简单使用
<%@ page language="java" import="java.util.*" pageEncoding="utf-8"% ...
- js如何判断数据类型
1.最常见的判断方法:typeof console.log(typeof a) ------------> string console.log(typeof b) ------------&g ...