SIFT(尺度不变特征变换)简介 OpenCV-Python v4.7.0

目标

在本章中

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

理论

在过去的几章中,我们看到了一些角点检测器,如Harris等。它们是旋转不变的,这意味着,即使图像被旋转,我们也能找到相同的角。这是显而易见的,因为在旋转的图像中,角也仍然是角。但是,缩放的情况呢?如果图像被缩放,一个角可能就不是一个角了。例如,请看下面一张简单的图片。在一个小窗口中的小图像的角在同一窗口中被放大后是平的。所以,哈里斯的角不是按比例不变的。
在这里插入图片描述
2004年,英属哥伦比亚大学的D.Lowe在他的论文 《Distinctive Image Features from Scale-Invariant Keypoints》 中提出了一种新的算法–尺度不变特征变换(SIFT),该算法提取关键点并计算其描述符。这篇论文通俗易懂,被认为是关于SIFT的最佳材料。这个解释只是这篇论文的一个简短总结)

在SIFT算法中,主要有四个步骤。我们将逐一看到它们。

1. 尺度空间极值检测

从上面的图片,很明显,我们不能用同一个窗口来检测不同尺度的关键点。对于小角,它是可以的。但是要检测更大的角,我们需要更大的窗口。为此,我们使用了尺度空间滤波。其中,高斯的拉普拉斯在不同σ值的图像上被发现。高斯拉普拉斯作为一个斑点检测器,可以检测到由于σ的变化而产生的各种大小的斑点。例如,在上述图像中,低σ的高斯核对小角给出了高值,而高σ的高斯核对大角很适合。因此,我们可以找到整个尺度和空间的局部最大值,这给了我们一个(x,y,σ)值的列表,这意味着在(x,y)的σ尺度上有一个潜在的关键点。

但这个LoG有点昂贵,所以SIFT算法使用高斯之差,这是LoG的一个近似值。高斯之差是以两个不同的σ获得图像的高斯模糊之差,让它成为σ和kσ。这个过程是针对高斯金字塔中的不同八度的图像进行的。它在下面的图像中表示:

在这里插入图片描述
一旦找到这个DoG,图像就会在不同的比例和空间上搜索局部极值。例如,图像中的一个像素与它的8个邻居以及下一个比例尺的9个像素和以前比例尺的9个像素进行比较。如果它是一个局部极值,它就是一个潜在的关键点。这基本上意味着该关键点在该比例尺中得到了最好的体现。它显示在下面的图片中:
在这里插入图片描述
关于不同的参数,本文给出了一些经验数据,可以总结为:八度数=4,音阶数=5,初始σ=1.6,k=√2等为最佳值。

2. 关键点定位

一旦找到了潜在的关键点位置,就必须对其进行完善,以获得更准确的结果。他们使用泰勒级数扩展尺度空间来获得更准确的极点位置,如果这个极点的强度小于一个阈值(根据论文,0.03),它就被拒绝。这个阈值在OpenCV中被称为contrastThreshold

DoG对边缘有更高的响应,所以边缘也需要被去除。为此,使用了一个类似于Harris角落检测器的概念。他们使用一个2x2的Hessian矩阵(H)来计算主曲率。我们从哈里斯角检测器知道,对于边缘,一个特征值比另一个大。所以这里他们使用了一个简单的函数、

如果这个比率大于一个阈值,在OpenCV中称为edgeThreshold,这个关键点就会被丢弃。论文中给出的是10。

因此,它消除了任何低对比度的关键点和边缘关键点,剩下的是强兴趣点。

3. 方向分配

现在,一个方向被分配给每个关键点,以实现对图像旋转的不变性。根据比例,在关键点位置周围采取一个邻域,并在该区域计算梯度大小和方向。创建一个覆盖360度的36个bin的方向直方图(它由梯度大小和高斯加权的圆形窗口加权,σ等于关键点的1.5倍)。直方图中的最高峰被抽取,任何高于80%的峰值也被考虑用来计算方向。它创建的关键点具有相同的位置和规模,但方向不同。这有助于提高匹配的稳定性。

4. 关键点描述符

现在,关键点描述符被创建。关键点周围有一个16x16的邻域。它被划分为16个4x4大小的子块。对于每个子块,创建8个bin的方向直方图。因此,总共有128个bin值可用。它被表示为一个矢量,形成关键点描述符。除此之外,还采取了一些措施来实现对光照变化和旋转等的稳健性。

5. 关键点匹配

两幅图像之间的关键点是通过识别其最近的邻居来匹配的。但在某些情况下,第二个最近的匹配点可能非常接近于第一个。这可能是由于噪音或其他一些原因造成的。在这种情况下,最接近的距离与第二接近的距离之比被采取。如果它大于0.8,它们就被拒绝。根据该论文,它消除了大约90%的错误匹配,而只丢弃了5%的正确匹配。

这是对SIFT算法的一个总结。对于更多的细节和理解,强烈建议阅读原始论文。

OpenCV中的SIFT

现在让我们来看看OpenCV中的SIFT功能。请注意,这些功能以前只在opencv contrib repo中提供,但专利在2020年到期。所以它们现在被包含在主版本中。让我们从关键点检测开始,并绘制它们。首先,我们必须构建一个SIFT对象。我们可以向它传递不同的参数,这些参数是可选的,它们在文档中有很好的解释。

import numpy as np
import cv2 as cv
img = cv.imread('home.jpg')
gray= cv.cvtColor(img,cv.COLOR_BGR2GRAY)
sift = cv.SIFT_create()
kp = sift.detect(gray,None)
img=cv.drawKeypoints(gray,kp,img)
cv.imwrite('sift_keypoints.jpg',img)

sift.detect() 函数找到图像中的关键点。如果你想只搜索图像的某一部分,你可以传递一个掩码。每个关键点是一个特殊的结构,它有许多属性,如它的(x,y)坐标,有意义的邻域的大小,指定其方向的角度,指定关键点的强度的响应等。

OpenCV还提供了 cv.drawKeyPoints() 函数,在关键点的位置上画出小圆圈。如果你给它传递一个标志,cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS,它就会按照关键点的大小画一个圆,甚至会显示其方向。请看下面的例子。

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

请看下面的两个结果:
在这里插入图片描述
现在要计算描述符,OpenCV提供了两种方法。

  1. 由于你已经找到了关键点,你可以调用sift.compute(),从我们找到的关键点计算出描述符。例如:kp,des = sift.compute(grey,kp)
  2. 如果你没有找到关键点,可以直接用 sift.detectAndCompute() 这个函数在一个步骤中找到关键点和描述符。
    我们将看到第二种方法:
sift = cv.SIFT_create()
kp, des = sift.detectAndCompute(grey,None)

这里kp将是一个关键点的列表,des是一个形状为(关键点的数量)×128的numpy数组[ (Number of Keypoints)×128.]。

所以我们得到了关键点、描述符等。现在我们想看看如何在不同的图像中匹配关键点。这一点我们将在接下来的章节中学习。

  • 1
    点赞
  • 4
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值