本周课程学前准备:
1. Ubuntu
操作系统,不建议装虚拟机。版本
16.04
、
18.04
、
20.04
均可 win10 + Ubuntu18.04 双系统安装教程可参考:
https://www.cnblogs.com/masbay/p/10844857.html
https://www.jianshu.com/p/fe4e3915495e
https://www.cnblogs.com/tanrong/p/9166595.html
Linux
入门教程:
鸟哥的
Linux
私房菜
--
基础学习篇
http://cn.linux.vbird.org/linux_basic/linux_basic.php
Linux
命令 快速索引
http://cn.linux.vbird.org/linux_basic/1010index.php
本周课程重点
:
1. 熟悉Ubuntu操作系统,掌握Linux基础语法。
2. 初步了解ORB-SLAM2的优点及应用。
3. 成功编译并运行ORB-SLAM2 单目模式。
4. 掌握ORB特征及均匀化原理及实现。
1. ORB_SLAM 2简介
1.1 ORB_SLAM 2简介
首个(
2017
年发布时)支持单目,双目和
RGB-D
相机的完整的开源
SLAM
方案,具有回环检测和重 新定位的功能。 能够在CPU
上进行实时工作,可以用于移动终端如 移动机器人、手机、无人机、汽车。
特征点法的巅峰之作,定位精度极高,可达厘米级。 能够实时计算出相机的位姿,并生成场景的稀疏三维重建地图。 代码非常工整,可读性强,包含很多实际应用中的技巧,非常实用。 支持仅定位模式,该模式适用于轻量级以及在地图已知情况下长期运行,此时不使用局部建图和回 环检测的线程。 双目和RGB-D
相对单目相机的主要优势在于,可以直接获得深度信息,不需要像单目情况中那样 做一个特定的SFM
初始化。
1.2 ORB_SLAM2 框架
主体框架
数据输入的预处理
为了兼容不同相机(双目相机与
RGBD
相机)
,
需要对输入数据进行预处理,使得交给后期处理的数据格式一致(
这一点做的很好,兼容性很好
),具体流程如下:
2. TUM 数据集使用
2.1 ORB_SLAM2 在TUM数据集上的表现
2.2 TUM RGB-D 数据集 简介
注意两点:深度的表达方式 以及 数据的存储格式
2.3 运行RGBD模式时的预处理
关于
associate.py , 注意:只能在Python2
环境下运行
Python
下运行
python associate.py rgb.txt depth.txt > associate.txt
python associate.py associate.txt groundtruth.txt > associate_with_groundtruth.txt
注意:
直接
association
后出问题,生成的结果 associate.txt 1641行; associate_with_groundtruth.txt 1637行;也就是说,associate
的不一定有
groundtruth
,所以要以
associate_with_groundtruth.txt
的关联结果 为准
2.4. 不同颜色地图点的含义
红色
点表示参考地图点,其实就是
tracking
里的
local mappoints
void Tracking::UpdateLocalMap()
{ // This is for visualization
mpMap->SetReferenceMapPoints(mvpLocalMapPoints);
// Update UpdateLocalKeyFrames();
UpdateLocalPoints();
}
黑色
点表示所有地图点,红色点属于黑色点的一部分
3. ORB 特征
3.1 FAST关键点
1、选取像素p,假设它的亮度为Ip;设置一个阈值T(比如Ip的20%);
2、以像素p为中心,选取半径为3的圆上的16个像素点;
3、假如选取的圆上,有连续的N个点的亮度大于Ip+T或小于Ip-T,那么像素p可以被认为是特征点;
4、循环以上4步,对每一个像素执行相同操作。
3.2 BRIEF 特征
https://blog.csdn.net/hltt3838/article/details/105912580
论文:
BRIEF: Binary Robust Independent Elementary Features
BRIEF
算法的核心思想是在
关键点P的周围以一定模式选取N个点对,把这
N个点对的比较结果
组合起来作为描述子
。为了保持踩点固定,工程上采用特殊设计的固定的
pattern
来做
问题1: FAST特征点的数量很多,并且不是确定,而大多数情况下,我们希望能够固定特征点的数量。
解决方法: 在ORB当中,我们可以指定要提取的特征点数量。对原始的FAST角点分别计算Harris的响应值,然后选取前N个点具有最大相应值的角点,作为最终角点的集合。
问题2: FAST角点不具有方向信息和尺度问题。
解决方法: 尺度不变性构建的图像的金字塔,并且从每一层上面来检测角点。
灰度质心法: 质心是指以图像块灰度值作为权重的中心。(目标是为找找到方向:几何中心 ——> Q为灰度质心).
理解:为什么要考虑尺度的问题? 因为相机在运动的过程中,可能离物体越来越远或者越来越近,这时候出现的情况是:近看图像上的特征点,在远看图像上就没有啦,因为图像的平滑,那么更别说特征点的匹配了! 为了让它们能匹配上,需要对图构建尺度空间,获得图片不同尺度下的表达,并获取特征点,具体的做法就是图像的金字塔。比如:我们要提取1000个特征点,而金字塔的层数是8,把这1000个特征点按照面积比例分别在 每层图像提取,这样的话就是说在不同尺度的图片上都能提取到特征点,这样就可以解决前面说的 “相机在运动的过程中,可能离物体越来越远或者越来越近,这时候出现的情况是:近看图像上的特征点,在远看图像上就没有啦” 问题!
参考:https://blog.csdn.net/RobotLife/article/details/87194017?utm_medium=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control&dist_request_id=48c2bb06-67c0-42b6-8a5d-4ead425a80a7&depth_1-utm_source=distribute.pc_relevant.none-task-blog-BlogCommendFromMachineLearnPai2-3.control 具体的理解可以看后面的内容+代码理解!
3.3 ORB 特征
原始的
FAST
关键点没有方向信息,这样当图像发生旋转后,
brief
描述子也会发生变化(
图像的灰度值可能发生改变
) ,使得特征点对旋转不鲁棒 ;
解决方法:
orientated FAST ,使用灰度质心法计算特征点的方向,
什么是灰度质心法?
在一个圆内计算灰度质心 ,下图P为几何中心,Q为灰度质心
https://blog.csdn.net/qq_18661939/article/details/52900524
理解:半径为R的圆内,选取 FAST关键点,描述子, 且在圆内质心是唯一的,不变的,那么 特征点和质心的连接便可以确定方向 !
至此,不仅仅提取了FAST角点,还找出了角点的角度。这个角度可以用来指导描述子的提取,保证每次都在相同的方向上计算描述子,实现角度不变性。
这就是Oriented FAST。
有的人看到上面的解释后,可能还不理解为什么灰度质心法为什么保证了图像的旋转不变性,下面进行更加详细的解析! 仔细理解!
其中 x、y为图像块中的像素在关键点坐标系中的坐标。需要知道,当图片旋转时,图像块(方格区域)的质心在图像块中的位置并未改变 (
质心在垂直坐标系中的坐标是变化的)。
上图表示,
在FAST关键点的基础上,进行描述子的计算时,当图像发生旋转后,图像上的随机像素对的坐标将会发生变化,使得描述子的差异很大,非常影响后期的特征匹配。如何能够让图片发生旋转时,所选的随机像素对的坐标不发生改变呢?如下图所示:
我们知道,ORB在进行FAST角点提取时,计算出了关键点的方向,上图左的向量OC,方向角为θ。
前面我们说过,
当图片发生旋转时,质心在图像块中的位置不变,因此,我们可以
将随机像素对在FAST关键点坐标系中的坐标(垂直坐标系)通过旋转θ角度,转换为其在Oriented FAST关键点坐标系中的坐标(向量OC为x轴的坐标系) (这一步才是关键),上图中的左图表示了坐标关系,而右图则表示,当图片旋转时,随机像素对在虚线坐标系(以向量OC为x轴坐标系)中的坐标不变,即旋转不变性。
下面求圆内的坐标范围 ,umax:
1/4
圆的每一行的
u
轴坐标边界(下图中橙色线段
FG
)
cvFloor 返回不大于参数的最大整数值, cvCeil 返回不小于参数的最小整数值,cvRound 则是四舍五入
vmax = cvFloor(HALF_PATCH_SIZE * sqrt(2.f) / 2 + 1);
vmin = cvCeil(HALF_PATCH_SIZE * sqrt(2.f) / 2);
// 对应从D到B的红色弧线,umax坐标从D到C
for (v = 0; v <= vmax; ++v)
umax[v] = cvRound(sqrt(hp2 - v * v)); // 勾股定理,hp2 是半径
// 对应从B到E的蓝色弧线,umax坐标从C到A
for (v = HALF_PATCH_SIZE, v0 = 0; v >= vmin; --v)
{
while (umax[v0] == umax[v0 + 1]) ++v0;
umax[v] = v0;
++v0;
}
参考:
https://blog.csdn.net/liu502617169/article/details/89423494
https://www.cnblogs.com/wall-e2/p/8057448.html
问题:Umax和Vmax这些到底有什么用?
答案:主要是确定圆内横纵坐标的边界用的,方便索引像素值。这部分有点麻烦,详见课程第2讲; 认真理解一下,我们在索引像素值的时候,一定是个 for() 循环,那这个for() 循环的的边界值是多大?就是用这个方法确定的! 有人可能会说,边界值是R呀,但是你想一下,像素点的坐标 u,v轴是存在一个关系的,没有必要每次都最大范围R的搜索!
3.4 为什么要重载小括号运算符 operator() ?
可以用于仿函数(一个可以实现函数功能的对象) ,仿函数(functor
)又称为函数对象(
function object
)是一个能行使函数功能的类。仿函数的语法几乎和我们普通的函数调用一样,不过作为仿函数的类,都必须重载operator()
运算符
1.
仿函数可有拥有自己的数据成员和成员变量,这意味着这意味着仿函数拥有状态。这在一般函数中是 不可能的。
2.
仿函数通常比一般函数有更好的速度。
扩展阅读
https://blog.csdn.net/jinzhu1911/article/details/101317367
3.5 金字塔的计算
ORBextractor::ComputePyramid
尺度不变的理解:在orb_slam2中,为了实现特征尺度不变性采用了图像金字塔,金字塔的缩放因子为1.2, 其思路就是对原始图形(第0层)依次进行1/1.2缩放比例进行降采样得到共计8张图片(包括原始图像),然后分别对得到的图像进行特征提取,并记录特征所在金字塔的第几层,这样得到一帧图像的特征点。现在假设在第二层中有一特征点F,为了避免缩放带来特征点F在纵向的移动,为简化叙述,选择的特征点F位于图像中心。根据相机成像 “物近像大,物远像小” 的原理,假设 摄像机原始图像即金字塔第0层对应图2中成像视野I0 ,则图像金字塔第2层图像可以相应对应于图中成像视野I2 。其中特征点F所在patch的相应关系。根据得到 结论1: d2 / d0 = 1.22 。
有了以上铺垫现在,来说说,尺度不变性,这里不直接说明,而是看看对于第m层上的一个特征点,其对应尺度不变时相机与特征点对应空间位置之间距离(简称物距)的范围。假设第m层上有一特征点Fm,其空间位置与拍摄时相机中心的位置为dm ,显然这是原始图像缩放1/1.2m倍后得到的特征点patch,考虑 “物远像小” 的成像特点,要使得该第m层特征点对应patch变为图像金字塔第0层中同样大小的patch,其相机与空间点的距离d=dm * 1.2m ,即尺度不变的最大物距 dmax = dm*1.2m 。要求尺度不变的最小物距则这样考虑:根据 “物近像大” 的成像特点,使得当前第m层的特征点移到第7层上则,真实相机成像图像得放大1.27-m倍,故对应最小物距dmin=dm *1.2m-7 。
3.6 特征点数量的分配计算
来自:
https://zhuanlan.zhihu.com/p/61738607
3.7 使用四叉树对金字塔每一图层中的特征点进行平均和分发
DistributeOctTree
1、如果图片的宽度比较宽,就先把分成左右
w/h
份;一般的
640×480
的图像开始的时候只有一个 node。
2、如果
node
里面的点数
>1
,把每个
node
分成四个
node
,如果
node
里面的特征点为空,就不要了, 删掉。
3、新分的
node
的点数
>1
,就再分裂成
4
个
node
。如此,一直分裂。
4、终止条件为:
node
的总数量
> [
公式
]
,或者无法再进行分裂。
5、然后从每个
node
里面选择一个质量最好的
FAST
点。
参考:
https://zhuanlan.zhihu.com/p/61738607
ExtractorNode::DivideNode
节点分裂顺序:后加的先分裂
理解:
ORB-SLAM中并没有使用OpenCV的实现,因为OpenCV的版本提取的ORB特征过于集中,会出现扎堆的现象。这会降低SLAM的精度,对于闭环来说,也会降低一幅图像上的信息量。具体的对ORB-SLAM的影响可以参考我的另一篇文章 杨小东:[ORB-SLAM2] ORB特征提取策略对ORB-SLAM2性能的影响;ORB-SLAM中的实现提高了特征分布的均匀性。最简单的一种方法是把图像划分成若干小格子,每个小格子里面保留质量最好的n个特征点。这种方法看似不错,实际上会有一些问题。当有些格子里面能够提取的数量不足n个的时候(无纹理区域),整幅图上提取的特征总量就达不到我们想要的数量。严重的情况下,SLAM就会跟丢喽,ORB-SLAM中的实现就解决了这么一个问题,当一个格子提取不到FAST点的时候,自动降低阈值。ORB-SLAM主要改进了FAST角点提取步骤。
上面步骤的内容理解如下: