【理解】ORB特征提取与ORBSLAM特征匹配简要剖析

ORB特征提取

优势:

ORB:Orinted FAST+Rotated BRIEF
顾名思义:ORB特征是基于FAST特征的一个改进算法,它改进了FAST检测子不具有方向性的问题,在FAST特征提取的基础上加入了特征点的主方向。从而为后续的BRIEF描述子增添旋转不变的特征,同时构建图像金字塔实现尺度不变性。这样一来,图像帧与帧之间的特征匹配就变得容易许多,减少了特征点丢失,不匹配或误匹配的现象。

ORB特征提取采用速度极快的二进制描述子BRIEF,使得图像特征提取的速度大大提升。由原论文的测试数据可知(图1),每检测同一帧图像,ORB约要花费15.3ms,而SURF要花费217.3ms,SIFT特征提取则要花费5228.7ms,三者的差距是数量级的。因此基于其速度快的优势,ORB非常适合运用在如SLAM这样的实时系统

图一:
在这里插入图片描述

ORB特征提取总体分为两个步骤:

  1. FAST特征点提取,找出图像中的角点,并在FAST基础上计算了特征点的主方向。
  2. BRIEF(Binary Robust Independent Elementary Feature)描述子:对前一步提取出的特征点周围图像区域进行描述并记录。由于前一步的特征提取计算了特征点的方向,因此为BRIEF描述子增加了旋转不变性。

经典FAST特征提取:

提取思想:如果一个像素与邻域的像素灰度差别较大(过亮或过暗),那么它更可能是角点。

检测过程

  1. 在图像中提取像素p,设其灰度值为I_p
  2. 设定一个阈值T(假设为20%I_p)
  3. 以像素p为圆心,选取半径为三的圆边上的16个像素点。
  4. 假如选取的的圆上有连续N个点灰度值大于I_p+T或小于I_p-T,那么p可以被认为是特征点。(N通常取12,即FAST-12,常见的还有FAST-9和FAST-11)
  5. 循环以上四步,对图像中的每一个像素点执行相同的操作。

值得一提的是,图像中绝大多数像素点并不是角点,为了更高效的排除它们,我们可以添加一项预操作来优化检测算法
具体操作为:对于每个像素,直接检测邻域圆上第1,5,9,13个像素点的灰度(如图2),只有当其中三个像素满足I_p+T或小于I_p-T时,当前像素才可能是一个角点。否则直接排除(这样一来对于每个像素的平均检测数便由6减少到了2)。

图二:
在这里插入图片描述
此外,原始的FAST角点经常出现扎堆现象,所以在第一遍检测之后,还需要用非极大值抑制(Non-maximal suppression,NMS),在一定区域内仅保留响应极大值的角点(这里具体细节到时候再细看),避免角点集中的问题。

经典的BRIEF描述子:

BRIEF是一种二进制描述子,其N维描述向量仅由0和1组成,这里的0和1则描述了关键点周围随机选取的各像素对的灰度值的大小关系。

描述过程:

  1. 以特征点P为中心,取一个S×S大小的Patch邻域;
  2. 在这个邻域内随机取N对点(原论文建议采用高斯分布取点),然后对这2N个点分别做高斯平滑【降低噪声,使得描述子更加稳定,原论文建议采用9×9的kernal,但实际上一个滤波显然是不够的。因此ORB提出,利用积分图像来解决:在31x31的窗口中,产生一对随机点后,以随机点为中心,取5x5的子窗口,比较两个子窗口内的像素和的大小进行二进制编码,而非仅仅由两个随机点决定二进制编码。(这一步可由积分图像完成)】。比较N对像素点的灰度值的大小:(设一对点p1,p2,灰度I_p):
    在这里插入图片描述
  3. 最后把步骤2得到的N个二进制码串组成一个N维向量即可;

最后在进行特征匹配时,例如特征点A、B的描述子如下:
A: 10101011
B: 10101010
我们设定一个阈值,比如80%。当A和B的描述子的相似度大于90%时,我们判断A, B是相同的特征点,即这2个点匹配成功。在这个例子中A, B只有最后- -位不同,相似度为87.5%,大于80%。则A和B是匹配的。

我们将A和B进行异或操作就可以轻松计算出A和B的相似度。而异或操作可以借组硬件完成,具有很高的效率,加快了匹配的速度。

注:由于在计算比较的两个特征点的BRIEF特征点时,需要保持用同一组高斯随机点对(所以需要提前定义好,作为模板),所以假如图像发生旋转,BRIEF描述子就会改变,原来的特征点和旋转后的特征点就有极大可能匹配不上。因此说经典的BRIEF描述子不具备旋转不变性。
在这里插入图片描述

ORB特征提取的改进:

如何在FAST检测的基础上维持特征点的尺度不变性?

ORB通过构建图像金字塔,在金字塔每一层图像上进行特征点检测,这样一来便涵盖了不同尺度的特征点。

具体实现
ORB_SLAM2中,对原始图形(第0层)依次进行1/1.2缩放比例进行下采样得到共计8张图片(包括原始图像)然后分别对得到的图像进行特征提取,并记录特征所在金字塔的第几层,这样就得到一帧图像不同尺度的特征点:

在这里插入图片描述
在特征点匹配时,两幅不同尺度下的图像便可以通过匹配相近尺度图像金字塔的特征点来维持尺度不变性(仅个人理解),
在这里插入图片描述
参考博客:https://blog.csdn.net/RobotLife/article/details/87194017

如何在FAST检测的基础上维持特征点的旋转不变性?

灰度质心法(Intensity Centroid):
假设我们选取图2这样的图像块,我们可以把图像块当作是平面上质量分布不均的扁平物体,它的质量分布就对应图像块上每一像素的灰度值,所以灰度质心法本质上就是求解图像块”灰度重心”的过程。

求解过程(对于单通道图像):
1.在一小的图像块B中,定义图像块的矩m为:
在这里插入图片描述
I(x,y)为像素灰度值,
当p=1,q=0时,m10为图像块x方向的加权和,权重为对应像素的灰度值,
当p=0,q=1时,m01为图像块y方向的加权和,权重为对应像素的灰度值,
当p=0,q=0时,m00为图像块的权值之和。

2.通过矩,可以找到图像的灰度质心坐标:
在这里插入图片描述
个人理解:灰度质心公式可以理解为求数学期望,只不过期望的对象成了坐标:即
在这里插入图片描述

对于B内每一个像素来说:
概率P:
在这里插入图片描述
概率P就是当前像素的灰度值占B所有灰度值总和的几分之几,假如B内所有像素点的灰度值相等,则每个像素点的概率都相等,求得的灰度质心也变为图像块的形心。

3.连接图像块的几何中心O与质心C,得到一个方向向量OC,于是特征点的方向可以定义为

在这里插入图片描述
参考博客:https://blog.csdn.net/Edgar_U/article/details/78483505

在提取了Orinted FAST关键点后,我们对每个点计算其描述子,由于我们计算了关键点的主方向向量,因此在计算描述子的过程中,我们将主方向设为x轴正方向,将旋转后的图像通过坐标变换变换为与主方向坐标系一致,这样一来最初的关键点和旋转后的关键点便建在了相同的坐标系上。再通过原始的BRIEF描述,得到的BRIEF描述子便具有了旋转不变性。

坐标变换:
θ是主方向角,S表示随机点位置(2xn的矩阵),Sθ表示旋转后的随机点的位置(2xn的矩阵),x1=(u1,v1)是一个坐标向量,其余类同,Rθ为旋转矩阵。
在这里插入图片描述
在这里插入图片描述
参考https://mp.weixin.qq.com/s/u5gSCwQ3XahF0fe19biAyQ
参考https://blog.csdn.net/gaotihong/article/details/78712017

对特征点数量与分布进行优化:

前面提到FAST特征对角点数目的优化,ORB算法在这方面也做了改进:即指定要提取的角点数量N,对原始FAST角点分别计算Harris响应值,然后选取N个具有最大响应值的角点作为最终的角点集合,若图像中的特征点不足N个,则将响应值降低为原来的1/2。

具体操作:

  1. 假定N=32,采用四叉树结构对图像进行分解,四叉树初始化为M个节点,即最开始把图像分割的个数。N=round(width/height),即若宽高比为16/9,则M=2。
    在这里插入图片描述
  2. 先对第一个节点一分为4,把各区域的关键点分配到对应四叉树子节点中(对第二个节点同样的操作,以此类推):
    在这里插入图片描述
  3. 当区域内没有关键点时,则该区域对应节点为空,节点不再分割;或当区域内仅有一个关键点时,节点也不再分割。
    在这里插入图片描述
  4. 上图我们观察到图像中的有效区域为30,此时我们估计如果再对每一个区域细分,将大约产生30+17*3=81个有效区域,由于最终每个区域都将产生一个特征点,81>32,所以这时候我们改变策略,仅取关键点最多的区域分解,此时正好有32个节点,于是对那些特征点数>1的区域采取NMS,保留响应值最大的一个角点。

在这里插入图片描述
这样一来不仅抑制了角点的数量,同时角点分布也不会过于集中。

此外,为了方便接下来的特征点匹配,ORB还将每帧图像分为64*48个格子,匹配时只需取出对应格子的关键点和描述子即可,缩小搜索范围,避免遍历整张图像。
在这里插入图片描述

ORBSLAM中的特征匹配:

ORB SLAM中的特征匹配函数:

·SearchForInitialization
·SearchByBow(2种)
·SearchByProjection(4种)
·SearchForTriangulation
·Fuse (2种)
·SearchBySim3
在这里插入图片描述
会用到特征匹配的部分:
Initial Pose Estimation(初始位姿估计)
Relocalisation(重定位)
Track Local Map(局部地图跟踪)
New Points Creation(特征点构建)
Compute Sim3(计算相似矩阵)
Loop Fusion(地图点的回环融合)

一.Initialization(初始化):

初始化的特征匹配:利用初始化的ORB匹配点来初始化地图:

(1)SearchForInitialization

·Tracking->MonocularInitialization
·寻找ORB匹配点,利用匹配点初始化地图
·设图像size(1920,1080),取宽高的1/8:
在这里插入图片描述
在这里插入图片描述
设上一帧有一特征点p,如何在当前帧匹配这一特征点呢?

  1. p所在上一帧的坐标对应到当前帧,即p在当前帧为p’
  2. 遍历以p’为中心的100*100区域寻找匹配点,计算p与区域内特征点的汉明距离(Hamming distance)
    对于二进制串a和b来说,汉明距离等于a异或b中1的数目:
    在这里插入图片描述
  3. 将汉明距离最小的特征点作为最优匹配候选点。如果汉明距离小于给定阈值就认为它是匹配点。

注:
5. 匹配点要大于100个才能进行初始化
2. 初始化的匹配过程仅在金字塔第0层(原始图像)搜索特征点进行匹配
3. 剔除那些在所选格子内但不属于搜索范围内的点
4. 最优距离要小于50,计算最优和次优距离的比值(假设最优距离是30,次优距离是40,如果他们的比值小于给定的某个阈值,则最优距离的特征点便认为具有高区分度)。

匹配完成后如何计算特征点的主方向?

  1. 统计匹配点的方向(这里的方向是指当前帧与上一帧匹配点对的方向角之差:/delta)直方图(条形图,每30度为一刻度)
  2. 统计出特征点数量最多的三个方向判断第二多的数量<0.1×第一多的数量?
    符合则将第一多的方向作为主方向,
    否则判断第三多的数量<0.1×第一多的数量?
    符合则将第一多的和第二多方向都作为主方向,并将其余不是主方向的匹配点排除。
    在这里插入图片描述

二.Tracking(初始化后的特征点跟踪):

由于初始化过程中有太多的未知量,上述SearchForInitialization的匹配策略便是最优的,但当我们提取并匹配了帧与帧之间的特征点后,在接下来的帧与帧之间,如何利用初始化的参数提高匹配效率便成了关键:

(2) SearchByProjection

·Tracking->TrackWithModel(跟踪模型1)
·根据匀速模型计算初始位姿,然后通过投影的方式搜索匹配点
匀速模型:
基于初始化或前一帧的位姿参数(通过上一帧与上上帧图像的位姿变换,我们可以计算出变换参数T),我们假设相机的运动是匀速的(帧与帧之间的时间间隔极小),则有当前帧与上一帧的位姿变换T’=T,这样我们便通过参数T将上一帧的特征点投影到当前帧,并在投影点的小范围内进行特征点匹配(跟踪),匹配过程和初始化一样。
在这里插入图片描述

  1. 遍历前一帧所有的特征点
  2. 将前一帧特征点对应的坐标投影到当前帧,在一定范围内搜索匹配点
  3. 将搜索到的特征点和前一帧的特征点逐一计算描述子距离
  4. 找出汉明距离最小的特征点
  5. 如果小于阈值,则为匹配点,跟踪成功,
  6. PoseOptimization(位姿优化,即通过匹配点计算真实的T’),若跟踪的特征点数大于10则跟踪成功。
  7. 如果匹配点不足,提高阈值,重新匹配。
(3) SearchByBow(使用词袋模型)

·Tracking->TrackReferenceKeyFrame(跟踪模型2)/Relocalization
·在不知道位姿变换(缺少T)的情况下通过特征向量寻找匹配点(同样适用于跟丢后的重定位)

  1. 提取关键帧中的特征向量(使用map容器)(继承map<unsigned int(节点ID),vector(权重)>)
  2. 对相同节点的特征点一一计算描述子距离
  3. 挑选汉明距离最小的匹配对
  4. 判断最小距离和次小距离的比例,并检查旋转方向
  5. 得到两个当前帧和关键帧的匹配点(以上步骤和TrackWithModel的最主要区别便在于TrackWithModel使用投影来匹配,TrackReferenceKeyFrame则通过词袋模型得到的Vocabulary Tree来匹配),
  6. Relocalization利用匹配点通过EPnP计算位姿,TrackReferenceKeyFrame将上一帧的位姿作为初始位姿在利用匹配点优化位姿。
    bG9nLmNzZG4ubmV0L1NFU0VTc3Nzcw==,size_16,color_FFFFFF,t_70)
    个人理解:
    ORBSLAM中的BOW相当于是一个离线的庞大的词典,里面几乎涵盖了各种各样的特征点的描述子,在当前帧图像匹配到的特征点几乎都可以在Vocabulary Tree中找到与之对应的描述子,这时候记录对应节点序号和权值,待所有关键点匹配完后生成特征向量,这时候只要匹配当前帧和关键帧的特征向量是否具有高匹配度,匹配成功则跟踪成功(基于Relocalization),

推荐参考:
https://mp.weixin.qq.com/s/r5bSPRSWBcOqi8LYPC6XyQ
https://blog.csdn.net/lwx309025167/article/details/80524020

(4) SearchByProjection

·Tracking->Relocalization(重定位)
·利用EPnP(Efficient Perspective-n-Point)计算位姿然后进行位姿优化(motion-only BA),如果内点不足则通过投影(TrackWithMode)的方式搜索更多匹配点。

  1. 前面已经通过EPNP得到的内点不再进行搜索
  2. 通过投影的方法还需估计关键帧特征点在当前帧图像金字塔中的层数(由于可能会有尺度变化),(通过地图点离相机光芯的距离计算[具体计算策略:特征点本身具有可以识别到的最小距离dmin与最大距离dmax(超出这个范围可能就不是特征点),通过计算特征点与相机光芯的距离dc,计算dc/dmax就可以粗略估计当前特征点位于图像金字塔的层数])
  3. 投影搜索:和前面的SearchByProjection类似,将关键帧地图点投影到当前帧,然后在小范围内搜索。
(5) SearchByProjection

·Tracking->TrackLocalMap->SearchLocalPoints
·搜索局部地图点,不包含前面三个步骤匹配过的地图点

搜索当前帧的共视图(Covisibility Graph),将局部地图上的特征点投影到当前帧,从而进一步搜索更多的先前丢失的匹配点:

  1. 先对局部地图点(Local Map)检察其是否在当前帧视锥中,并预测金字塔层数
  2. 根据投影搜索匹配点,将符合要求的局部地图地图点归为该特征点的地图点
  3. 根据更新后的地图点再对当前帧位姿进行优化
  4. 如果内点足够多,跟踪线程跟踪成功。
    在这里插入图片描述在这里插入图片描述
    Tracking总结:
    1.使用匀速模型跟踪特征点(TrackWithModel)
    2.在无法取得匀速模型的情况下,与关键帧之间通过特征向量比对进行跟踪(TrackReferenceKeyFrame)
    3 在跟丢的情况下进行重定位(Relocalization)
    4 完成以上三部分后再使用局部地图跟踪(TrackLocalMap),维持内点的数量。

三.Local Mapping(局部建图)

(6) SearchForTriangulation

·LocalMapping->Run->CreateNewMapPoint
·在跟踪线程中没有跟踪到的特征点在参考关键帧中搜索匹配点,进行三角测量(Triangulation)

  1. 选取与当前关键帧共视程度最高的20帧相邻帧,
  2. 计算当前帧到相邻帧的R和t(旋转+平移),并计算F矩阵(Fundadion Matrix)
  3. 类似SearchByBow,对两帧之间同一节点的特征点寻找匹配
  4. 计算匹配点离极线的距离,匹配后检查匹配点的视差。利用DLT进行三角测量得到3D地图,检查深度,重投影误差,尺度连续性
    在这里插入图片描述
(7) Fuse(特征点融合)

·LocalMapping->Run->SearchInNeighbors
·处理最近一个关键帧时,要对先前产生的重复特征点进行融合
在这里插入图片描述

  1. 选取与当前帧共视程度最高的20帧一级相邻帧再从这20帧中选出5帧对应的二级相邻帧
  2. SearchByProjection类似,将地图点投影搜索
  3. 将地图点转换到相机坐标系下,判断其深度,尺度,视角
  4. 再投影到像素坐标中,在一定区域内搜索
  5. 选取匹配点,如果存在地图点,则将两个地图点融合成一个
    在这里插入图片描述
  6. 判断两个被匹配的关键点被观测次数的多少,将观测次数多的取代观测少的进行融合
  7. 假设相邻关键帧地图点被观测次数更多(以红点取代蓝点):
    在这里插入图片描述

四.Loop Closing(回环检测):

(8) SearchByBow

·LoopClosing->Run->ComputeSim3
·搜索匹配点计算相似矩阵Sim3

  1. TrackReferenceKeyFrame,Relocalization中的SearchBoW一样(同样是利用了词袋模型Vocabulary tree)
  2. 提取关键帧中的特帧向量
  3. 对相同节点的特征点逐一计算描述子距离
  4. 选取最优距离的作为匹配点
  5. 利用匹配点计算Sim3矩阵
(9) SearchBySim3

·LoopClosing->Run->ComputeSim3
·通过Sim3进一步搜索匹配点(投影到当前帧),进一步对Sim3进行优化

  1. Relocallization中的SearchByProjection类似,进一步搜索优化Sim3
  2. 将关键帧地图点通过Sim3投影到候选关键帧坐标系下,在一定范围内搜索
  3. 双向匹配,将候选关键帧地图点也投影到关键帧,搜索匹配点
  4. 只有双向匹配成立时,才认为这两个特征点是匹配点
  5. 优化后如果内点足够多,则认为是回环关键帧。
    在这里插入图片描述
(10) SearchByProjection

·LoopClosing->Run->ComputeSim3
将回环关键帧的共视关键帧地图点投影到回环关键帧中搜索匹配点如果匹配点足够,说明找到回环了。
在这里插入图片描述

(11) Fuse

·LoopClosing->Run->CorrectLoop->SearchAndFuse
·通过Sim3把共视关键帧的位姿矫正过来,并将矫正后的地图点融合
在这里插入图片描述

  1. 找到回环后,CorrectLoop通过Sim3矫正当前关键帧的共视关键帧
  2. 利用矫正位姿将地图点投影到关键帧中,搜索匹配点
  3. 如果匹配点也有地图点对应,则被融合替代
  4. 如果匹配点没有对应地图点,则直接添加
    在这里插入图片描述

由于博主水平有限,一些细节一时无法完全解析,博主将再今后的学习总结中逐步完善。
ORB源码待分析完成后献上!!!

全篇参考:

【详解】ORB特征提取与匹配
高翔《视觉SLAM十四讲》

猜你喜欢

转载自blog.csdn.net/SESESssss/article/details/106297018