特征检测(二):OpenCV中的SIFT尺度不变特征变化特征检测技术

目标

在这一章当中,html

  • 咱们将学习SIFT算法的概念
  • 咱们将学习如何找到SIFT关键点和描述符。

理论

在最后几章中,咱们看到了一些角落探测器,如哈里斯等。它们是旋转不变的,这意味着,即便图像旋转了,咱们也能够找到相同的角落。这是显而易见的,由于角落在旋转的图像中也是角落。可是缩放呢?若是图像缩放,角落可能不是角落。例如,请查看下面的简单图片。放大同一个窗口时,小窗口内的小图像中的一个角落是平坦的。因此哈里斯的角落不是规模不变的。python

尺度不变性

所以,2004年,不列颠哥伦比亚大学的D.Lowe在他的论文中提出了一种新的算法 - 尺度不变特征变换(SIFT),该算法从尺度不变关键点获取特征图像特征,提取关键点并计算其描述符。(本文很容易理解,并被认为是SIFT上最好的资料,因此这个解释只是本文的一个简短摘要)算法

SIFT算法主要涉及四个步骤。咱们将逐一看到他们。数组

1.尺度空间极值检测

从上图中能够看出,咱们不能使用相同的窗口来检测不一样比例的关键点。小角落也行。但要检测更大的角落,咱们须要更大的窗口。为此,使用缩放空间滤波。其中,高斯拉普拉斯能够找到具备各类\西格玛值的图像。LoG做为一个斑点检测器,能够检测因为变化而产生的各类大小的斑点\西格玛。总之,\西格玛做为缩放参数。例如,在上面的图像中,低的高斯内核\西格玛为小角部提供高值,而高斯内核高度\西格玛适合较大的角部。所以,咱们能够在规模和空间中找到局部最大值,这给咱们一个(X,Y,\西格马)值列表,这意味着在(x,y)\西格玛规模上存在潜在的关键点。函数

可是这个LoG有点贵,因此SIFT算法使用高斯差分,这是LoG的近似值。高斯的差做为图像的高斯模糊的用两种不一样的差获得\西格玛,让它\西格玛ķ\西格玛。这个过程是在高斯金字塔的不一样八度的图像中完成的。它在下面的图像中表示:学习

高斯差分

一旦找到这个DoG,图像就会在比例和空间上搜索到局部极值。例如,图像中的一个像素与其8个邻居以及下一个尺度的9个像素和先前尺度的9个像素相比较。若是它是一个局部极值,这是一个潜在的关键点。它基本上意味着这个关键点最能体如今这个尺度上。它显示在下面的图像中:spa

高斯差分

关于不一样的参数,给出这能够归纳为,八度= 4,等级水平= 5,初始的数目的数目一些经验数据\西格玛= 1.6K = \ SQRT {2}等等做为最佳值。code

2.关键点本地化

一旦找到潜在的关键点位置,就必须对其进行改进以得到更准确的结果。他们使用泰勒级数展开的尺度空间来得到更精确的极值位置,而且若是这个极值的强度小于阈值(根据纸张为0.03),它将被拒绝。该阈值在OpenCV中称为contrastThresholdhtm

DoG对边缘有更高的响应,因此边缘也须要去除。为此,使用了相似于Harris角点检测器的概念。他们用2×2 Hessian矩阵(H)来计算市政曲率。咱们从Harris角点检测器知道,对于边缘,一个特征值比另外一个大。因此这里他们使用了一个简单的函数对象

若是此比率大于阈值(在OpenCV中称为edgeThreshold),则丢弃该关键点。在纸上给出10。

所以它消除了任何低对比度关键点和边缘关键点,而且仍然存在强烈的兴趣点。

3.方向分配

如今为每一个关键点分配一个方向以实现图像旋转的不变性。根据规模在关键点位置周围采起邻居关系,并在该地区计算梯度大小和方向。建立一个方向直方图,其中36个方框覆盖360度。(它经过梯度幅度和高斯加权圆窗口\西格玛等于关键点尺度的1.5倍进行加权,得到直方图中的最高峰值,而且任何高于80%的峰值也被认为是计算方向,它建立关键点具备相同的位置和规模,但方向不一样,有助于匹配的稳定性。

4.关键点描述符

如今建立关键点描述符。关键点周围有一个16x16的街区。它分为16个4x4大小的子块。对于每一个子块,建立8个方向直方图。因此共有128个bin值可用。它被表示为造成关键点描述符的向量。除此以外,还采起了几项措施来实现对光照变化,旋转等的鲁棒性。

5.关键点匹配

两幅图像之间的关键点经过识别它们最近的邻居来匹配。但在某些状况下,第二个最接近的匹配可能很是接近第一个。这多是因为噪音或其余缘由。在那种状况下,采用最近距离与第二近距离的比率。若是它大于0.8,则被拒绝。根据论文,它排除了大约90%的错误匹配,而丢弃只有5%的匹配正确。

因此这是SIFT算法的总结。欲了解更多细节和理解,强烈建议阅读原文。记住一件事,这个算法是得到专利的。因此这个算法被包含在OpenCV中的非自由模块中。

OpenCV中的

如今让咱们看看OpenCV中提供的SIFT功能。让咱们从关键点检测开始并绘制它们。首先,咱们必须构建一个SIFT对象。咱们能够将不一样的参数传递给它,这些参数是可选的,而且在文档中有很好的解释。

import cv2
import numpy as np

img = cv2.imread('home.jpg')
gray= cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

sift = cv2.SIFT()
kp = sift.detect(gray,None)

img=cv2.drawKeypoints(gray,kp)

sift.detect()函数在图像中查找关键点。若是您只想搜索图像的一部分,则能够传递掩码。每一个关键点都是一个特殊的结构,它具备许多属性,如它的(x,y)坐标,有意义的邻域的大小,指定其方向的角度,指定关键点强度的响应等。

 

OpenCV还提供cv2.drawKeyPoints()函数,用于绘制关键点位置上的小圆圈。若是你传递一个标志cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS给它,它将绘制一个尺寸为关键点的圆,它甚至会显示它的方向。看下面的例子。

img=cv2.drawKeypoints(gray,kp,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imwrite('sift_keypoints.jpg',img)

看到下面的两个结果:

SIFT关键点

如今计算描述符,OpenCV提供了两种方法。

  1. 既然你已经找到了关键点,你能够调用sift.compute()来计算咱们找到的关键点的描述符。例如:kp,des = sift.compute(gray,kp)
  2. 若是您没有找到关键点,可使用函数sift.detectAndCompute()在一个步骤中直接找到关键点和描述符。

咱们将看到第二种方法:

sift = cv2.SIFT()
kp, des = sift.detectAndCompute(gray,None)

这里kp将是一个关键点列表,des是一个形状不规则的数组Number \ _of \ _Keypoints \ times 128

参考:

http://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_sift_intro/py_sift_intro.html

 

转载注明出处!!!

相关文章
相关标签/搜索