兴趣点检测

前面几章讨论了如何对图像进行低层处理(滤波、边缘检测)和中层分析(分割)。本章进入一个新的问题领域:如何在不同图像之间建立对应关系(Correspondence)——找到两张图像中描述同一个物理点的像素。这是图像匹配、三维重建、物体识别和目标追踪的基础。

核心挑战在于:两张图像的拍摄条件(视角、距离、光照)可能完全不同,我们需要在每张图像中独立地找到一组「特别的」点,使得这些点在不同条件下仍然能被重复检测到,并且能通过描述它们的局部外观来判断哪个点对应哪个点。

想象你和朋友约好在一张航拍照片上碰面——你会选择哪个位置?大概率是某个道路交叉口、建筑物的拐角,而不是一片空旷的田野或一条笔直的公路。换一个场景:如果航拍照片里有一个圆形的陨石坑,你也可能选择它的中心。前者是角点检测的目标,后者是斑点检测的目标——本章要讨论的两类关键点检测器恰好对应这两种直觉。

关键点匹配的整体流程

兴趣点(Interest Points)也称关键点(Keypoints)或局部特征(Local Features),是图像中「与众不同」的点——在它们周围的局部区域有某种独特的结构,使得即使图像发生变化,这些点仍然能被可靠地找到。

关键点匹配分为五个步骤:

  1. 检测:在每张图像中独立找到一组关键点
  2. 定义区域:为每个关键点确定一个局部区域(大小和方向)
  3. 归一化:将区域统一缩放到固定大小
  4. 描述:从归一化的区域中提取一个紧凑的特征向量(描述子)
  5. 匹配:比较两张图像中描述子之间的距离,距离小于阈值的认为匹配

本章聚焦前两步——如何检测关键点以及如何确定其尺度。描述子的构建将在下一章讨论。

好的关键点需要什么

一个好的关键点检测器必须在两个相互矛盾的目标之间取得平衡:

可重复性(Repeatability):尽管图像经历了几何变换(旋转、缩放)和光度变化(亮度、对比度),同一个物理点仍然能在不同图像中被检测到。这要求检测器对变换不敏感——但检测到的点越少,遗漏的风险越大。

可区分性(Distinctiveness):每个关键点的描述必须足够独特,使得可以可靠地判断两个点是否对应同一个位置。这要求局部区域有丰富的信息——但过于严格的筛选可能丢掉有用的特征。

这两个目标之间存在张力。在检测端:追求可重复性意味着更鲁棒的检测和更精确的定位,但可能丢掉一些有用的点;追求更多的点则对遮挡更鲁棒、对纹理稀少的区域也能工作,但可能引入不可重复的虚假检测。在描述端类似:更独特的描述能减少错误匹配,但更灵活的描述对预期变化更鲁棒、能最大化正确匹配数。

此外还需要紧凑性(关键点数远少于像素数)和局部性(每个特征占据的区域足够小,对遮挡和杂乱背景有鲁棒性)。

Harris 角点检测器

什么样的点是好的关键点

想象透过一个小窗口观察图像。将窗口沿各个方向微小平移,观察窗口内像素值的变化:

  • 平坦区域:无论往哪个方向移动,窗口内的内容几乎不变——没有可辨识的特征
  • 边缘:沿边缘方向移动不变,垂直于边缘方向才有变化——只有一个方向有信息
  • 角点:无论往哪个方向移动都有显著变化——这正是我们要找的

自相关函数

将上述直觉形式化。定义窗口平移 [u,v][u, v] 后的自相关函数(误差函数):

E(u,v)=x,yw(x,y)[I(x+u,y+v)I(x,y)]2E(u, v) = \sum_{x, y} w(x, y) \bigl[I(x+u, y+v) - I(x, y)\bigr]^2

其中 w(x,y)w(x, y) 是窗口函数(可以是矩形窗或高斯窗)。E(u,v)E(u, v) 衡量的是平移后图像块与原始块的差异——EE 越大,说明该方向上的变化越剧烈。

直接对所有可能的 [u,v][u, v] 计算 EE 代价很大。如果平移量 [u,v][u, v] 很小,可以用 Taylor 展开来近似——这样 EE 就变成了一个关于 [u,v][u, v] 的二次型,其形状完全由一个 2×22 \times 2 矩阵决定。

I(x+u,y+v)I(x+u, y+v)(u,v)=(0,0)(u, v) = (0, 0) 处做一阶 Taylor 展开:I(x+u,y+v)I(x,y)+Ixu+IyvI(x+u, y+v) \approx I(x, y) + I_x u + I_y v,代入后得到:

E(u,v)[uv]M[uv]E(u, v) \approx \begin{bmatrix} u & v \end{bmatrix} \bm{M} \begin{bmatrix} u \\ v \end{bmatrix}

其中 M\bm{M}2×22 \times 2二阶矩矩阵(Second Moment Matrix),也称结构张量(Structure Tensor):

M=x,yw(x,y)[Ix2IxIyIxIyIy2]\bm{M} = \sum_{x, y} w(x, y) \begin{bmatrix} I_x^2 & I_x I_y \\ I_x I_y & I_y^2 \end{bmatrix}

实际实现中通常用高斯权重代替矩形窗:M=g(σI)[Ix2(σD)IxIy(σD)IxIy(σD)Iy2(σD)]\bm{M} = g(\sigma_I) * \begin{bmatrix} I_x^2(\sigma_D) & I_x I_y(\sigma_D) \\ I_x I_y(\sigma_D) & I_y^2(\sigma_D) \end{bmatrix},其中 σD\sigma_D 是求导时的平滑尺度,σI\sigma_I 是积分(加权求和)时的平滑尺度。

特征值的直觉

M\bm{M} 是对称半正定矩阵,可以做特征值分解:M=R1[λ100λ2]R\bm{M} = \bm{R}^{-1} \begin{bmatrix} \lambda_1 & 0 \\ 0 & \lambda_2 \end{bmatrix} \bm{R}

E(u,v)E(u, v)(u,v)(u, v) 平面上描绘了一个椭圆形的「碗」。可以把 E(u,v)E(u, v) 想象为一个三维曲面——uuvv 是水平坐标,EE 值是高度:

  • 平坦区域的曲面几乎是平的,无论怎么移动窗口 EE 都不变
  • 边缘区域的曲面是一个长长的「山谷」,只有垂直于边缘方向才有变化
  • 角点区域的曲面是一个陡峭的「碗」,向任何方向移动 EE 都迅速增大

两个特征值决定了碗的形状——椭圆的半轴长度正比于 λ1/2\lambda^{-1/2}

λ1\lambda_1, λ2\lambda_2 的关系 椭圆形状 对应结构
都很小 大而扁平的圆 平坦区域
λ1λ2\lambda_1 \gg \lambda_2 窄长的椭圆 垂直边缘
λ2λ1\lambda_2 \gg \lambda_1 窄长的椭圆(另一方向) 水平边缘
都很大且 λ1λ2\lambda_1 \approx \lambda_2 小而圆 角点

角点度量函数

直接计算特征值需要做特征值分解,计算量大。Harris 提出了一个不需要显式计算特征值的角点响应函数

R=det(M)κtrace2(M)R = \det(\bm{M}) - \kappa \cdot \text{trace}^2(\bm{M})

其中 det(M)=λ1λ2\det(\bm{M}) = \lambda_1 \lambda_2trace(M)=λ1+λ2\text{trace}(\bm{M}) = \lambda_1 + \lambda_2κ\kappa 是经验常数(通常取 0.040.060.04 \sim 0.06)。将 M\bm{M} 的元素代入展开:

R=g(Ix2)g(Iy2)[g(IxIy)]2κ[g(Ix2)+g(Iy2)]2R = g(I_x^2) \cdot g(I_y^2) - [g(I_x I_y)]^2 - \kappa \cdot [g(I_x^2) + g(I_y^2)]^2

这个展开式清楚地显示了计算 RR 只需要三个平滑后的导数乘积图——完全不需要做特征值分解。

R>0R > 0 且较大时,两个特征值都大——角点;R<0R < 0 时,一个特征值远大于另一个——边缘;R|R| 很小时——平坦区域。

其他角点度量

  • Shi-Tomasi 准则(常用于追踪):R=min(λ1,λ2)R = \min(\lambda_1, \lambda_2)——直接取较小特征值,物理含义清晰:只有当两个方向上的变化都足够大时,RR 才大
  • Noble 准则(调和平均):R=λ1λ2λ1+λ2=det(M)trace(M)+εR = \dfrac{\lambda_1 \lambda_2}{\lambda_1 + \lambda_2} = \dfrac{\det(\bm{M})}{\text{trace}(\bm{M}) + \varepsilon}——不需要 κ\kappa 参数,ε\varepsilon 是避免除零的小常数

Harris 检测器的完整流程

  1. 计算图像的偏导数 IxI_xIyI_y(可选先做高斯平滑)
  2. 计算导数的平方和乘积:Ix2I_x^2Iy2I_y^2IxIyI_x I_y
  3. 用高斯滤波器 g(σI)g(\sigma_I) 平滑上述三个图像
  4. 计算角点响应函数 RR
  5. 非极大值抑制,保留局部最大值
1
2
3
4
5
6
7
8
9
import cv2
import numpy as np

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY).astype(np.float32)
# OpenCV 提供了一步到位的 Harris 角点检测
# blockSize=2: 邻域大小, ksize=3: Sobel 核大小, k=0.04: Harris 参数 κ
harris_response = cv2.cornerHarris(gray, blockSize=2, ksize=3, k=0.04)
# 阈值化 + NMS
corners = harris_response > 0.01 * harris_response.max()

不变性分析

理解 Harris 检测器在哪些变换下保持不变非常重要——这决定了它的适用范围。

旋转不变。图像旋转后,M\bm{M} 的特征向量方向改变(椭圆旋转了),但特征值不变(椭圆的形状不变)——RR 不受影响。所以同一个角点在旋转后的图像中仍然会被检测到。

对亮度偏移不变II+bI \to I + b 时,导数不变(IxI_x 只依赖差分),因此 M\bm{M} 不变,RR 不变。

对亮度缩放部分不变IaII \to aI 时,IxaIxI_x \to aI_xMa2M\bm{M} \to a^2 \bm{M}Ra4RR \to a^4 R——绝对值变了,但如果用自适应阈值(如取 RR 的最大值的某个百分比),检测到的角点位置大致不变。

综合来看,Harris 对仿射亮度变换 IaI+bI \to aI + b 具有部分不变性——对偏移完全不变,对缩放在自适应阈值下近似不变。

Harris 不具备尺度不变性

一个角在近处是角点,放远(缩小)后同样大小的窗口覆盖了更大的物理范围,角点可能变成了一条边缘。这意味着如果两张图像的尺度不同,Harris 在两张图中可能检测到完全不同的点——无法建立对应关系。

Hessian 检测器

Harris 检测器基于一阶导数的外积(结构张量)来寻找角点。另一种思路是直接使用二阶导数——Hessian 检测器使用图像的二阶导数矩阵来检测关键点:

H(I,σ)=[Ixx(x,σ)Ixy(x,σ)Ixy(x,σ)Iyy(x,σ)]\bm{H}(I, \sigma) = \begin{bmatrix} I_{xx}(x, \sigma) & I_{xy}(x, \sigma) \\ I_{xy}(x, \sigma) & I_{yy}(x, \sigma) \end{bmatrix}

Harris 关注的是「局部梯度在各方向上的分布」(一阶导数的统计);Hessian 关注的是「亮度函数在各方向上的曲率」(二阶导数本身)。直觉是寻找在两个正交方向上都有强曲率的位置——这样的位置通常是角点或斑点中心。

检测准则是 Hessian 行列式的局部极大值:det(H)=IxxIyyIxy2\det(\bm{H}) = I_{xx} I_{yy} - I_{xy}^2

与 Harris 相比,Hessian 的响应特征不同:Harris 对角点有非常精确的定位,而 Hessian 不仅对角点有响应,对强纹理区域(如密集的条纹或圆点图案)也有响应——它更像是一个「斑点检测器」。注意 Hessian 矩阵可以带尺度参数 σ\sigma,这使得它天然适合多尺度检测。

尺度不变区域检测

到此为止,Harris 和 Hessian 能够精确定位关键点的空间位置 (x,y)(x, y)。但如果两张图像的拍摄距离不同,同一个物理结构在图像中占据的像素数量不同——我们还需要知道每个关键点对应多大的区域。这就是尺度选择问题。

为什么需要自动尺度选择

假设我们已经检测到了关键点的位置,接下来要为每个关键点提取一个局部区域来计算描述子。但区域多大?如果不知道关键点对应的尺度,两张图中同一个物理点的区域大小可能不一致,导致描述子完全不同。

朴素的方法是穷举所有可能的尺度——在每个关键点处尝试不同大小的窗口,比较描述子。这种穷举搜索对于两张图之间的匹配尚可接受(虽然效率低),但对于大规模图像检索和物体识别来说完全不可行——你不可能为每张图的每个关键点存储所有可能尺度的描述子。

自动尺度选择的核心思想

更聪明的做法是:设计一个关于区域大小的函数(称为特征函数签名函数),使其在与物体结构尺度匹配时产生极值。关键性质是:如果物体在图像中变大了 ss 倍,这个函数的极值位置也会移动 ss 倍——因此在不同尺度的图像中独立地寻找极值,就能自动找到与物体尺度匹配的区域。

具体地说,想象对一个圆形斑点分别用不同 σ\sigmaLoG 滤波器响应:当 σ\sigma 太小时,滤波器只覆盖斑点的一小部分,响应不强;当 σ\sigma 太大时,滤波器远超斑点范围,正负区域互相抵消;只有当 σ\sigma 恰好匹配斑点大小时,响应达到最大值。如果同一个斑点在另一张图中因距离不同而变大了,最大响应对应的 σ\sigma 也会相应变大——这就是尺度不变性的来源。

LoG 作为特征尺度函数

什么函数具备这种性质?尺度归一化的高斯拉普拉斯算子(Scale-normalized LoG)是一个经典选择:

L(x,y,σ)=σ2(Gxx(x,y,σ)+Gyy(x,y,σ))L(x, y, \sigma) = \sigma^2 \bigl(G_{xx}(x, y, \sigma) + G_{yy}(x, y, \sigma)\bigr)

σ2\sigma^2 归一化是关键——没有它,随着 σ\sigma 增大,LoG 的响应会自然衰减,无法公平比较不同尺度的响应。

LoG 本质上是一个斑点检测器:它对大小与 σ\sigma 匹配的圆形结构(斑点)有最强响应。

直觉可以从一维信号理解:想象一个宽度为 ww 的矩形脉冲,用不同 σ\sigmaLoG 去卷积它。当 σw\sigma \ll w 时,LoG 只能「看到」脉冲的边缘,响应不强;当 σw\sigma \gg w 时,脉冲相对于 LoG 太小,正负区域相互抵消;只有当 σw\sigma \approx w 时,LoG 的正中心恰好覆盖整个脉冲,响应达到峰值。这个峰值对应的 σ\sigma 就是该脉冲的特征尺度(Characteristic Scale)。

在二维中同理:当 σ\sigma 恰好等于斑点的半径时,LoG 响应达到峰值。对同一个物体在不同尺度的图像中,峰值对应的 σ\sigma 成比例变化——例如一朵向日葵的中心在全尺寸图像中特征尺度为 σ9.8\sigma \approx 9.8,在 3/4 尺寸图像中变为 σ6.0\sigma \approx 6.0,比例恰好约为 3/4。

LoG 检测器的工作流程

  1. 在多个尺度 σ1,σ2,,σn\sigma_1, \sigma_2, \ldots, \sigma_n 上计算 σ22GI\sigma^2 \nabla^2 G * I,得到一组响应图
  2. 将所有尺度的响应图堆叠成三维尺度空间(Scale Space)
  3. (x,y,σ)(x, y, \sigma) 三维空间中寻找局部极大值——即同时在空间和尺度上都是极值的点
  4. 每个极值点输出一个三元组 (x,y,σ)(x, y, \sigma)——位置加尺度

找到特征尺度 σ\sigma 后,以 (x,y)(x, y) 为中心、cσc\sigmacc 为常数)为半径提取圆形区域,然后将其缩放到固定大小(如 41×4141 \times 41 像素)——这样不同尺度的关键点都得到了统一大小的图像块,可以公平地计算描述子。

DoG 近似

直接计算 LoG 需要二阶导数,计算量大。实践中常用高斯差分DoG)来近似:

DoG(x,y,σ)=G(x,y,kσ)G(x,y,σ)(k1)σ22G\text{DoG}(x, y, \sigma) = G(x, y, k\sigma) - G(x, y, \sigma) \approx (k-1) \sigma^2 \nabla^2 G

为什么 DoG 能近似 LoG?因为热方程告诉我们  ⁣G/ ⁣σ=σ2G\pd G / \pd \sigma = \sigma \nabla^2 G,对 σ\sigma 取有限差分就得到 G(kσ)G(σ)(k1)σ ⁣G/ ⁣σ=(k1)σ22GG(k\sigma) - G(\sigma) \approx (k-1)\sigma \cdot \pd G / \pd \sigma = (k-1)\sigma^2 \nabla^2 G。常数因子 (k1)(k-1) 对所有尺度相同,不影响极值位置。

DoG 的实用优势在于:不需要计算导数,而且高斯金字塔在构建过程中已经计算了不同 σ\sigma 的高斯模糊图像——相邻层之差就是 DoG,几乎不需要额外计算。

具体实现中,高斯金字塔按倍频程(Octave)组织:每个 octave 内 σ\sigma 以固定比例递增(如 k=21/sk = 2^{1/s}ss 为每个 octave 的层数),相邻 octave 之间图像尺寸减半。在每个 octave 内,相邻高斯层之差构成 DoG 层,关键点在这些 DoG 层的 (x,y,σ)(x, y, \sigma) 空间中检测。

DoG 检测器的关键点定位

  1. 在高斯金字塔中计算相邻层之差,得到 DoG 金字塔
  2. DoG 尺度空间中寻找 (x,y,σ)(x, y, \sigma) 的局部极大值(比较 26 个邻居:同层 8 个 + 上下层各 9 个)
  3. 剔除低对比度点(响应阈值)
  4. 剔除边缘响应点(用 Hessian 矩阵的主曲率比判断)
  5. 输出候选关键点列表 (x,y,σ)(x, y, \sigma)

例如对一张 233×189233 \times 189 的图像,DoG 检测到 832 个极值点;经对比度阈值筛选后剩 729 个;再剔除边缘响应后剩 536 个——每一步都在去掉不可靠的候选。

组合检测器

LoG/DoG 检测斑点,Harris/Hessian 检测角点——它们的强项不同。将两者结合可以获得更好的效果:

Harris-Laplacian:先在多个尺度上运行 Harris 角点检测器,在每个尺度上独立找到空间极大值;然后对每个候选点,沿尺度轴检查 LoG 响应是否也是极值——只有同时在空间(Harris)和尺度(LoG)上都是极值的点才被保留。

Hessian-Laplacian:同样的流程,只是用 Hessian 代替 Harris 做空间定位。

flowchart TD
    subgraph 空间定位
        H["Harris<br/>(角点)"]
        HE["Hessian<br/>(角点 + 斑点)"]
    end
    subgraph 尺度选择
        L["LoG / DoG<br/>(特征尺度)"]
    end
    subgraph 组合
        HL["Harris-Laplacian"]
        HEL["Hessian-Laplacian"]
        DOG["DoG 检测器<br/>(SIFT 使用)"]
    end

    H --> HL
    HE --> HEL
    L --> HL
    L --> HEL
    L --> DOG

    classDef spatial fill:#e3f2fd,stroke:#1565c0,stroke-width:2px
    classDef scale fill:#e8f5e8,stroke:#2e7d32,stroke-width:2px
    classDef combo fill:#fff3e0,stroke:#ef6c00,stroke-width:2px

    class H,HE spatial
    class L scale
    class HL,HEL,DOG combo

总结

检测器 检测什么 尺度不变 旋转不变 特点
Harris 角点 精确定位,广泛使用
Hessian 角点 + 斑点 对纹理也有响应
LoG 斑点 自动确定特征尺度
DoG 斑点 LoG 的高效近似,SIFT 使用
Harris-Laplacian 角点 Harris 空间定位 + LoG 尺度选择
Hessian-Laplacian 角点 + 斑点 Hessian 空间定位 + LoG 尺度选择

检测器输出的是一组 (x,y,σ)(x, y, \sigma) 三元组——位置和尺度。下一章将讨论如何在这些关键点上构建描述子(如 SIFT),以实现跨图像的匹配。