4. 特征点检测(下):SIFT特征提取原理、尺度空间、关键点定位与方向分配
好,咱们接着聊SIFT。上一节我们把特征点检测的来龙去脉理了一遍,这一节我打算深入SIFT的核心——尺度空间、关键点定位和方向分配。说实话,SIFT这套东西我当年啃了很久,后来在项目里真正用起来,才体会到它为什么能成为经典。
4.1 尺度空间:为什么需要它?
你想想看,一张照片里的物体,离得近和离得远,在图像上的大小完全不一样。如果我们的特征检测器只能识别固定大小的特征,那换个距离就失效了。这显然不行。
SIFT的解决办法是——构建一个尺度空间。说白了,就是对图像做一系列不同尺度的模糊,模拟人眼从近到远看物体的效果。
具体怎么做?用高斯卷积核。公式长这样:
L(x, y, σ) = G(x, y, σ) * I(x, y)
其中 G(x, y, σ) = 1/(2πσ²) * exp(-(x²+y²)/(2σ²))
σ是尺度参数,越大图像越模糊。我习惯把σ想象成“观察距离”——σ小,看到细节;σ大,看到轮廓。
关键点:SIFT不是直接在高斯模糊图上找特征,而是在高斯差分(DoG)图上找。DoG就是相邻尺度的高斯图相减:
D(x, y, σ) = L(x, y, kσ) - L(x, y, σ)
这样做的好处是——DoG近似于尺度归一化的拉普拉斯算子,计算量却小得多。
4.2 高斯金字塔与DoG金字塔
构建尺度空间,实际工程中是用高斯金字塔来实现的。我画了一张图帮你理解这个结构:
嗯,这里要注意——每组(Octave)内的图像尺寸相同,但尺度σ递增。组间则进行2倍下采样。我刚开始实现时,总搞不清组内层数和DoG层数的关系。后来记住一句话:N层高斯图产生N-1层DoG图,就再也没错过。
4.3 关键点定位:在DoG空间中找极值
有了DoG金字塔,下一步就是找关键点了。SIFT的做法是——每个像素点要和它周围的26个邻居比较:
- 同尺度的8个邻域像素
- 上一尺度的9个像素
- 下一尺度的9个像素
如果这个点是最大值或最小值,就把它标记为候选关键点。
我的经验:实际做的时候,边缘响应和低对比度点会混进来很多假关键点。我曾经在纹理丰富的区域一下子检出上万个点,结果匹配时慢得让人崩溃。所以后面两步筛选非常关键。
4.4 精确定位:亚像素级别的优化
DoG空间的极值点是在离散像素上找到的,但真正的极值可能落在像素之间。SIFT用泰勒展开来做亚像素定位:
D(x) = D + (∂D/∂x)ᵀ·x + 0.5·xᵀ·(∂²D/∂x²)·x
求导得偏移量:x̂ = -(∂²D/∂x²)⁻¹ · (∂D/∂x)
如果偏移量x̂在任一维度上大于0.5,说明极值点更靠近另一个像素,我们就挪过去重新算。这个迭代过程一般3-5次就收敛了。
避坑指南:我曾经在低纹理区域遇到迭代不收敛的情况,后来加了最大迭代次数限制(5次)和偏移量阈值(0.5),才稳定下来。另外,|D(x̂)| < 0.03的点直接丢弃,这些都是低对比度的噪声点。
4.5 消除边缘响应:用Hessian矩阵把关
DoG对边缘也有响应,但边缘上的点不稳定——沿着边缘方向位置变化很小,垂直方向变化很大。SIFT用Hessian矩阵来检测这种“坏点”:
H = [[Dxx, Dxy],
[Dxy, Dyy]]
Tr(H) = Dxx + Dyy
Det(H) = Dxx·Dyy - Dxy²
若 Tr(H)² / Det(H) < (r+1)²/r,则保留
r 通常取10
这个公式的物理意义是——如果两个特征值相差太大(比值超过r),说明这个点位于边缘上,不要。
我记得第一次调这个参数时,r设得太小(比如5),结果很多角点也被误杀了。后来改成10,效果好了很多。你可以在自己的数据集上微调这个值。
4.6 方向分配:让特征点拥有“朝向”
关键点定位好了,还得给它分配一个主方向。这样后续的特征描述才能做到旋转不变。
做法是这样的:
- 在关键点所在的尺度上,取邻域窗口(通常16×16像素)
- 计算每个像素的梯度幅值和方向
- 用高斯权重对幅值进行加权(离中心越近权重越大)
- 构建36柱的方向直方图(每柱10度)
- 直方图的峰值就是主方向
梯度计算公式:
m(x,y) = sqrt((L(x+1,y)-L(x-1,y))² + (L(x,y+1)-L(x,y-1))²)
θ(x,y) = atan2(L(x,y+1)-L(x,y-1), L(x+1,y)-L(x-1,y))
一个细节:如果存在另一个峰值,其幅值达到主峰值的80%以上,SIFT会为这个关键点创建多个方向。这意味着同一个位置可能有多个不同朝向的关键点。我刚开始觉得这有点浪费,后来发现对匹配鲁棒性帮助很大——尤其是在图像有旋转时。
4.7 我的一些实践心得
做了这么多年图像融合,SIFT给我的感觉是——它像一位可靠的老朋友。虽然现在有更快的ORB、更鲁棒的A-SIFT,但SIFT的平衡性最好。
几个实用建议:
- 尺度参数σ:默认1.6,但如果你处理的是大尺寸图像(比如4000×3000),可以适当增大到2.0,减少关键点数量,提升速度
- 每组层数S:3层是经典值,纹理丰富的场景可以增加到4层
- 对比度阈值:0.03是Lowe论文的值,实际项目中我常用0.04,能过滤掉更多噪声
好了,SIFT的特征点检测部分就讲到这里。下一节我们会聊特征描述子的构建——也就是如何把关键点周围的信息编码成一个128维的向量,让匹配变得简单可靠。
公众号:蓝海资料掘金营,微信deep3321