十一、opencv-python图像处理顶级操作(3)——SIFT/SURF算法

一、SIFT原理

 Harris和Shi-Tomasi角点检测算法,虽然具有旋转不变性,但是不具有尺度不变性,也就是说如果图像被放大后,在使用同样的窗口,就检测不到角点了。
在这里插入图片描述
 所以,介绍一种计算机视觉的算法,尺度不变特征转换即SIFT,它用来侦测与描述影响中的局部性特征,它在空间尺度中寻找极值点,并提取出其位置、尺度、旋转不变量。
SIFT算法的实质是在不同的尺度空间上查找关键点(特征点),并计算出关键点的方向。SIFT所查找到的关键点是一些十分突出,不会因光照、仿射变换和噪音等因素而变化的点。如角点、边缘点、暗区的亮点及亮区的暗点等。

1、基本流程

  • 尺度空间极值检测

搜索所有尺度上的图像位置。通过高斯差分函数来识别潜在的对于尺度和旋转不变的关键点。

  • 关键点定位

在每个候选的位置上,通过一个拟合精细的模型来确定位置和尺度。关键点的选择依据于他们的稳定程度。

  • 关键点方向确定

基于图像局部的梯度方向,分配给每个关键点位置一个或多个方向。所有后面的对图像数据的操作都相对于关键点的方向、尺度和位置进行变换,进而保证了对于这些变换的不变性。

  • 关键点描述

在每个关键点周围的邻域内,在选定的尺度上测量图像局部的梯度。这些梯度作为关键点的描述符,它允许比较大的局部形状的变形或光照变化。

2、尺度空间极值检测

 在不同的尺度空间不能使用相同的窗口检测极值点,对小的关键点使用小的窗口,对大的关键点使用大的窗口,为了达到此目的,我们使用尺度空间滤波器。

高斯核是唯一可以产生多尺度空间的核函数。
-《Scale-space theory:A basic tool for analysing structures at different scales》。

 一个图像的尺度空间 L(x, y, σ \sigma σ),定义为原始图像 I(x, y)与一个可变尺度的2维高斯函数G(x, y, σ \sigma σ)卷积运算,即:
L ( x , y , σ ) = G ( x , y , σ ) ∗ I ( x , y ) L(x, y, \sigma) = G(x, y, \sigma)*I(x, y) L(x,y,σ)=G(x,y,σ)I(x,y)
其中:
G ( x , y , σ ) = 1 2 π σ 2 e − x 2 + y 2 2 σ 2 G(x, y, \sigma) = \frac{1}{2π\sigma^2}e^-\frac{x^2+y^2}{2\sigma^2} G(x,y,σ)=2πσ21e2σ2x2+y2
σ \sigma σ是尺度空间因子,它决定了图像的模糊程度。在大尺度下( σ \sigma σ值大)表现的是图像的样貌信息,在小尺度下( σ \sigma σ值小)表现的是图像的细节信息。
 在计算高斯函数的离散近似时,在大概 3 σ \sigma σ距离之外的像素都可以看做不作用,这些像素的计算也就可以忽略。所以,在实际应用中,只计算 (6 σ \sigma σ+1)*(6 σ \sigma σ+1)的高斯卷积核就可以保证相关像素影响。

 下面我们构建图像的高斯金字塔,它采用了高斯函数对图像进行模糊以及降采样处理得到的,高斯金字塔构建过程中,首先将图像扩大一倍,在扩大的图像基础上构建高斯金字塔;然后对该尺寸下图像进行高斯模糊,几幅模糊之后的图像集合构成了一个Octave, 然后对该Octave下选择一副图像进行下采样,长和宽分别缩短一倍,图像面积变为原来四分之一。
 这幅图像就是下一个Octave的初始图像,在初始图像的基础上完成属于这个Octave的高斯模糊处理,以此类推完成整个算法所需要的所有八度构建,这样这个高斯金字塔就构建出来了,整个流程如图所示:
在这里插入图片描述
 利用LoG(高斯拉普拉斯方法),即图像的二阶导数,可以在不同的尺度下检测图像的关键点信息,从而确定图像的特征点。单LoG的计算量大,效率低。所以我们通过两个相邻高斯尺度空间的图像的相减,得到DoG(高斯差分)来近似LoG。
 为了计算DoG,我们构建高斯差分金字塔,该金字塔是在上述的高斯金字塔的基础上构建而成的,建立过程是:在高斯金字塔中每个Octave中相邻两层相减就构成了高斯差分金字塔。如下图所示:
在这里插入图片描述
 高斯差分金字塔的第1组第1层是由高斯金字塔的第1组第2层减第1组第1层得到的。以此类推,逐组逐层生成每一个差分图像,所有差分图像构成差分金字塔。概括为DOG金字塔的第0组第1层图像是有高斯金字塔的第o组,第I+1层减第o组第I层得到的。后续SIFT特征点的提取都是在DOG金字塔上进行的。
 在DoG搞定之后,就可以在不同的尺度空间搜索局部最大值了。对于图像的一个像素点而言,它需要与自己周围的8邻域,以及尺度空间中上下两层中的相邻的18(2X9)个点相比。如果是局部最大值,它就可能是一个关键点。基本上来说关键点是图像在相应尺度空间中的最好代表。如下图所示:
在这里插入图片描述 搜索过程从每组的第二层开始,以第二层为当前层,对第二层的DOG图像中的每个点取一个3X3的立方体,立方体上下层为第一层和第三层。这样,搜索得到的极值点既有位置坐标(DOG的图像坐标),又有空间尺度坐标(层坐标)。当第二层搜索完成后,再以第三层作为当前层,其过程与第二层的搜索类似。当S=3时,每组里面要搜索3层,所以在DOG中就有S+2层,在初始构建的金字塔中每组有S+3层。

3、关键点定位

  由于DOG对噪声和边缘比较敏感,因此在上面高斯差分金字塔中检测到的局部极值点需经过进一步的检测才能精确定位为特征点。
  使用尺度空间的泰勒级数展开来获得极值的准确位置,如果极值点的灰度值小于阈值(一般为0.03或0.04)就会被忽略。在OpenCV中这种阈值被称为contrastThreshold。
  DOG算法对边界非常敏感,所以我们必须要把边界去除。Harris算法除了可以用于角点检测之外,还可以用于检测边界。从Harris角点检测的算法中,当一个特征值远远大于另一个特征值时,检测到的是边界。那在DOG算法中欠佳的关键点在平行边缘的方向有较大的主曲率,而在垂直于边缘的方向有较小的曲率,两者的比值如果高于某个阈值(在OpenCV中叫做边界阈值),就认为该关键点为边界,将被忽略,一般将该阈值设置为10。
  将低对比度和边界的关键点去除,得到的就是我们感兴趣的关键点。

4、关键点方向确定

  经过上述两个步骤,图像的关键点完全找到了,这些关键点具有尺度不变性。为了实现旋转不变性,还需要为每个关键点分配一个方向角度,也就是根据检测到的关键点所在高斯尺度图像的邻域结构中求得一个方向基准。
  对于任一关键点,我们采集其所在高斯金字塔图像以r为半径的区域内所有像素的梯度特征(幅值和幅角)。半径r为:
r = 3 × 1.5 σ r=3\times1.5\sigma r=3×1.5σ
  其中 σ \sigma σ是关键点所在octave的图像尺度,可以得到对应的尺度图像。
  梯度的幅值和方向的计算公式为:
m ( x , y ) = ( L ( x + 1 , y ) − L ( x − 1 , y ) ) 2 + ( L ( x , y + 1 ) + L ( x , y − 1 ) ) 2 m(x, y)=\sqrt{(L(x+1, y) -L(x-1, y) )^2+(L(x, y+1)+L(x, y-1))^2} m(x,y)=(L(x+1,y)L(x1,y))2+(L(x,y+1)+L(x,y1))2
θ ( x , y ) = a r c t a n ( L ( x , y = 1 ) − L ( x , y − 1 ) L ( x + 1 , y ) − L ( x − 1 , y ) ) \theta(x, y)=arctan(\frac{L(x, y=1) - L(x, y-1)}{L(x+1, y)-L(x-1, y)}) θ(x,y)=arctan(L(x+1,y)L(x1,y)L(x,y=1)L(x,y1))
 邻域像素梯度的计算结果如下图所示:
在这里插入图片描述
  完成关键点梯度计算后,使用直方图统计关键点领域内像素的梯度幅值和方向。具体做法是,将360°分为36注,每10°一注,然后在以r为半径的区域内,将梯度方向在某一个柱内的像素找出来,然后将他们的幅值相加在一起作为柱的高度。因为在r为半径的区域内,像素的提付幅值对中心像素的贡献是不同的,因此还需要对幅值进行加权处理,采用高斯加权,方差为1.5 σ \sigma σ。如下图所示,是简化图中只画了8个方向的直方图。
在这里插入图片描述  每个特征点必须分配一个主方向,还需要一个或多个辅方向,增加辅方向的目的是为了增强图像匹配的鲁棒性。辅方向的定义是,当一个柱体的高度大于主方向柱体高度的80%时,该柱体所代表的方向就是给特征点的辅方向。
  直方图的峰值,即最高的柱代表的方向是特征点邻域范围内图像梯度的主方向,但该柱体代表的角度是一个范围,所以我们还要对离散的直方图进行插值拟合,以得到更精确的方向角度值。利用抛物线对离散的直方图进行拟合,如下图所示:

在这里插入图片描述
获得图像关键点主方向之后,每个关键点有三个信息(x, y, σ \sigma σ, θ \theta θ);位置、尺度、方向。由此我们可以确定一个SIFT特征区域。通常使用一个带箭头的圆或直接使用箭头表示SIFT区域的三个值;中心表示特征点位置,半径表示关键点尺度,箭头表示方向。如下图所示:
在这里插入图片描述

5、关键点描述

  通过以上步骤,每个关键点被分配了位置,尺度和方向信息。接下来我们为每个关键点建立了一个描述符,该描述符既具有可区分性,有具有对某些变量的不变性,如光照,视角等。而且描述符不仅仅包含关键点,也包括关键点周围对其有贡献的像素点。主要思路就是通过将关键点周围图像区域分块,计算块内的梯度直方图,生成具有特征向量,对图像信息进行抽象。
  描述符与特征点所在的尺度有关,所以我们在关键点所在的高斯尺度图像上生成对应的描述符。以特征点为中心,将其附近领域划分为 d ∗ d d*d dd个子区域(一般去 d = 4 d=4 d=4),每个子区域都是一个正方形,边长为 3 σ 3\sigma 3σ,考虑到实际计算时,需进行三次线性插值,所以特征点领域的 3 σ ( d + 1 ) ∗ 3 σ ( d + 1 ) 3\sigma(d+1) * 3\sigma(d+1) 3σ(d+1)3σ(d+1)的范围,如下图所示:
在这里插入图片描述  为保证特征点的旋转 不变性,以特征点为中心,将坐标轴选装为关键点的主方向,如下图所示:
在这里插入图片描述
  计算子区域内的像素的梯度,并按照 σ = 0.5 d \sigma=0.5d σ=0.5d进行高斯加权,然后插值计算得到每个种子点的八个方向的梯度,插值方法如下图所示:
在这里插入图片描述  每个种子点的梯度都是由覆盖其的4个子区域插值而得的。如图中的红色点,落在第0行和第1行之间,对这两行都有贡献。对第0行和第3列种子行的贡献因子为dr,对第1行和第3列的贡献因子为1-dr,同理,对邻近两列的贡献因子为dc和1-dc,对邻近两个方向的贡献因子为do和1-do。则最终累加在每个方向上的梯度大小为:
w e i g h t = w ∗ d r k ( 1 − d r ) ( 1 − k ) d c m ( 1 − d c ) ( 1 − m ) d o n ( 1 − d o ) ( 1 − n ) weight=w*dr^k(1-dr)^{(1-k)}dc^m(1-dc)^{(1-m)}do^n(1-do)^{(1-n)} weight=wdrk(1dr)(1k)dcm(1dc)(1m)don(1do)(1n)
  其中k, m, n为0或者1,。如上统计448 = 128个梯度信息即为该关键点的特征向量,按照特征点对每个关键点的特征向量进行排序,就得到了SIFT特征描述向量。

6、总结

SIFT在图像的不变特征提取方面有很大的优势,但并不完美,仍存在实时性不高,有时特征点较少,对边缘光滑的目标无法准确提取特征点等缺陷,自SIFT算法问世以来,人们就一直对齐进行优化和改进,其中最著名的就是SURF算法.

二、SURF原理

使用SIFT算法进行关键点检测和描述的执行速度比较慢,需要速度更快的算法。2006年Bay提出了SURF算法,是SIFT算法的增强版,它的计算量小,运算速度快,提取的特征与SIFT几乎相同,将其与SIFT算法对比如下:
在这里插入图片描述

总结

SIFT原理:

  • (1)尺度空间极值检测:构建高斯金字塔,高斯差分金字塔,检测极值点
  • (2)关键点定位:去除对比度较小和边缘对极值点的影响
  • (3)关键点方向确定:利用梯度直方图确定关键点的方向
  • (4)关键点描述:对关键点周围图像区域分块,计算块内的梯度直方图,对关键点信息进行描述。

SURF算法:

  • 对SIFT算法的改进,在尺度空间极值检测,关键点方向确定,关键点描述方面都有改进,提高了检测效率。

猜你喜欢

转载自blog.csdn.net/weixin_44463519/article/details/126172634