基于 SIFT 和 FLANN 的指纹图像匹配与认证
指纹识别是生物特征识别中的经典应用,其核心任务是从指纹图像中提取稳定的特征点,并将这些特征与模板指纹进行匹配,从而判断两幅指纹是否属于同一人。本文使用 SIFT 特征点检测 和 FLANN 匹配器 实现简单的指纹认证,并逐行解析代码。
一、整体思路
读取指纹图像:加载待验证指纹和模板指纹。
提取特征点:使用 SIFT 算法检测关键点并计算描述符。
特征点匹配:通过 FLANN 匹配器对两幅图像的描述符进行匹配。
筛选匹配结果:使用 Lowe's 比率测试剔除错误匹配。
统计匹配点数量:根据匹配数量判断认证是否通过。
可视化结果:在指纹图像上标注匹配到的关键点。
二、核心代码解析
import cv2
import numpy as np
我们引入了 OpenCV 和 NumPy,分别用于图像处理和矩阵运算。
1. 图像显示函数
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
简单的封装,用于显示图像并等待用户按键关闭。
2. 特征提取与匹配函数
def verification(src, model):
# 创建SIFT特征提取器
sift = cv2.SIFT_create()
# 检测关键点和计算描述符(特征向量) 源图像
kp1, des1 = sift.detectAndCompute(src, None) # 第二个参数:掩膜
# for k in kp1:
# print(k.pt)
# 检测关键点和计算描述符 模板图像
kp2, des2 = sift.detectAndCompute(model, None)
# 创建FLANN匹配器
flann = cv2.FlannBasedMatcher()
# 使用k近邻匹配(des1中的每个描述符与des2中的最近两个描述符进行匹配)
matches = flann.knnMatch(des1, des2, k=2)
# distance: 匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近。表示查询图像(待匹配的 “目标图”)中特征点的索引。
# imgIdx表示匹配对应的图像索引。当进行多图之间的特征匹配(比如从多个模板图中找与目标图的匹配)时,用这个索引标记当前匹配来自哪一张图像(比如第 0 张、第 1 张模板图)。
# queryIdx: 测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。表示查询图像(待匹配的 “目标图”)中特征点的索引。
# trainIdx: 样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。表示训练图像(用于匹配的 “模板图”)中特征点的索引。
# 进行比较筛选
ok = []
for m, n in matches:
# 根据Lowe's比率测试,选择最佳匹配
if m.distance < 0.4 * n.distance:
ok.append((m,n))
# 统计通过筛选的匹配数量
num = len(ok)
if num >= 10:#500
result = "认证通过"
else:
result = "认证失败"
ok_list = np.array(ok)
if len(ok_list.shape) == 2:
f = ok_list[:,0]
m = ok_list[:,1]
else:
f = []
m = []
f_p = [kp1[a.queryIdx].pt for a in f]
m_p = [kp2[a.trainIdx].pt for a in f]
return result, f_p, m_p
# distance: 匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近。表示查询图像(待匹配的 “目标图”)中特征点的索引。 # imgIdx表示匹配对应的图像索引。当进行多图之间的特征匹配(比如从多个模板图中找与目标图的匹配)时,用这个索引标记当前匹配来自哪一张图像(比如第 0 张、第 1 张模板图)。 # queryIdx: 测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。表示查询图像(待匹配的 “目标图”)中特征点的索引。 # trainIdx: 样本图像的特征点描述符下标,同时也是描述符对应特征点的下标。表示训练图像(用于匹配的 “模板图”)中特征点的索引。
这里使用 SIFT (Scale-Invariant Feature Transform) 算法提取关键点和描述符。
kp1
/kp2
:关键点列表,每个关键点包含位置、尺度、方向等信息。des1
/des2
:描述符数组,通常是 128 维向量,用于表示关键点的局部特征。
3. FLANN 匹配器
FLANN (Fast Library for Approximate Nearest Neighbors) 是一种快速近似最近邻搜索库,非常适合处理大规模高维特征匹配。
这里使用 k=2 的 KNN 匹配,为每个描述符找出两个最近的匹配点,方便后续做比率测试。
4. Lowe's 比率测试
比率测试的思想是:如果最近邻距离远小于次近邻距离,说明匹配更可靠。
这里阈值设置为 0.4(可以根据实际情况调整,0.7 是常见的经验值)。
5. 匹配数量判断与坐标提取
当匹配点数量大于一定阈值(此处为 10),判定认证成功,否则失败。
接着提取匹配点的坐标,方便后续可视化:
if __name__ == "__main__":
finger1 = cv2.imread("finger1.BMP")
cv_show('finger1', finger1)
finger2 = cv2.imread("finger2.BMP")
cv_show('finger2', finger2)
model = cv2.imread("finger3.BMP")
cv_show('model', model)
result1,f1,m1 = verification(finger1, model)
result2,f2,m2 = verification(finger2, model)
for i in f1:
finger1 = cv2.circle(finger1, (int(i[0]), int(i[1])), 3, (0, 0, 255), -1)
for i in m1:
model = cv2.circle(model, (int(i[0]), int(i[1])), 3, (0, 0, 255), -1)
cv_show('finger1', finger1)
cv_show('model', model)
for i in f2:
finger2 = cv2.circle(finger2, (int(i[0]), int(i[1])), 3, (0, 0, 255), -1)
for i in m2:
model = cv2.circle(model, (int(i[0]), int(i[1])), 3, (0, 0, 255), -1)
cv_show('finger2', finger2)
cv_show('model', model)
print("finger1验证结果为:", result1)
print("finger2验证结果为:", result2)
6. 主程序:加载图像与可视化
分别读取两幅待验证指纹和一幅模板指纹,并显示。
7. 验证与绘制关键点
将匹配到的关键点画在原图上(红色圆点),便于直观观察匹配效果。
8. 输出结果
输出指纹认证是否通过。
三、关键概念解析
SIFT 特征点:具有尺度不变性和旋转不变性,适合处理指纹这种局部纹理特征丰富的图像。
FLANN 匹配器:比暴力匹配更高效,适合大规模匹配任务。
Lowe's 比率测试:有效剔除伪匹配,提高准确率。
匹配阈值:匹配点数阈值是影响认证结果的关键参数,需根据数据调整。
四、运行结果与分析
运行程序后,可以直观看到匹配到的关键点。如果匹配数量较多,则输出“认证通过”,否则输出“认证失败”。这种方法适用于简单场景的指纹比对,但在实际应用中还需要:
对图像预处理(去噪、增强对比度)
使用更多鲁棒特征(ORB、深度学习特征)
加入 RANSAC 剔除错误匹配