OpenCV-Python系列之ORB算法

ORB是2011年ICCV上作者Rublee所提出,主要针对目前主流的SIFT或者SURF等算法的实时性进行改进。当然在实时性大为提升的基础上,匹配性能也在一定程度较SIFT与SURF算法降低。但是,在图像Two Views匹配对之间变换关系较小时,能够匹配性能逼近SIFT算法,同时计算耗时极大降低。ORB算法实时性在移动端设备上提供很好的应用,当下比较流行SLAM中采用较多的ORB-SLAM算法主要就是青睐于ORB算法实时性同时匹配精度并不差。

论文对ORB算法主要贡献如下:

1、 在FAST角点算子快速提取角点基础上,添加主方向信息。

2 、通过方向BRIEF描述算子高效计算FAST角点提取的特征点描述符。

3 、分析方向BRIEF描述符的方差与相关性。

4 、提出一种在旋转不变情况下去除相关性的BRIEF描述子的学习方式,在最近邻应用中获得更好的效果。

ORB特征通过增加了FAST检测子所没有的方向性,利用计算速度特快的描述子BRIEF,这就使得提取图像特征时速度加快了很多。在以往提取一帧图像特征点的实验中,在提取相同数量的特征点情况下,提取SURF点耗时时间大约是提取ORB特征点的14倍,而提取SIFT点耗时更大,大概比提取ORB特征点多三百多倍。由此可知提取ORB特征点比提取SIFT, SURF特征点所需要的计算量小得多。所以对于需要实时运行视觉SLAM算法的系统,其前端提取ORB特征点比较合适,且ORB特征点具有两个特性:一是尺度不变,二是旋转不变性。

下面几种特征点检测的效果图:

image.png

现在我们来进行原理解读。

原理

ORB 是 Oriented Fast and Rotated Brief 的简称,可以用来对图像中的关键点快速创建特征向量,这些特征向量可以用来识别图像中的对象。
其中,Fast 和 Brief 分别是特征检测算法和向量创建算法。ORB 首先会从图像中查找特殊区域,称为关键点。关键点即图像中突出的小区域,比如角点,比如它们具有像素值急剧的从浅色变为深色的特征。然后 ORB 会为每个关键点计算相应的特征向量。ORB 算法创建的特征向量只包含 1 和 0,称为二元特征向量。1 和 0 的顺序会根据特定关键点和其周围的像素区域而变化。该向量表示关键点周围的强度模式,因此多个特征向量可以用来识别更大的区域,甚至图像中的特定对象。
ORB 的特点是速度超快,而且在一定程度上不受噪点和图像变换的影响,例如旋转和缩放变换等。

FAST 算法

ORB 特征检测的第一步是查找图像中的关键点,而关键点检测算法即使用 FAST 算法。

FAST 是 Features from Accelerated Segments Test 的简称,可以快速选择关键点,算法步骤如下:

给与一个像素点 p,FAST 比较目标 p 圆圈范围中的 16 个像素,每个像素按高于 p,小于 p,或者与 p 相似,分为三类。

image.png

注意这里的比较是带有阈值 h 的。对于给定的阈值 h,更亮的像素将是亮度超过 Ip+h 的像素,更暗的像素将是亮度低于 Ip-h 的像素,相似像素将是亮度在这两个值之间的像素。在对像素分类后, 如果圈圈上有 8 个以上的相连像素,暗于或亮于 p 则将像素 p 选作关键点。

而 FAST 如此高效的原因是,仅将 p 与圆圈中的 4 个等距像素相比。这种方法已经证明和比较 16 个周围像素的效果相同。如果至少有一对连续像素的亮度高于或低于 p,则将 p 选作关键点。这种优化使得在整个图像中搜索关键点的时间缩短了四倍。

image.png

但是,这些关键点可以像我们提供什么样的信息?对比邻近像素的亮度有何意义?首先观察一下 FAST 算法标记关键点的图像:

image.png

可以看出关键点位于亮度有变化的区域,此类区域通常确定了某种边缘,例如猫的爪子。边缘定义了猫的界限,以及脸部区域的界限,因此这些关键点使我们能够识别这只猫,而不是图像中的任何其他对象或背景。

第二个则为BRIEF算法,我们在上一节已经讲过,这里就不在赘述了。

缩放不变性和旋转不变性

ORB 使用 FAST 检测图像中的关键点,并且通过额外的几个步骤确保无论对象的大小或位置如何都能检测到图像中的对象。

给定一个图像 ORB 算法首先开始构建图像金字塔。

图像金字塔是单个图像的多尺度表示法,由一系列原始图像的不同分辨率版本组成。金字塔的每个级别都由上个级别的图像下采样版本组成。下采样是指图像分辨率被降低,比如图像按照 1/2 比例下采样。因此一开始的 4x4 正方形区域现在变成 2x2 正方形。图像的下采样包含更少的像素,并且以 1/2 的比例降低大小。

image.png

这是一个包含 5 个级别的图形金字塔示例,在每个级别图像都以 1/2 的比例下采样。到了第四级别图像的分辨率是原始图像的 1/16。ORB 创建好图像金字塔后,它会使用 FAST 算法从每个级别不同大小的图像中快速找到关键点。因为金字塔的每个级别由原始图像的更小版本组成,因此原始图像中的任何对象在金字塔的每个级别也会降低大小。
通过确定每个级别的关键点 ORB 能够有效发现不同尺寸的对象的关键点,这样的话 ORB 实现了部分缩放不变性。这一点很重要,因为对象不太可能在每个图像中的大小都完全一样,尤其是像猫这样的对象某个时刻可能靠近相机,在另一个时刻离相机很远。

image.png

例如朝左或朝右,取决于该关键点周围的强度是如何变化的。
我们详细了解下背后原理。ORB 首先选择金字塔Level 0 中的图像,对于该图像 ORB 将计算关键点的方向。

image.png

方法是首先计算以该关键点为中心的方框中的强度形心。强度形心可以看做给定 patch 中的平均像素强度的位置。计算强度形心后,通过画一条从关键点到强度形心的向量,获得该关键点的方向,如上图所示。这个关键点的方向是向下并朝左,因为这个区域的亮度朝着这个方向增强。
为金字塔级别 0 的图像中的每个关键点分配方向后,ORB 现在为所有其他金字塔级别的图像重复相同流程。需要注意的是,在每个图像金字塔级别,Patch 大小并没有缩减,因此相同 Patch 在每个金字塔级别覆盖的图像区域将更大,导致关键点的大小各不相同。

image.png

可以从此处看出这一点。在此图中,圆圈表示每个关键点的大小,更高的金字塔级别中的关键点大小更大。
找到关键点并为其分配方向后,ORB 现在使用修改后的 BRIEF 版本创建特征向量,这个修改后的 BRIEF 版本称为 rBRIEF,即 Rotation-Aware BRIEF。无论对象的方向如何,它都可以为关键点创建相同的向量,使得 ORB 算法具有旋转不变性,意味着它可以在朝着任何角度旋转的图像中检测到相同的关键点。和 BRIEF 一样 rBRIEF 首先在给定关键点周围的已界定 patch 中随机选择 256 个像素对,以构建 256 位向量。然后根据关键点的方向角度旋转这些随机像素对,使随机点的方向与关键点的一致。最后, rBRIEF 对比随机像素对的亮度并相应地分配 1 和 0 创建对应的特征向量,为图像中的所有关键点创建的所有特征向量集合称之为 ORB 描述符。

OpenCV中的ORB算法

ORB算法的第一步是定位训练图像中的所有关键点。找到关键点后,ORB会创建相应的二进制特征向量,并在ORB描述符中将它们组合在一起。

我们将使用OpenCV的ORB类来定位关键点并创建它们相应的ORB描述符。使用ORB_create()函数设置ORB算法的参数。 ORB_create()函数的参数及其默认值如下:

cv2.ORB_create(nfeatures = 500,

             scaleFactor = 1.2,

             nlevels = 8,

             edgeThreshold = 31,

             firstLevel = 0,

             WTA_K = 2,

             scoreType = HARRIS_SCORE,

             patchSize = 31,

             fastThreshold = 20)

参数:

·nfeatures - int

确定要查找的最大要素(关键点)数。

·scaleFactor - float

金字塔抽取率,必须大于1。ORB使用图像金字塔来查找要素,因此必须提供金字塔中每个图层与金字塔所具有的级别数之间的比例因子。scaleFactor = 2表示经典金字塔,其中每个下一级别的像素比前一级低4倍。大比例因子将减少发现的功能数量。

·nlevels - int

金字塔等级的数量。最小级别的线性大小等于input_image_linear_size / pow(scaleFactor,nlevels)。

·edgeThreshold - - int

未检测到要素的边框大小。由于关键点具有特定的像素大小,因此必须从搜索中排除图像的边缘。 edgeThreshold的大小应该等于或大于patchSize参数。

·firstLevel - int

此参数允许您确定应将哪个级别视为金字塔中的第一级别。它在当前实现中应为0。通常,具有统一标度的金字塔等级被认为是第一级。

·WTA_K - int

用于生成定向的BRIEF描述符的每个元素的随机像素的数量。可能的值为2,3和4,其中2为默认值。例如,值3意味着一次选择三个随机像素来比较它们的亮度。返回最亮像素的索引。由于有3个像素,因此返回的索引将为0,1或2。

·scoreType - int

此参数可以设置为HARRIS_SCORE或FAST_SCORE。默认的HARRIS_SCORE表示Harris角算法用于对要素进行排名。该分数仅用于保留最佳功能。 FAST_SCORE生成的关键点稍差,但计算起来要快一些。

·patchSize - int

面向简要描述符使用的补丁的大小。当然,在较小的金字塔层上,由特征覆盖的感知图像区域将更大。

我们可以看到,cv2.ORB_create()函数支持多种参数。前两个参数(nfeatures和scaleFactor)可能是最有可能改变的参数。其他参数可以安全地保留其默认值,将获得良好的结果。

我们仍然使用这张图片:

image.png

来看代码:

def ORB(img):
     # Initiate ORB detector
     orb = cv2.ORB_create()
 
     # find the keypoints with ORB
     kp = orb.detect(img, None)
 
     # compute the descriptors with ORB
     kp, des = orb.compute(img, kp)
 
     # draw only keypoints location,not size and orientation
     img2 = cv2.drawKeypoints(img, kp, None, color=(0, 255, 0), flags=0)
     plt.imshow(img2), plt.show()

结果:

image.png

我们会在之后讲述使用各大算法如何对两幅图像进行特征匹配。

posted @ 2021-12-08 09:30  wuyuan2011woaini  阅读(1149)  评论(0编辑  收藏  举报