第四章

特征提取与匹配:给图像提取指纹

第三层 · SIFT/ORB/匹配 两张图怎么“找相同”

一、问题:怎么判断"两张图是同一个东西"

"小陈,拍照搜书的核心问题:你拍一张封面,怎么在 5 万本书里找到最像的那一本?"老周问。

"……像素逐个比对?"

"天真。你拍的封面和数据库里的原图,光线不同、角度不同、大小不同、还有透视变形。 逐像素比对,一样都匹配不上。我们要的是——不管怎么变,都能认出来的'不变特征'。"

图像匹配的难点:
  ① 尺度变化:近拍/远拍,大小不一样
  ② 旋转变化:书歪了
  ③ 光照变化:暗/亮/阴影
  ④ 视角变化:有一点透视
  ⑤ 遮挡:手指挡了一角

  解法:提取"特征点"(关键点 Keypoint)
    = 图像里"与众不同、稳定可重复"的位置
    角点、边缘交点、纹理斑块……
    每个特征点有一个"描述子"(Desriptor)= 它的"指纹"
    → 两张图有大量"相似指纹" → 是同一物体!

"特征提取 = 给图像的'标志性位置'做'指纹'——不管图怎么变,同一物体的特征指纹不会变。这是传统视觉的基石。"


二、角点检测:什么是"特征点"

"先看最简单的特征点——角点(Corner)。"老周说:

角点(Corner Point):
  图像里"两个方向亮度都剧烈变化"的位置
  (如书角、文字拐角、窗户角)

  为什么角点是好的特征?
    平移后还能找到(位置独特)
    旋转后还是角点(性质不变)
    光照变化影响小(局部对比)

  Harris 角点检测(经典):
    cv2.cornerHarris(gray, blockSize, ksize, k)
    → 每个像素一个"角点响应值"
    → 响应值大的 = 角点

  Shi-Tomasi 角点(改进版,OpenCV 常用):
    corners = cv2.goodFeaturesToTrack(gray, maxCorners, qualityLevel, minDistance)
    → 找出 N 个"质量最高"的角点
import cv2
import numpy as np

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

# Harris 角点检测
dst = cv2.cornerHarris(gray, 2, 3, 0.04)
img_corners = img.copy()
img_corners[dst > 0.01 * dst.max()] = [0, 0, 255]   # 角点标红

# Shi-Tomasi 角点(更常用)
corners = cv2.goodFeaturesToTrack(gray, maxCorners=100,
                                  qualityLevel=0.01, minDistance=10)
for c in corners:
    x, y = c.ravel()
    cv2.circle(img, (int(x), int(y)), 3, (0, 255, 0), -1)

"角点是特征的'入门款'——它告诉你'哪里值得关注'。但角点太'弱',尺度一变大就找不到了。要更强,上 SIFT/ORB。"


三、SIFT:尺度不变特征变换(经典王者)

"真正让视觉界沸腾的是 SIFT(尺度不变特征变换)——2004 年 Lowe 提出,能同时应对尺度、旋转、光照变化。"老周说:

SIFT(Scale-Invariant Feature Transform):
  核心思想:在不同尺度(放大/缩小)下都能找到稳定的特征点
  每个特征点有 128 维描述子(向量)= 它的"DNA 指纹"

  为什么强:
    尺度不变:近拍远拍都能匹配(尺度空间金字塔)
    旋转不变:旋转后描述子不变
    光照鲁棒:基于梯度方向,不受亮度整体变化影响
    → 教科书级的经典算法

  注意:SIFT 有专利(已过期),OpenCV 需要 contrib 模块
  OpenCV:
    sift = cv2.SIFT_create()
    kp, des = sift.detectAndCompute(gray, None)
    # kp = 关键点列表;des = 描述子矩阵 (N×128)

四、ORB:又快又免费的"实用派"

"SIFT 强但慢。移动端要快,用 ORB。"老周说:

ORB(Oriented FAST and Rotated BRIEF):
  结合了 FAST(快速角点检测)+ BRIEF(二进制描述子)
  特点:
    快(比 SIFT 快 1-2 个数量级)
    免费(无专利)
    描述子是二进制的(匹配用汉明距离,超快)
  缺点:尺度不变性不如 SIFT(可配合金字塔改善)

  OpenCV:
    orb = cv2.ORB_create(nfeatures=500)
    kp, des = orb.detectAndCompute(gray, None)

  选型:
    要精度(匹配质量)→ SIFT
    要速度(实时/移动端)→ ORB
    现在很多场景已被深度学习替代,但传统特征
    在"图像拼接、SLAM、纹理匹配"仍有价值

五、特征匹配:找相同指纹

"有了特征点,怎么判断两张图相似?特征匹配(Feature Matching)。"老周说:

import cv2

# 两张图提取特征
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1, None)
kp2, des2 = orb.detectAndCompute(img2, None)

# 暴力匹配(ORB 用汉明距离)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1, des2)

# 按距离排序(距离小 = 相似)
matches = sorted(matches, key=lambda m: m.distance)

# 取前 N 个好匹配画出来
good = matches[:50]
result = cv2.drawMatches(img1, kp1, img2, kp2, good, None)

# FLANN 匹配(SIFT 大数据量用,更快)
# flann = cv2.FlannBasedMatcher(dict(algorithm=1, trees=5), {})
# matches = flann.knnMatch(des1, des2, k=2)
匹配评估:
  匹配数量:越多越好
  匹配质量:平均距离越小越好(指纹越接近)
  比率测试(Lowe's ratio test):
    最匹配距离 / 次匹配距离 < 0.7 → 保留(更可靠)
    → 过滤错误匹配(误匹配的克星)

  怎么判断"是同一本书"?
    匹配数 > 阈值 且 质量好 → 判定同一封面
    云间书店:拍照封面 vs 数据库封面做匹配
    → 匹配分最高的书 = 搜索结果

"特征匹配 = 比指纹——两张图的特征描述子大量相似,就是同一个东西。比率测试是过滤误匹配的关键技巧,面试常考。"


六、图像拼接与全景:特征匹配的经典应用

"特征匹配最经典的应用之一:图像拼接(Image Stitching)——把多张照片拼成全景图。"老周说:

图像拼接流程:
  ① 拍多张有重叠的图(云间书店书架全景)
  ② 提取特征(SIFT/ORB)
  ③ 匹配相邻图特征
  ④ 计算变换矩阵(Homography,单应性矩阵)
  ⑤ 图像变换对齐 + 融合拼接
  ⑥ 输出全景图

  OpenCV 一行实现:
  stitcher = cv2.Stitcher_create()
  status, pano = stitcher.stitch([img1, img2, img3])
  # status 0 = 成功,pano = 全景图

  背后的数学:单应性变换
    找到 4 对以上匹配点 → 解出 8 参数变换矩阵
    → 一张图可以"变形"到另一张图的角度

  应用:手机全景拍照、地图街景拼接、文档拼接

"图像拼接是'特征提取+匹配'的综合大作业——手机的全景拍照,就是这个流程。看懂它,你就懂了传统视觉的'经典三件套':特征、匹配、变换。"


七、章末:老周的第四章总结

第三层:特征提取与匹配
├── 问题:图像会变(尺度/旋转/光照/视角),怎么认得出
├── 特征点 = 图像的"标志位置"(角点/斑块)
├── Harris / Shi-Tomasi:角点检测(入门款)
├── SIFT:尺度不变王者(128维描述子,慢但准)
├── ORB:快速免费(二进制描述子,实时首选)
├── 特征匹配:比指纹(汉明距离 + 比率测试过滤误匹配)
├── 应用:图像拼接(特征+匹配+单应性变换=全景)
└── 现代:很多场景被深度学习替代,但经典仍有用武之地
第五层(预告):传统机器学习视觉 —— 用 SVM 给图书分类

"小陈,你现在能给图像'提取指纹'、'比对指纹'了——这是传统视觉的看家本领。"老周说,"但光有特征还不够:拍照搜书,我们要的是'这张封面属于哪个类别(哪本书)'。下一章,我们进入机器学习——用 HOG 特征 + SVM 分类器,让机器学会'看图归类'。这是深度学习的'前辈',理解了它,后面的 CNN 会好懂很多。"

✌ 语言