【opencv】SIFT(尺度不变特征变换)算法?

在这里插入图片描述
关键词:SIFT Algorithm

一、介绍

   您是否想过,即使从模糊的照片或不同的角度,您也能立即识别朋友的脸?这是因为您的大脑擅长识别关键特征并建立联系。尺度不变特征变换 (SIFT) 算法是计算机视觉领域的一种强大工具,它模仿了这种能力。

   与人类不同,机器很难识别图像中具有不同比例或视角的物体。SIFT 弥补了这一差距。通过从图像中提取独特的特征,SIFT 允许机器将这些特征与同一物体的新图像进行匹配。这为图像识别、物体检测等领域的激动人心的应用铺平了道路。在本文中,我们将深入研究 SIFT 算法,并探索它如何赋予机器类似人类的图像识别能力。

   学习目标

   向初学者介绍强大的 SIFT(尺度不变特征变换)技术。
了解如何使用尺度不变特征变换算法执行特征匹配。
尝试使用 Python 编写 SIFT(尺度不变特征变换)算法。

二、什么是 SIFT 算法?

2.1 SIFT 算法描述

   SIFT(尺度不变特征变换)算法是一种用于特征检测和描述的计算机视觉技术。它可以检测图像中对尺度、旋转和仿射变换变化具有鲁棒性的独特关键点或特征。SIFT(尺度不变特征变换)的工作原理是根据关键点的局部强度极值来识别关键点,并计算描述符来捕获这些关键点周围的局部图像信息。然后,这些描述符可用于图像匹配、对象识别和图像检索等任务。

2.2 SIFT 算法示例

   看看下面的图片集,想想它们之间的共同元素:
在这里插入图片描述

SIFT 算法示例
   当然是辉煌的埃菲尔铁塔!眼尖的你们还会注意到,每张图片都有不同的背景,是从不同的角度拍摄的,而且前景中也有不同的物体(在某些情况下)。

三、人类与机器识别

   我敢肯定,你只需要花一小会儿的时间就能搞清楚这一切。图像以奇怪的角度旋转或放大到只显示一半的铁塔都没关系。这主要是因为你已经多次看过埃菲尔铁塔的图像,你的记忆很容易回忆起它的特征。我们自然而然地明白,图像的比例或角度可能会发生变化,但物体保持不变。

   但机器在处理同样的事情时却遇到了巨大的困难。如果我们改变某些东西(如角度或比例),它们识别图像中的物体将是一项挑战。好消息是,机器非常灵活,我们可以教它们以几乎人类的水平识别图像。

3.1 SIFT 在计算机视觉中的应用

   这是计算机视觉工作中最令人兴奋的方面之一!

   SIFT 计算机视觉,即尺度不变特征变换,是计算机视觉中的一种特征检测算法。

   SIFT 算法有助于定位图像中的局部特征,通常称为图像的“关键点”。这些关键点是比例和旋转不变量,可用于各种计算机视觉应用,如图像匹配、对象检测、场景检测等。

3.2 SIFT 关键点的优势

   我们还可以在模型训练期间使用 SIFT 生成的关键点作为图像的特征。SIFT 特征、边缘特征或 HOG 特征的主要优点是它们不受图像大小或方向的影响。

   示例演示
   例如,这是另一张埃菲尔铁塔的图片及其较小版本。第一张图像中物体的关键点与第二张图像中找到的关键点相匹配。当另一张图像中的物体略微旋转时,两张图像也会出现同样的情况。很神奇,对吧?
在这里插入图片描述

3.3 示例演示

  • SIFT 流程
       让我们了解一下这些关键点是如何识别的,以及用于确保尺度和旋转不变性的技术是什么。从广义上讲,整个过程可以分为 4 个部分:

   构建尺度空间:确保特征与尺度无关
   关键点定位:识别合适的特征或关键点
   方向分配:确保关键点旋转不变
   关键点描述符:为每个关键点分配一个唯一的指纹
   最后,我们可以使用这些关键点进行特征匹配!

  •    构建尺度空间
    我们需要在忽略任何噪声的情况下识别给定输入图像中最独特的特征。此外,我们需要确保特征不依赖于尺度。这些都是关键概念,让我们逐一讨论它们。

  •    高斯模糊
    我们使用高斯模糊技术来减少图像中的噪音。

   对于图像中的每个像素,高斯模糊都会根据其具有特定 sigma 值的相邻像素计算一个值。下面是应用高斯模糊之前和之后的图像示例。如您所见,纹理和细节已从图像中删除,只保留了相关信息(如形状和边缘):
在这里插入图片描述

  •    高斯模糊
    高斯模糊有助于图像处理,并成功去除了图像中的噪声,并且我们突出了图像的重要特征。现在,我们需要确保这些特征与尺度相关。这意味着我们将通过创建“尺度空间”在多个尺度上搜索这些特征。

   尺度空间是从单幅图像生成的具有不同尺度的图像集合。

   因此,这些模糊图像是针对多个比例创建的。要创建一组不同比例的新图像,我们将获取原始图像并将比例缩小一半。对于每个新图像,我们将创建模糊版本,如上所示。

   下面是一个可以更好地理解它的例子。我们有大小为 (275, 183) 的原始图像和尺寸为 (138, 92) 的缩放图像。对于这两幅图像,都会创建两个模糊图像:
在这里插入图片描述

高斯模糊 | SIFT(尺度不变特征变换)算法
   你可能会想——我们需要缩放图像多少次,每张缩放后的图像需要创建多少张模糊图像?理想的八度数应该是四个,每个八度的模糊图像数量应该是五个。
在这里插入图片描述

高斯模糊 | SIFT(尺度不变特征变换)算法

  • 高斯差分
       到目前为止,我们已经创建了多个尺度的图像(通常用 σ 表示),并对每个尺度的图像使用高斯模糊来降低图像中的噪声。接下来,我们将尝试使用一种称为高斯差分或 DoG 的技术来增强特征。

   高斯差分是一种特征增强算法,它涉及从原始图像的另一个较不模糊的版本中减去一个模糊版本。

   DoG 会通过以相同的比例从前一个图像中减去每个图像,为每个八度创建另一组图像。以下是 DoG 实现方式的直观说明:
在这里插入图片描述

高斯差分

   注:该图片取自原论文。为了更清晰的视图,现在以垂直形式表示八度音阶。

   让我们在比例空间中为图像创建 DoG。请看下图。左侧有 5 张图像,全部来自第一个八度(因此具有相同的比例)。每个后续图像都是通过对前一个图像应用高斯模糊创建的。

   右边是四幅通过减去连续高斯函数生成的图像。结果令人瞠目结舌!
在这里插入图片描述

  • 连续高斯
       我们增强了每幅图像的功能。请注意,这里我仅针对第一个八度音阶实施了该功能,但所有八度音阶都会发生相同的过程。

   现在我们有了一组新的图像,我们将用它来找到重要的关键点。

四、关键点定位

   创建图像后,下一步是从图像中找到可用于特征匹配的重要关键点。这个想法是找到图像的局部最大值和最小值。这部分分为两个步骤:

  • 找到局部最大值和最小值
       删除低对比度关键点(关键点选择)
    局部最大值和局部最小值
    为了找到局部最大值和最小值,我们遍历图像中的每个像素并将其与相邻像素进行比较。

   当我说“邻近”时,这不仅包括该图像的周围像素(像素所在的位置),还包括八度音阶中前一个和下一个图像的九个像素。

   这意味着每个像素值都会与其他 26 个像素值进行比较,以确定它是否是局部最大值/最小值(称为极值)。例如,在下图中,我们有来自第一个八度的三幅图像。标记为x的像素与相邻像素(绿色)进行比较,如果它是相邻像素中最高或最低的,则被选为关键点或兴趣点:
在这里插入图片描述

   我们现在有了代表图像且尺度不变的潜在关键点。我们将对选定的关键点进行最后的检查,以确保这些是代表图像的最准确的关键点。

关键点选择

   太棒了!到目前为止,我们已经成功生成了尺度不变的关键点。但其中一些关键点可能对噪声不够稳健。这就是为什么我们需要进行最后检查,以确保我们拥有最准确的关键点来表示图像特征。

   因此,我们将消除对比度低或非常靠近边缘的关键点。

   为了处理低对比度的关键点,我们会对每个关键点进行二阶泰勒展开式计算。如果结果值小于 0.03(幅度),我们会拒绝该关键点。

   那么我们该如何处理剩余的关键点呢?好吧,我们进行检查以识别位置不佳的关键点。这些关键点靠近边缘,具有较高的边缘响应,但可能对少量噪声不够稳健。二阶 Hessian 矩阵用于识别此类关键点。您可以在此处了解背后的数学原理。

   现在我们已经执行了对比度测试和边缘测试来拒绝不稳定的关键点,我们现在将为每个关键点分配一个方向值以使旋转不变。

五、实验任务指导

   在此阶段,我们有一组稳定的图像关键点。现在我们将为每个关键点分配一个方向,以便它们不受旋转影响。我们可以再次将此步骤分为两个较小的步骤:

5.1 计算大小和方向

   创建震级和方向的直方图
计算震级和方向
请考虑下面显示的示例图像:
在这里插入图片描述

计算震级和方向
   假设我们想找到红色像素值的幅度和方向。为此,我们将通过取 55 与 46 和 56 与 42 之间的差来计算 x 和 y 方向上的梯度。结果分别为 Gx = 9 和 Gy = 14。

   一旦我们有了梯度,我们就可以使用以下公式找到幅度和方向:

  • 幅度 = √[(G x ) 2 +(G y ) 2 ] = 16.64
  • Φ = atan(Gy / Gx) = atan(1.55) = 57.17
  • 幅度表示像素的强度,方向表示像素的方向。
  • 有了这些像素的幅度和方向值,我们现在就可以创建直方图。

5.2 创建震级和方向的直方图

   在 x 轴上,我们将为角度值设置区间,例如 0-9、10-19、20-29 和最高 360。由于我们的角度值为 57,因此它将位于第 6 个区间。第 6 个区间值将与像素的大小成比例,即 16.64。我们将对关键点周围的所有像素执行此操作。

   这就是我们得到下面直方图的方法:
在这里插入图片描述

5.2 创建震级和方向的直方图

   您可以参考本文,了解有关计算梯度、幅度、方向和绘制直方图的更详细解释 -方向梯度直方图的宝贵介绍。

   此直方图将在某个点达到峰值。我们看到峰值所在的箱体将是关键点的方向。此外,如果存在另一个显著峰值(在 80% 到 100% 之间),则会生成另一个关键点,其幅度和尺度与用于生成直方图的关键点相同。角度或方向将等于具有峰值的新箱体。

   实际上,此时我们可以说关键点的数量可能会略有增加。

5.3 关键点描述符

   这是 SIFT(尺度不变特征变换)计算机视觉的最后一步。到目前为止,我们已经有了尺度不变和旋转不变的稳定关键点。在本节中,我们将使用相邻像素、它们的方向和它们的大小来为该关键点生成一个唯一的指纹,称为“描述符”。

   此外,由于我们使用周围的像素,描述符将部分地不受图像的照明或亮度的影响。

   我们首先在关键点周围取一个 16×16 的邻域。这个 16×16 块进一步划分为 4×4 子块,对于每个子块,我们使用幅度和方向生成直方图。
在这里插入图片描述

5.4 关键点描述符

   在此阶段,箱体大小会增加,我们只取 8 个箱体(而不是 36 个)。每个箭头代表 8 个箱体,箭头的长度定义量级。因此,每个关键点总共会有 128 个箱体值。

   下面是在 matplotlib 中使用 pyplot 的示例:

import cv2 
import matplotlib.pyplot as plt
%matplotlib inline

#reading image
img1 = cv2.imread('eiffel_2.jpeg')  
gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)

#keypoints
sift = cv2.xfeatures2d.SIFT_create()
keypoints_1, descriptors_1 = sift.detectAndCompute(img1,None)

img_1 = cv2.drawKeypoints(gray1,keypoints_1,img1)
plt.imshow(img_1)

matplotlib 中的 pyplot
在这里插入图片描述

六、特征匹配

   我们现在将使用 SIFT 计算机视觉特征进行特征匹配。为此,我下载了两张从不同位置拍摄的埃菲尔铁塔图像。你可以用任意两张你想要的图像来尝试。

   以下是我使用的两张图片:

在这里插入图片描述

import cv2 
import matplotlib.pyplot as plt
%matplotlib inline

# read images
img1 = cv2.imread('eiffel_2.jpeg')  
img2 = cv2.imread('eiffel_1.jpg') 

img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

figure, ax = plt.subplots(1, 2, figsize=(16, 8))

ax[0].imshow(img1, cmap='gray')
ax[1].imshow(img2, cmap='gray')

特征匹配代码

   现在,对于这两幅图像,我们将生成 SIFT 特征。首先,我们必须构建一个 SIFT 对象。我们首先使用 sift_create 创建一个 SIFT 计算机视觉对象,然后使用函数detectAndCompute获取关键点。它将返回两个值 - 关键点和 sift 计算机视觉描述符。

   让我们确定关键点并打印在每个图像中找到的关键点总数:

import cv2 
import matplotlib.pyplot as plt
%matplotlib inline

# read images
img1 = cv2.imread('eiffel_2.jpeg')  
img2 = cv2.imread('eiffel_1.jpg') 

img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

#sift
sift = cv2.xfeatures2d.SIFT_create()

keypoints_1, descriptors_1 = sift.detectAndCompute(img1,None)
keypoints_2, descriptors_2 = sift.detectAndCompute(img2,None)

len(keypoints_1), len(keypoints_2)
283, 540

   接下来,让我们尝试将图像 1 中的特征与图像 2 中的特征进行匹配。我们将使用BFmatcher (强力匹配)模块中的match()函数。此外,我们将在匹配两幅图像的特征之间画线。这可以使用OpenCV python 中的drawMatches函数来完成。

import cv2 
import matplotlib.pyplot as plt
%matplotlib inline

# read images
img1 = cv2.imread('eiffel_2.jpeg')  
img2 = cv2.imread('eiffel_1.jpg') 

img1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
img2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY)

#sift
sift = cv2.xfeatures2d.SIFT_create()

keypoints_1, descriptors_1 = sift.detectAndCompute(img1,None)
keypoints_2, descriptors_2 = sift.detectAndCompute(img2,None)

#feature matching
bf = cv2.BFMatcher(cv2.NORM_L1, crossCheck=True)

matches = bf.match(descriptors_1,descriptors_2)
matches = sorted(matches, key = lambda x:x.distance)

img3 = cv2.drawMatches(img1, keypoints_1, img2, keypoints_2, matches[:50], img2, flags=2)
plt.imshow(img3),plt.show()

在这里插入图片描述

OpenCV python 中的 drawMatches 函数
   为了清晰起见,我在这里只绘制了 50 个匹配项。您可以根据自己的喜好增加匹配项的数量。要找出匹配的关键点数,我们可以打印变量matches的长度。在本例中,答案是 190。

七、结论

   在本文中,我们详细讨论了 SIFT 特征匹配算法。该网站为 SIFT 的每个步骤提供了出色的可视化效果。您可以添加自己的图像,它也会为该图像创建关键点。另一种流行的特征匹配算法是 SURF(加速稳健特征),它是 SIFT 的更快版本。我鼓励您也探索它。

   如果你是计算机视觉和图像数据领域的新手,我建议你查看以下课程:使用深度学习 2.0 的计算机视觉

7.1 关键要点

   SIFT(尺度不变特征变换)是一种强大的图像匹配技术,可以识别和匹配对缩放、旋转和仿射畸变不变的特征。
它在计算机视觉应用中得到广泛应用,包括图像匹配、对象识别和 3D 重建。
SIFT 技术生成具有不同尺度的图像的尺度空间,然后使用高斯差分 (DoG) 方法识别关键点。
   它还计算每个关键点的描述符,可用于特征匹配和对象识别。
您可以使用 Python 和 OpenCV 库实现 SIFT,该库提供了检测关键点、计算描述符和匹配特征的函数。

  • 21
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

无水先生

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值