查看全课大纲(第 16 / 93 节)
  1. 1.计算机视觉概述
  2. 2.计算机视觉应用场景
  3. 3.困难与挑战
  4. 4.开源库介绍
  5. 5.图像显示与存储
  6. 6.CLAHE
  7. 7.腐蚀膨胀与开闭运算
  8. 8.滤波与边缘填充
  9. 9.各种滤波
  10. 10.图像金字塔
  11. 11.傅里叶变换
  12. 12.短时傅里叶变换与小波变换
  13. 13.颜色特征与颜色直方图
  14. 14.几何特征_边缘
  15. 15.几何特征-角点与斑点
  16. 16.局部特征-SIFT特征描述子
  17. 17.局部特征-SURF特征描述子
  18. 18.局部特征-ORB特征描述子
  19. 19.其他特征描述子
  20. 20.传统图像分割技术
  21. 21.GraphCut
  22. 22.GrabCut
  23. 23.人脸检测的传统方法
  24. 24.行人检测的传统方法HOG+SVM
  25. 25.行人检测DPM
  26. 26.人工神经网络的架构
  27. 27.目标函数与梯度下降
  28. 28.误差反向传播
  29. 29.可手算的神经网络
  30. 30.改进目标函数与克服梯度消散
  31. 31.神经网络之传统神经网络与深度网络的差异
  32. 32.各种梯度下降算法
  33. 33.如何选择合适的梯度下降算法
  34. 34.避免过适应
  35. 35.CNN的架构
  36. 36.CNN的误差反向传播_卷积层
  37. 37.CNN的误差反向传播_池化层
  38. 38.分类所用的数据集
  39. 39.Alexnet详解
  40. 40.VGG详解
  41. 41.GoogLeNet_v1
  42. 42.BatchNormalization
  43. 43.GoogLeNet_v3v4
  44. 44.ResNet
  45. 45.ResNeXt
  46. 46.CNN设计准则
  47. 47.图像检索与推土机距离
  48. 48.基于颜色相似性
  49. 49.基于形状相似性
  50. 50.基于纹理相似性
  51. 51.基于局部特征相似性
  52. 52.DL的二值哈希编码
  53. 53.高维空间中检索KDTree
  54. 54.高维空间中检索LSH
  55. 55.目标识别任务综述
  56. 56.RCNN
  57. 57.SPP-Net
  58. 58.Fast R-CNN
  59. 59.Faster R-CNN
  60. 60.R-CNN系列模型回顾
  61. 61.R-FCN的设计思路
  62. 62.R-FCN的实现
  63. 63.YOLOv1
  64. 64.YOLOv2_9000
  65. 65.YOLOv3
  66. 66.图像分割应用场景与数据集
  67. 67.上采样的实现方式
  68. 68.FCN网络架构的由来
  69. 69.FCN构建细节
  70. 70.DeepLabv1
  71. 71.CRF
  72. 72.DeepLabv2
  73. 73.DeepLabv3
  74. 74.特定的医学影像分割任务
  75. 75.U-Net
  76. 76.3D U-Net
  77. 77.V-Net
  78. 78.DenseNet
  79. 79.病理切片分析任务及数据集
  80. 80.病理切片分析
  81. 81.图说任务及其传统处理方法
  82. 82.深度语言模型与RNN
  83. 83.LSTM及其变种
  84. 84.NIC模型
  85. 85.SAT模型
  86. 86.图说的性能指标
  87. 87.判别模型与生成模型
  88. 88.KL散度与JS散度
  89. 89.VAE
  90. 90.GAN的基本原理
  91. 91.DCGAN与CGAN
  92. 92.Wasserstein GAN
  93. 93.SRGAN

局部特征-SIFT特征描述子

小象实战讲义 · 基于深度学习的计算机视觉

在计算机视觉中,如何让计算机在不同角度、光照、尺度下识别出同一个物体,是一个核心挑战。本节将介绍一种经典的局部特征描述子——SIFT(Scale-Invariant Feature Transform,尺度不变特征变换)。它通过寻找图像中稳定的关键点,并生成高维的特征向量来描述这些点,从而实现对图像的旋转、缩放、亮度变化等具有不变性的匹配。学完本节,你将理解SIFT特征的基本原理、构建步骤及其优缺点。

💡 核心导读

  • 局部特征与不变性:理解为何需要寻找对旋转、缩放、亮度变化不敏感的局部特征点。
  • SIFT核心步骤:掌握从构建高斯金字塔、计算DoG空间、寻找极值点,到生成128维描述子的完整流程。
  • 尺度空间与关键点:学习如何在不同尺度下寻找稳定的斑点(Blob)作为关键点。
  • 方向估计与描述子生成:了解如何通过梯度直方图确定关键点主方向,并生成旋转不变的128维特征向量。
  • SIFT的优缺点:认识SIFT特征强大的不变性与独特性,同时也了解其计算复杂度高的缺点。

什么是局部特征与SIFT?

局部特征是指图像中一些稳定的、具有区分性的点(或区域),即使图像发生旋转、缩放、亮度变化甚至部分遮挡,这些点及其周围的特征信息也能在很大程度上保持不变。理想的特征描述子应具备良好的不变性(抗几何与光度变化)、独特性(不同点特征差异大)和充足的数量(少量物体也能产生大量特征点)。

SIFT特征描述子正是基于尺度空间不变性而设计的。它的特点可以概括为:

  1. 良好的不变性:对旋转、尺度缩放、平移、亮度变化、噪声等具有鲁棒性。
  2. 独特性好:信息量丰富,适合在海量特征库中进行快速准确的匹配。
  3. 数量充足:即使是少数物体也能产生大量SIFT特征点。
  4. 计算效率:需要说明的是,原始的SIFT算法计算量较大,其“计算快”的特点通常需要借助硬件加速才能达到实时性。在实际应用中,它比后续的SURF、ORB等特征要慢。

SIFT特征计算的基本原理与步骤

SIFT特征计算的核心思想是:在尺度空间中寻找稳定的极值点作为关键点,然后计算该点邻域内的梯度方向直方图,形成特征描述子。

其计算主要分为四个步骤:

  1. 在DoG尺度空间中获取极值点(关键点)。
  2. 对关键点进行精细化处理(位置插值、剔除低对比度点、去除边缘点)。
  3. 关键点的方向估计。
  4. 关键点描述子的生成。

步骤一:构建尺度空间与DoG

从LoG到DoG

最理想的尺度空间特征检测器是高斯拉普拉斯(Laplacian of Gaussian, LoG),其极值点对应图像中的斑点(Blob),稳定性好。但LoG的计算量非常大。SIFT作者发现,高斯差分(Difference of Gaussians, DoG) 可以很好地近似LoG,且计算上只需简单的图像减法。

直观理解:对同一图像用两个不同标准差(σ\sigma 和 kσk\sigma)的高斯核进行模糊,得到两幅模糊程度不同的图像,两者相减得到的是一个带通响应,它近似于该尺度下的 LoG。LoG 的零值对应边缘,极值对应斑点。因此,在DoG空间中寻找极值点,本质上近似于在LoG空间中寻找稳定的斑点。

import numpy as np
import cv2

# 为了演示DoG的概念,我们构造一个简单的5x5图像块,中心亮,四周暗。
img = np.array([[10, 10, 10, 10, 10],
                [10, 60, 60, 60, 10],
                [10, 60, 90, 60, 10],
                [10, 60, 60, 60, 10],
                [10, 10, 10, 10, 10]], dtype=np.float32)

# 使用两个不同大小的高斯核进行模糊
# 注意:为了在小图像上看到效果,这里使用较小的核和标准差。
blur1 = cv2.GaussianBlur(img, (3, 3), sigmaX=0.5)
blur2 = cv2.GaussianBlur(img, (3, 3), sigmaX=1.0)

# 计算高斯差分 (DoG)
dog = blur2 - blur1

print("原始图像中心区域:")
print(img[1:4, 1:4])
print("\n模糊1 (σ=0.5) 中心区域:")
print(blur1[1:4, 1:4].round(2))
print("\n模糊2 (σ=1.0) 中心区域:")
print(blur2[1:4, 1:4].round(2))
print("\nDoG (模糊2 - 模糊1) 中心区域:")
print(dog[1:4, 1:4].round(2))
原始图像中心区域:
[[60. 60. 60.]
 [60. 90. 60.]
 [60. 60. 60.]]

模糊1 (σ=0.5) 中心区域:
[[50.26 57.19 50.26]
 [57.19 78.58 57.19]
 [50.26 57.19 50.26]]

模糊2 (σ=1.0) 中心区域:
[[38.6  50.01 38.6 ]
 [50.01 66.13 50.01]
 [38.6  50.01 38.6 ]]

DoG (模糊2 - 模糊1) 中心区域:
[[-11.65  -7.18 -11.65]
 [ -7.18 -12.46  -7.18]
 [-11.65  -7.18 -11.65]]

可以看到,DoG结果在中心区域为负值,这反映了从较清晰图像到较模糊图像,中心亮斑的“损失”,这个差异在斑点区域最为显著。

高斯金字塔与Octave

为了检测不同尺度的特征,SIFT构建了一个高斯金字塔。与传统金字塔不同,SIFT金字塔的每一层(相同分辨率)不是一张图,而是用一组递增的σ\sigma参数进行高斯模糊得到的一组图像,这组图像称为一个Octave(八度)。

Octave之间的关系是:下一个Octave(分辨率减半)的底层图像,由当前Octave中从下往上数的倒数第三张图像进行降采样(隔点采样)得到。这样设计的妙处在于,当前Octave倒数第三张图像的模糊尺度恰好是底层图像的2倍(假设尺度因子k按21/s2^{1/s}递增)。降采样后,新Octave底层图像在原图坐标下的等效尺度为2σ2\sigma,而在自身像素坐标下仍记作σ\sigma,尺度就这样连续翻倍。

假设我们在每个Octave内想要在s个尺度层上寻找极值点。为了在DoG空间中进行极值比较(需要上下各一层),DoG图像需要s+2层。进而,生成DoG所需的高斯模糊图像就需要s+3层。通常s=3,所以每个Octave有6层高斯模糊图像,产生5层DoG图像。

步骤二:寻找DoG空间极值点并精细化

极值点检测

关键点初步定义为DoG尺度空间中的局部极值点。检测时,每一个采样点需要与其同尺度的8个邻域点、以及上一尺度和下一尺度的各9个邻域点(共26个点)进行比较,只有当其是这26个点中的最大值或最小值时,才被保留为候选关键点。这保证了关键点在三维空间(x,y,σ)(x, y, \sigma)中都是极值。

关键点精细化

初步找到的极值点位于离散的像素网格和尺度采样上,并不精确。此外,DoG算子对边缘响应较强,一些不稳定的边缘点需要剔除。

  1. 位置与尺度插值:通过拟合三维二次函数来精确定位关键点的亚像素位置和尺度。这使得特征点对尺度和位置的微小变化更稳定。
  2. 剔除低对比度点:将候选点的DoG响应幅值(对比度)与阈值比较(Lowe 原文取 0.03),低于阈值的点易受噪声影响,直接剔除,以增强匹配的稳定性与抗噪能力。
  3. 去除边缘响应:利用关键点处的Hessian矩阵计算主曲率。边缘在某个方向上有很大的主曲率,而在垂直方向很小。通过设定阈值,剔除那些主曲率比值过大的点(即边缘点),保留类似斑点的稳定区域。

经过这些步骤,我们得到了图像中精确的、稳定的关键点,每个点有其位置(x,y)(x, y)、尺度σ\sigma和所在的Octave信息。

关键点方向估计与描述子生成

方向估计(赋予旋转不变性)

为了使描述子具有旋转不变性,需要为每个关键点分配一个主方向。

  1. 计算梯度幅值与方向:在以关键点为中心、半径为3×1.5σ3 \times 1.5\sigma的邻域内,计算每个像素的梯度幅值m(x,y)m(x,y)和方向θ(x,y)\theta(x,y)。 m(x,y)=(L(x+1,y)−L(x−1,y))2+(L(x,y+1)−L(x,y−1))2m(x,y) = \sqrt{(L(x+1,y)-L(x-1,y))^2 + (L(x,y+1)-L(x,y-1))^2} θ(x,y)=arctan⁡((L(x,y+1)−L(x,y−1))/(L(x+1,y)−L(x−1,y)))\theta(x,y) = \arctan((L(x,y+1)-L(x,y-1)) / (L(x+1,y)-L(x-1,y))) 其中LL为关键点所在尺度的高斯模糊图像(实际实现常用 atan2\text{atan2} 保留方向所在象限)。
  2. 生成梯度方向直方图:将360度的方向范围划分为36个柱(每柱10度),用梯度幅值作为权重进行累加。直方图的峰值代表了该关键点邻域梯度的主方向。
  3. 确定主方向与辅方向:将直方图中最高峰值对应的方向作为主方向。同时,为了增强匹配的鲁棒性,任何达到最高峰值80%幅值的方向,都会被创建为一个新的关键点(拥有该辅方向)。因此,一个位置和尺度可能对应多个方向的关键点。

生成128维SIFT描述子

确定了主方向后,就可以构建旋转不变的描述子了。

  1. 坐标轴旋转:将关键点邻域的坐标轴旋转到与主方向一致,确保后续描述与图像旋转无关。
  2. 划分区域与计算梯度:在旋转后的坐标系中,取以关键点为中心的16×1616 \times 16像素窗口。将这个窗口划分为4×44 \times 4个子区域(每个子区域4×44 \times 4像素)。
  3. 生成子区域方向直方图:在每个4×44 \times 4子区域内,计算每个像素的梯度幅值和方向(此时方向已相对主方向归一化)。将方向(0-360度)划分为8个柱(每柱45度),用梯度幅值进行加权累加,形成一个8维的方向直方图向量。
  4. 拼接成特征向量:4×44 \times 4个子区域,每个区域一个8维向量,最终拼接成一个4×4×8=1284 \times 4 \times 8 = 128维的特征向量,这就是SIFT描述子。
  5. 归一化:最后对128维向量进行归一化处理,以进一步减弱光照变化的影响。
import numpy as np

# 模拟SIFT描述子生成中,一个4x4子区域内的梯度方向统计。
# 假设一个4x4子区域,我们已经计算了每个像素相对主方向的梯度方向(0-360度)和幅值。
# 为简化,我们手动指定8个方向bin的累加幅值。

# 假设这是某个子区域统计出的8方向梯度幅值直方图(已加权累加)
subregion_histogram = np.array([1.2, 0.5, 3.1, 0.8, 2.5, 0.1, 1.8, 0.7])

print("一个4x4子区域的8维梯度方向直方图:")
print(subregion_histogram)
print(f"形状: {subregion_histogram.shape}")

# 假设我们有4x4=16个子区域(实际由图像计算得出)
# 这里我们模拟拼接过程:重复上面的直方图16次,形成128维向量(仅为演示,实际每个都不同)
sift_descriptor_demo = np.tile(subregion_histogram, 16)
print(f"\n模拟的完整SIFT描述子向量长度: {len(sift_descriptor_demo)}")
print("前16个元素:", sift_descriptor_demo[:16])
一个4x4子区域的8维梯度方向直方图:
[1.2 0.5 3.1 0.8 2.5 0.1 1.8 0.7]
形状: (8,)

模拟的完整SIFT描述子向量长度: 128
前16个元素: [1.2 0.5 3.1 0.8 2.5 0.1 1.8 0.7 1.2 0.5 3.1 0.8 2.5 0.1 1.8 0.7]

SIFT的优缺点与总结

优点:

  • 强大的不变性:通过尺度空间和方向估计,有效应对缩放、旋转、亮度变化。
  • 独特性好:128维的高维向量包含丰富信息,区分能力强,适合精确匹配。
  • 抗噪性:高斯平滑使其对噪声不敏感。

缺点:

  • 计算复杂度高:构建金字塔、计算DoG、极值检测、方向直方图等步骤都非常耗时,难以满足实时性要求。
  • 专利问题:在过去,SIFT曾受专利保护,限制了其商业应用(专利已过期)。
  • 对模糊和视角极端变化敏感:虽然对一般仿射变换有一定稳定性,但超出其设计范围时性能下降。

尽管如此,SIFT作为一种里程碑式的特征描述子,其设计思想深刻影响了后续的许多特征提取方法(如SURF、ORB)。在OpenCV等库中都有其实现。

# OpenCV 中 SIFT 的基本使用示例(伪代码,因版本差异可能需调整)
# import cv2
# 
# # 创建 SIFT 检测器
# sift = cv2.SIFT_create()
# 
# # 读取图像并检测关键点和描述子
# gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
# kp, des = sift.detectAndCompute(gray, None)
# 
# # kp 是关键点列表,每个关键点包含 pt, size, angle, response 等属性
# # des 是描述子矩阵,每行是一个128维的SIFT特征向量

📝 动手练一练

  1. 概念辨析:SIFT特征描述子分别依靠什么机制来实现对图像旋转、尺度缩放和亮度变化的不变性?
👉 点击查看参考答案
  • 抗旋转:通过计算关键点邻域的梯度方向直方图,将统计出的主方向作为该关键点的参考方向。在生成描述子前,将邻域坐标轴旋转至与主方向对齐,使得后续计算始终基于这个归一化的方向,从而消除了旋转的影响。
  • 抗尺度缩放:通过构建高斯金字塔(尺度空间),并在不同尺度的DoG图像中寻找极值点。这使得找到的关键点本身就带有尺度信息(σ)。无论物体在图像中是大是小,总能在某个合适的尺度层上检测到它对应的特征点。
  • 抗亮度变化:主要依靠梯度信息而非绝对灰度值。SIFT描述子基于梯度幅值和方向,光照均匀变化(如整体变亮/变暗)对梯度计算影响较小。此外,描述子生成后的向量归一化步骤,进一步削弱了光照对比度变化的影响。
  1. 流程思考:如果要在每个Octave的3个尺度层上寻找极值点,请问每个Octave至少需要多少层高斯模糊图像?多少层DoG图像?为什么?
👉 点击查看参考答案
  • DoG图像层数:需要在s=3个尺度层上找极值点。为了判断一个点是否是极值,需要与其上一层和下一层的对应邻域进行比较。因此,用于极值检测的DoG层至少需要 s + 2 = 3 + 2 = 5 层。
  • 高斯模糊图像层数:DoG图像由相邻两层高斯模糊图像相减得到。如果有D层DoG,就需要D+1层高斯模糊图像。因此,至少需要 5 + 1 = 6 层高斯模糊图像。
  • 原因:极值比较需要三维邻域(x, y, scale),缺少上下尺度层就无法确定当前点在尺度维度上是否为极值。

本章小结

本节深入讲解了经典的SIFT局部特征描述子。我们从局部特征的需求出发,理解了SIFT所追求的不变性、独特性和充足性。随后,我们一步步拆解了SIFT的四大核心步骤:在DoG尺度空间找极值点、关键点精细化、方向估计以及最终的128维描述子生成。其中,高斯金字塔与Octave的构建、用DoG近似LoG的巧妙思想、通过梯度直方图确定主方向以实现旋转不变性,都是需要掌握的关键概念。

SIFT特征在深度学习兴起之前,是图像匹配、物体识别等领域不可或缺的工具。虽然其计算速度较慢,但它的设计哲学和稳定性至今仍值得我们学习和借鉴。

📋 行动清单

  • 在脑海中复述SIFT特征从图像到128维向量的完整流水线。
  • 理解“尺度空间”和“旋转不变性”在SIFT中是如何具体实现的。
  • 使用OpenCV(确保版本支持)的cv2.SIFT_create()尝试对简单图像提取SIFT特征,观察关键点的位置和尺度(圆圈大小)。

—— 小象教研组