前言
图像的特征包含角点、关键点等信息,是图像的重要局部特征。角点、关键点不受平移、旋转等操作的部分影响,常用于目标识别、图像比对、指纹校验等场景。本章依次学习 Harris 角点检测、SIFT 关键点提取,最后基于 SIFT 实现指纹匹配实战,理解局部特征提取与特征匹配的基本流程。
一、Harris 角点检测
1.1 什么是角点
角点是图像中局部区域灰度发生剧烈变化的像素点。在角点位置,无论向哪个方向移动窗口,窗口内像素灰度都会出现明显改变,这类点具备很好的辨识度,可作为图像局部特征。
1.2 API:cv2.cornerHarris()
python
cv2.cornerHarris(img, blockSize, ksize, k[, dst[, borderType]]) -> dst
参数说明:
- img:输入灰度图像。
- blockSize:角点检测时考虑的邻域窗口大小。
- ksize:Sobel 算子求导所用的卷积核窗口大小,一般取 3。
- k:Harris 算法自由系数,常用取值 0.04~0.06。
返回值dst:与输入图像尺寸相同的响应矩阵。矩阵中数值越大,代表该像素为角点的概率越高。
筛选角点常用写法:dst > 0.05 * dst.max(),生成布尔掩码,筛选出高响应的角点位置,再在原图上将角点标记为红色。
1.3 示例代码
python
import cv2
#读取图像
img = cv2.imread(r"D:\pythoncode2\bigdata_ai40\Image\qie.png")
#转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
Harris角点检测
#参数:灰度图像,邻域窗口大小,Sobel算子窗口大小,Harris自由系数
dst = cv2.cornerHarris(gray, 4, 3, 0.04)
#筛选角点:响应值大于最大响应值的5%
img[dst > 0.05 * dst.max()] = [0, 0, 255] # 将角点标记为红色
#显示结果
cv2.imshow("Harris角点检测结果", img)
cv2.waitKey(0)
cv2.destroyAllWindows()

二、SIFT 关键点与描述子提取
Harris 角点不具备尺度不变性,而 *SIFT(尺度不变特征变换)*可以提取关键点(斑点类局部特征),同时生成描述子,对缩放、旋转有较好鲁棒性。
关键点(kp):指图像中辨识度高、稳定性强的局部特征位置,记录了特征点的中心坐标、尺度、方向等基础信息。
描述子(des):是对应关键点的高维特征向量,用于特征比对与匹配。SIFT算法会基于关键点的局部像素信息进行运算,生成128维特征向量,精准记录该区域的纹理、明暗、结构等细节特征,是实现图像特征匹配的核心依据。
2.1 核心 API
- sift = cv2.SIFT_create():创建 SIFT 对象
- kp = sift.detect(gray):只检测关键点,返回关键点对象列表kp
- kp, des = sift.compute(gray, kp):根据关键点计算对应的特征描述子
- drawKeypoints():把关键点绘制到图像上;
flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS可以绘制关键点的方向与大小圆圈。
2.2 SIFT 提取关键点示例代码
python
import cv2
import numpy as np
qie = cv2.imread(r"D:\pythoncode2\bigdata_ai40\Image\qie.png")
qie_gray = cv2.cvtColor(qie, cv2.COLOR_BGR2GRAY)
# 创建sift对象
sift = cv2.SIFT_create()
# 检测关键点
kp = sift.detect(qie_gray)
# 在图上绘制关键点
qie_sift = cv2.drawKeypoints(qie, kp, None, flags = cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
cv2.imshow("qie_sift", qie_sift)
cv2.waitKey(0)
# 计算描述子
kp, des = sift.compute(qie_gray, kp)
print(np.array(kp), kp, des)


三、基于 SIFT+FLANN 的指纹匹配实战
需求说明:
现在有指纹1,指纹2,匹配模板三张图片,要求找到与模板匹配的指纹
指纹1:

指纹2:

模板:

3.1 原理说明
流程:
- 使用 SIFT 分别提取模板指纹、待检测指纹的关键点与描述子;
- FLANN 匹配器对两组描述子做 K 近邻匹配knnMatch;
- 使用 比值测试m.distance < 0.8*n.distance过滤错误匹配对,保留高质量匹配点;
- 统计优质匹配点数量,设置阈值判断指纹是否匹配。本案例中匹配点大于 500 则判定认证通过。
3.2 主要 API
- cv2.FlannBasedMatcher():FLANN全称为快速近似最近邻搜索库,是一种高效的特征匹配器。其通过构建KD树索引结构优化高维特征检索,无需暴力遍历所有特征点,大幅降低计算开销、提升匹配速度,非常适配SIFT高维描述子的大批量匹配场景。
- knnMatch(des1, des2, k=2):寻找模板每个特征找最近两个的待检测指纹特征点,返回形式为元组(m,n)
- m、n为K近邻匹配筛选出的两组最优特征匹配结果,其中m.distance表示模板指纹与待测指纹对应特征点的欧式距离,距离越小代表特征相似度越高;m.queryIdx对应待测图像的关键点索引,m.trainIdx对应模板图像的关键点索引。
3.3 指纹匹配代码
python
import cv2
def cv_show(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
def verification(src,img):
sift = cv2.SIFT_create()
# 一步获取关键点、描述子
kpa,des1 = sift.detectAndCompute(src,None)
kp,des2 = sift.detectAndCompute(img,None)
# FLANN匹配器
flann = cv2.FlannBasedMatcher()
matches = flann.knnMatch(des1,des2,k=2)
good = []
# 比值测试筛选好的匹配
for m,n in matches:
if m.distance < 0.8*n.distance:
good.append((m,n))
num = len(good)
#比较相似数量
if num >500:
result = "认证通过"
else:
result = "认证失败"
return result
if __name__ == "__main__":
#读取指纹1
scr1 = cv2.imread(r"D:\pythoncode\bigdata_ai40\Image\zhiwen1.bmp")
cv_show("src1",scr1)
#读取指纹2
scr2 = cv2.imread(r"D:\pythoncode\bigdata_ai40\Image\zhiwen2.bmp")
cv_show("src2",scr2)
#读取模板
model = cv2.imread(r"D:\pythoncode\bigdata_ai40\Image\zhiwenpipei.bmp")
cv_show("model",model)
result1 = verification(scr1,model)
result2 = verification(scr2,model)
#输出验证结果
print("指纹1验证结果:", result1)
print("指纹2验证结果:", result2)
四、本章小结
- Harris 角点检测寻找灰度剧烈变化的拐角点,输出响应矩阵,但是不具备尺度不变性。
- SIFT 可以同时提取关键点与特征描述子,对缩放、旋转鲁棒性更强。
- FLANN 匹配器完成描述子匹配,比值测试可以剔除错误匹配对,提升匹配可靠性。
- 指纹匹配案例:统计优质匹配点数量,依靠阈值完成身份校验,是局部特征匹配的典型应用。