一前言
今天还是更新了,学无止境吧。
二主要内容
SURF 简介(加速鲁棒特性)
理论
在上一章中,我们看到了使用 SIFT 算法进行特征点的检测和描述。但它相对较慢,人们需要更加快速的算法。 2006 年,Bay,H.,Tuytelaars,T.和 Van Gool,L 三人发表了另一篇论文"SURF:Speeded Up Robust Features",引入了一种名为 SURF 的新算法。顾名思义,它是 SIFT 的加速版本。
在 SIFT 中,Lowe 用高斯差分(DoG)去近似高斯拉普拉斯算子(LoG),从而构造尺度空间。 SURF 则更进一步,用盒子滤波器去近似 LoG。下图显示了这种近似。这种近似的一个很大的优点是,借助积分图像可以很容易地计算出盒子滤波器的卷积,而且可以在不同的尺度空间同时进行计算。同样,SURF 依赖于 Hessian 矩阵的行列式去计算特征点的尺度和位置。

对于主方向,在 SURF 中是对以特征点为中心的 6s(s 为特征点的尺度)为半径的圆形区域内的图像进行 Haar 小波响应运算得到的。使用高斯函数对小波响应进行加权。然后将它们绘制在下图中给出的图像中。通过计算角度为 60 度的定向滑动窗口内的所有响应的总和来估算主方向。有趣的是,任意尺度空间上的小波响应都可以很容易地使用积分图像找到。对于许多应用,不需要旋转不变性,因此无需找到此方向,从而加快了过程。 SURF 提供被称为 Upright-SURF 或 U-SURF 的功能。(其实很简单,SURF是通过削减方向判断从而加快了速度)
旋转的鲁棒性。 OpenCV 支持这两种模式,取决于upright标志位。如果标志位为 0,则计算方向。如果为 1,则不计算方向同时速度更快。

对于特征描述,SURF 在水平和垂直方向上使用小波响应(再次,使用积分图像使事情变得更容易)。在特征点周围获取大小为 20sX20s 的邻域,其中 s 是特征点尺度大小。将它分为 4x4 子区域。对于每个子区域,采用水平和垂直小波响应,并形成一个像这样的矢量,\(\langle v = \sum d_x, \sum d_y, \sum |d_x|, \sum |d_y|\rangle\)。当表示为矢量时,这就是 64 维的 SURF 特征点描述了。(与 SIFT 相比)描述子的维度降低了,计算和匹配的速度提高了,但又提供了更具有独特性的特征。
为了增加特征点的独特性,SURF 特征点描述了具有扩展的 128 维版本。在 \(\langle d_y < 0\rangle\) 和 \(\langle d_y > 0\rangle\) 分别计算 \(\langle d_x\rangle\) 和 \(\langle x^2|d_x^2\rangle\) 的和。类似地,\(|d_y\rangle\) (和 \(|d_x|\)) (的和也根据) \(d_x\) 的符号进行区分,从而使特征数量加倍,但不会增加太多的计算复杂性。OpenCV 支持将 extended 标志位的值分别设置为 0 和 1,0 为 64 维,1 为 128 维(默认为 128 维)。
SURF 采用了许多方法来提高每一步的速度。分析显示在性能相当的情况下它比 SIFT 快 3 倍。 SURF 擅长处理模糊和旋转的图像,但不善于处理视角变化和光照变化。
OpenCV 中的 SURF
OpenCV 就像 SIFT 一样提供 SURF 功能。您使用一些可选参数(如 64/128-dim 描述符,Upright / Normal SURF 等)构造 SURF 对象。所有详细信息都在文档中进行了详细说明。然后就像我们在 SIFT 中所做的那样,我们可以使用 SURF.detect(),SURF.compute()等来查找特征点和描述子。
首先,我们将看到一个关于如何查找 SURF 特征点和描述子并绘制它的简单演示。由于与 SIFT 相同因此所有示例都显示在 Python 终端中。
python
import cv2 as cv
# 读取图像,第二个参数0表示以灰度模式读取
img = cv.imread('fly.png', 0)
# 创建SURF对象,设置Hessian阈值为400
# Hessian阈值用于控制特征点检测的灵敏度
# 值越高,检测到的特征点越少但更稳定
surf = cv.xfeatures2d.SURF_create(400)
# 检测关键点并计算描述子
# kp: 关键点列表(包含位置、尺度、方向等信息)
# des: 描述子矩阵(每行是一个特征点的描述向量)
kp, des = surf.detectAndCompute(img, None)
# 打印检测到的关键点数量
print(len(kp)) # 输出:699
1199 个关键点太多,无法在图片中显示。我们将它减少到大约 50 以将其绘制在图像上。在匹配时,我们可能需要所有这些功能,但现在不需要。所以我们增加了 Hessian 阈值。
python
import cv2
# 读取图像
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# 初始化SURF检测器
surf = cv2.xfeatures2d.SURF_create()
# 检查当前Hessian阈值
print(surf.getHessianThreshold())
# 设置新的Hessian阈值
surf.setHessianThreshold(50000)
# 检测关键点和计算描述子
kp, des = surf.detectAndCompute(img, None)
# 输出关键点数量
print(len(kp))
关键点数量变化分析
| 阈值 | 检测到的关键点数量 | 说明 |
|---|---|---|
| 400 | 699个 | 正常设置,检测到较多特征点 |
| 50000 | 47个 | 极高阈值,只检测到最显著的特征点 |
你可以看到 SURF 更像是斑点检测器。它检测到蝴蝶翅膀上的白色斑点

现在我想试一下 U-SURF,不检测特征点的方向。
python
import cv2
import matplotlib.pyplot as plt
# 读取图像
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)
# 创建 SURF 对象
surf = cv2.xfeatures2d.SURF_create()
# 检查 upright 标志
print(surf.getUpright())
# 如果 upright 为 False,设置为 True
if not surf.getUpright():
surf.setUpright(True)
# 重新计算特征点
kp = surf.detect(img, None)
# 绘制特征点
img2 = cv2.drawKeypoints(img, kp, None, (255, 0, 0), 4)
# 显示结果
plt.imshow(img2)
plt.show()
效果如下,所有方向都以相同的方向显示。它比以前更快。如果您的工作中不需要检测方向(如全景拼接)等,这种方法更好。

今天的代码最好都在python的编译环境下进行,因为我已经试了很多次了,想在虚拟环境直接运行行不通,是无法运行的。
三最后一语
今天更新少一点,大家多理解之前的内容。
我们终此一生,就是要摆脱他人的期待,找到真正的自己。------ 伍绮诗《无声告白》
感谢观看,共勉!!