特征点检测:图像配准的“地基”

图像配准这事儿,说白了就是找两张图之间的对应关系。怎么找?你得先找到那些“有特征”的点。这就好比你要把两张拼图拼在一起,得先找到拼图块边缘的独特花纹。特征点,就是图像里的那些“独特花纹”。

这一章,我们重点聊聊几种最常用的特征点检测方法。我个人在项目里用得最多的就是它们,几乎涵盖了从简单到复杂的所有场景。

特征点检测方法分类与对比 特征点检测 角点检测 尺度不变特征 快速特征 Harris Shi-Tomasi SIFT SURF ORB 核心对比 ● 角点检测:计算快,但无尺度不变性 ● SIFT/SURF:尺度/旋转不变,但计算慢 ● ORB:速度快,适合实时系统 ● 选型:看你配准场景对速度和精度的要求 小提示:SIFT/SURF的特征描述子维度高,匹配时通常用KD-Tree或暴力匹配; ORB用汉明距离,计算效率高一个量级。

角点检测入门:Harris 与 Shi-Tomasi

角点,就是图像中那些两条边交汇的地方。比如说,一张桌子的四个角,或者一个窗户的拐角。为什么它们重要?因为角点在图像发生平移、旋转甚至光照变化时,依然能保持稳定。我在做卫星图像配准时遇到过,有些区域纹理很弱,但角点总能提供可靠的锚点。

Harris 角点检测

Harris 角点检测的核心思想,说白了就是判断一个像素在周围小窗口里,往哪个方向移动,灰度变化都很大。如果灰度变化各向同性,那它就是角点。

它通过一个数学上的协方差矩阵(结构张量)来计算。矩阵的两个特征值,一个代表沿着边缘方向的梯度变化,另一个代表垂直方向的变化。如果两个特征值都大,就是角点。

我的一点心得:Harris 对旋转和部分光照变化不敏感,但对尺度变化非常敏感。你想想看,一个角点在远处看可能就是个点,但近处看却是一块区域。这就没法直接用了。

Shi-Tomasi 改进

Shi-Tomasi 可以看成是 Harris 的一个小变种。它发现,直接用后面那个公式里的 R 值来衡量角点,有时候不准。不如直接用两个特征值中的较小值。如果这个最小值大于某个阈值,那它就是个好角点。

这个改动看似简单,实际效果却好不少。OpenCV 里的 goodFeaturesToTrack 函数,用的就是 Shi-Tomasi 方法。我建议你在项目里可以优先试试它。

尺度不变特征:SIFT 与 SURF

刚才提到,角点检测怕尺度变化。如果你的配准场景里,两张图拍摄距离不一样,那角点就基本废了。这时候就需要尺度不变特征了。SIFT 就是这方面的祖师爷。

SIFT(Scale-Invariant Feature Transform)

SIFT 的全称是“尺度不变特征变换”。它首先构建一个图像尺度空间。怎么构建?通过对图像进行不同尺度的高斯模糊,然后差分。在差分尺度空间里,找那些在多个尺度下都能稳定存在的极值点。这些点就是候选关键点。

然后对这些候选点进行精确定位,去除低对比度的点和边缘响应点。最后给每个关键点分配一个主方向,并生成一个 128 维的特征描述子。这个描述子对旋转、缩放、光照变化都有很强的鲁棒性。

SIFT 关键点生成步骤(简版):

  1. 尺度空间极值检测(DoG 金字塔)
  2. 关键点定位(去掉低对比度和边缘点)
  3. 方向分配
  4. 描述子生成

SIFT 精度很高,但速度慢。而且它是有专利的,商用要小心。不过 OpenCV 里已经内置了,你用的时候只需要知道原理就行。

注意: 我曾经遇到一个坑,就是直接用 SIFT 配准超大尺寸的卫星图,结果内存直接爆了。这种情况下,你最好先把图像缩小,或者用分块策略。

SURF(Speeded Up Robust Features)

SURF 可以看作是 SIFT 的加速版。它用盒式滤波器代替高斯滤波,用积分图加速计算。特征描述子也从 128 维降到了 64 维。速度大概是 SIFT 的 3-7 倍,但精度略有下降。

说真的,在现在这个时代,如果你追求速度,ORB 可能更好;如果追求精度,SIFT 仍然是标杆。SURF 处于一个比较尴尬的位置。不过在一些老项目或特定场景里,它还是有价值的。我个人十分推荐在表格对比里保留它。

实时利器:ORB 特征

ORB 是 OpenCV Lab 搞出来的,全称是 Oriented FAST and Rotated BRIEF。它把两种已知算法 FAST 和 BRIEF 结合了起来,还做了旋转不变性改进。计算速度非常快,完全免费,没有专利问题。

ORB 首先用 FAST 算法快速检测角点,然后为每个特征点计算一个方向,再用改进后的 BRIEF 描述子(叫做 rBRIEF)来生成二进制描述子。这个描述子是二进制的,所以在匹配时可以用汉明距离,计算量小,速度快。

记住一点:ORB 虽然有方向,但它对尺度变化还是敏感的。如果你要配准的两张图尺度差很大,ORB 可能不太行。我记得有一次做无人机拼接,因为飞行高度变化明显,ORB 的效果就远不如 SIFT。

下面这张表格,是我在实际项目里常用的对比,大家可以参考下:

方法 尺度不变 旋转不变 速度 推荐场景
Harris 否 是 快 简单场景、教学实验
Shi-Tomasi 否 是 快 与 Harris 类似,更好用
SIFT 是 是 慢 高精度、遥感、医学图像
SURF 是 是 中等 需要加速的 SIFT 场景
ORB 否 是 极快 实时系统、嵌入式、手机端

代码实战:如何在 OpenCV 里调用

说了这么多理论,咱们还是得上手。在 OpenCV 里,调用这些特征检测器很简单。我给大家贴两个最常用的示例:一个是用 SIFT,一个是用 ORB。

import cv2

# 读取图像
img = cv2.imread('image.jpg', cv2.IMREAD_GRAYSCALE)

# SIFT 检测
sift = cv2.SIFT_create()
keypoints_sift, descriptors_sift = sift.detectAndCompute(img, None)

# ORB 检测
orb = cv2.ORB_create()
keypoints_orb, descriptors_orb = orb.detectAndCompute(img, None)

# 画出来看看
img_sift = cv2.drawKeypoints(img, keypoints_sift, None, color=(0, 255, 0))
img_orb = cv2.drawKeypoints(img, keypoints_orb, None, color=(0, 255, 0))

cv2.imshow('SIFT Keypoints', img_sift)
cv2.imshow('ORB Keypoints', img_orb)
cv2.waitKey(0)

代码很简洁。关键就是这个 detectAndCompute 函数,一步到位,既检测了关键点位置,又生成了描述子。我个人习惯上会先打印出关键点的数量和描述子的维度,确认一下数据对不对。

一点建议:如果你对 SIFT 和 SURF 的尺度空间构建过程感兴趣,可以自己调一下它们的参数,比如 nfeatures、nOctaveLayers。别看默认参数很泛用,配不同的图像,效果可能会差很多。

特征点检测是图像配准的第一步,也是最重要的一步。点选得好,后面的匹配和变换就稳了;点选得不好,后面再怎么调也没用。所以,花点时间理解这些算法的特点,并根据你的实际场景做选择,非常值得。