`
文章目录
-
- 一、角点检测基础
-
- [1.1 Harris角点检测原理](#1.1 Harris角点检测原理)
- [1.2 代码实现与参数解析](#1.2 代码实现与参数解析)
- 二、SIFT特征提取
-
- [2.1 SIFT特征提取流程](#2.1 SIFT特征提取流程)
- [2.2 关键点属性详解](#2.2 关键点属性详解)
- [2.3 描述符计算](#2.3 描述符计算)
- 三、基于特征匹配的指纹验证
-
- [3.1 简化版指纹验证系统](#3.1 简化版指纹验证系统)
- [3.2 匹配参数详解](#3.2 匹配参数详解)
- [3.3 改进版指纹验证系统](#3.3 改进版指纹验证系统)
- 四、进阶指纹匹配可视化
-
- [4.1 增强的指纹匹配可视化](#4.1 增强的指纹匹配可视化)
- [4.2 指纹数据识别](#4.2 指纹数据识别)
一、角点检测基础
角点是图像中局部区域与周围区域有较大灰度变化的点,通常位于物体的边缘或纹理丰富的区域。角点检测是许多视觉任务的基础。
1.1 Harris角点检测原理
Harris角点检测算法通过计算图像局部窗口在各个方向移动时灰度值的变化程度来识别角点。当窗口在任意方向移动都会导致灰度值显著变化时,该位置被认为是角点。
1.2 代码实现与参数解析
python
import cv2
import numpy as np
# 读取原始图像
img = cv2.imread(r"picture_3.jpg")
# 放大图像以便更好观察
img = cv2.resize(img, None, fx=1.5, fy=1.5)
# 转换为灰度图像
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
# 执行Harris角点检测
dst = cv2.cornerHarris(gray, blockSize=4, ksize=3, k=0.04)
# 标记检测到的角点
img[dst > 0.01 * dst.max()] = [0, 0, 255]
# 显示结果图像
cv2.imshow('img', img)
cv2.waitKey(0)
关键参数解析:
-
blockSize:角点检测中要考虑的邻域大小。这个值决定了检测角点时考虑的局部窗口尺寸,值越大,检测到的角点可能越少但更稳定。
-
ksize:Sobel求导中使用的窗口大小。Sobel算子用于计算图像的梯度,这个参数控制梯度计算的精度。
-
k:Harris角点检测方程中的自由参数,取值范围通常为[0.04, 0.06]。这个值影响角点响应的灵敏度。
角点标记原理:
通过阈值处理dst > 0.01 * dst.max(),我们将角点响应值大于最大响应值1%的像素标记为红色。这种方法可以筛选出最明显的角点。
二、SIFT特征提取
SIFT(尺度不变特征变换)是一种强大的局部特征描述子,具有尺度、旋转和光照不变性。
2.1 SIFT特征提取流程
python
# 读取第二张图像
img1 = cv2.imread(r"picture_2.jpg")
# 缩小图像以便处理
img1 = cv2.resize(img1, None, fx=0.5, fy=0.5)
# 转换为灰度图像
img1_gray = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY)
# 创建SIFT特征提取器对象
sift = cv2.SIFT_create()
# 在图像中检测关键点
kp = sift.detect(img1_gray)
# 绘制关键点
img1_sift = cv2.drawKeypoints(img1, kp, outImage=None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)
# 显示结果
cv2.imshow('img1_sift', img1_sift)
cv2.waitKey(0)
# 计算关键点描述符
kp, des = sift.compute(img1, kp)
print(np.array(kp).shape, des.shape)

2.2 关键点属性详解
SIFT检测到的每个关键点包含以下重要属性:
-
kp.pt:关键点的(x, y)坐标,表示该特征点在图像中的位置。
-
kp.size:关键点的大小(尺度),反映了特征点所在的图像金字塔层级。
-
kp.angle:关键点的方向,基于局部图像梯度计算,使特征具有旋转不变性。
-
kp.response:关键点的响应值,表示该特征点的显著程度。
-
kp.octave:关键点所在的金字塔层级,用于实现尺度不变性。
2.3 描述符计算
sift.compute()方法计算关键点的描述符,每个描述符是一个128维的向量,描述了关键点周围区域的局部特征。这些描述符可以用于后续的特征匹配任务。
三、基于特征匹配的指纹验证
特征匹配是将不同图像中的相似特征点关联起来的过程,在指纹识别、人脸识别等生物特征验证中有重要应用。



3.1 简化版指纹验证系统
python
import cv2
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
def verification(src, template):
# 创建SIFT特征提取器
sift = cv2.SIFT_create()
# 检测源图像的关键点和计算描述符
kp1, des1 = sift.detectAndCompute(src, None)
# 检测模板图像的关键点和计算描述符
kp2, des2 = sift.detectAndCompute(template, None)
# 创建FLANN匹配器
flann = cv2.FlannBasedMatcher_create()
# 使用k近邻匹配
matches = flann.knnMatch(des1, des2, k=2)
# 进行比较筛选
ok = []
for m, n in matches:
# 根据Lowe's比率测试,选择最佳匹配
if m.distance < 0.8 * n.distance:
ok.append((m, n))
# 统计通过筛选的匹配数量
num = len(ok)
# 判断验证结果
if num >= 500:
result = "认证通过"
else:
result = "认证失败"
return result
if __name__ == "__main__":
# 读取待验证图像和模板图像
src1 = cv2.imread(r"src1.bmp")
cv_show("src1", cv2.resize(src1, None, fx=0.5, fy=0.5))
src2 = cv2.imread(r"src2.bmp")
cv_show("src2", cv2.resize(src2, None, fx=0.5, fy=0.5))
model = cv2.imread(r"model.bmp")
cv_show("model", cv2.resize(model, None, fx=0.5, fy=0.5))
# 进行验证
result1 = verification(src1, model)
result2 = verification(src2, model)
print("src1验证结果为:", result1)
print("src2验证结果为:", result2)

3.2 匹配参数详解
-
matches:使用k近邻算法进行特征匹配,k=2表示每个特征在模板图像中找2个最近邻。
-
m.distance:匹配的特征点描述符的欧式距离,数值越小说明两个特征点越相近。
-
queryIdx:测试图像的特征点描述符的下标。
-
trainIdx:样本图像的特征点描述符下标。
3.3 改进版指纹验证系统
python
import cv2
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
def verification(src, template):
# 创建SIFT特征检测器对象
sift = cv2.SIFT_create()
# 检测源图像的关键点和计算描述符
kp1, des1 = sift.detectAndCompute(src, None)
# 检测模板图像的关键点和计算描述符
kp2, des2 = sift.detectAndCompute(template, None)
# 创建FLANN匹配器对象
flann = cv2.FlannBasedMatcher_create()
# 使用k近邻算法进行特征匹配
matches = flann.knnMatch(des1, des2, k=2)
# 初始化存储匹配点坐标的列表
matched_points_src = []
matched_points_template = []
# 遍历所有匹配对
for m, n in matches:
# Lowe's比率测试: 筛选最佳匹配
if m.distance < 0.4 * n.distance:
# 获取源图像匹配点的坐标
src_pt = kp1[m.queryIdx].pt
# 获取模板图像匹配点的坐标
template_pt = kp2[m.trainIdx].pt
# 将浮点坐标转换为整数并添加到列表
matched_points_src.append((int(src_pt[0]), int(src_pt[1])))
matched_points_template.append((int(template_pt[0]), int(template_pt[1])))
# 计算成功匹配点的数量
num = len(matched_points_src)
# 创建图像的副本用于绘制标记点
src_with_points = src.copy()
template_with_points = template.copy()
# 在源图像上绘制匹配点标记
for pt in matched_points_src:
cv2.circle(src_with_points, pt, 3, (0, 0, 255), -1)
# 在模板图像上绘制匹配点标记
for pt in matched_points_template:
cv2.circle(template_with_points, pt, 3, (0, 0, 255), -1)
# 根据匹配点数量判断验证结果
result = "认证通过" if num >= 10 else "认证失败"
# 返回验证结果和标记后的图像
return result, src_with_points, template_with_points, matched_points_src, matched_points_template
if __name__ == "__main__":
# 读取图像文件
src1 = cv2.imread(r"src1.bmp")
src2 = cv2.imread(r"src2.bmp")
model = cv2.imread(r"model.bmp")
# 对第一个图像进行验证
result1, src1_points, model1_points, src1_coords, model1_coords = verification(src1, model)
print("src1验证结果为:", result1)
# 对第二个图像进行验证
result2, src2_points, model2_points, src2_coords, model2_coords = verification(src2, model)
print("src2验证结果为:", result2)
# 显示匹配结果
cv_show("src1", cv2.resize(src1_points, None, fx=0.5, fy=0.5))
cv_show("model1", cv2.resize(model1_points, None, fx=0.5, fy=0.5))
cv_show("src2", cv2.resize(src2_points, None, fx=0.5, fy=0.5))
cv_show("model2", cv2.resize(model2_points, None, fx=0.5, fy=0.5))


四、进阶指纹匹配可视化
在上一部分我们介绍了基本的特征匹配技术后,现在进一步探讨更实用的指纹识别应用场景。以下是两个更完善的指纹识别系统,分别专注于匹配结果的可视化和基于数据库的指纹身份识别。
4.1 增强的指纹匹配可视化
python
import cv2
def cv_show(name, img):
cv2.imshow(name, img)
cv2.waitKey(0)
# 读取图像
src1 = cv2.imread("D:\Code\PythonTest\src1.bmp")
cv_show('src1', src1)
model = cv2.imread("D:\Code\PythonTest\model.bmp")
cv_show('model', model)
# 创建SIFT特征提取器
sift = cv2.SIFT_create()
# 检测关键点和计算描述符
kp1, des1 = sift.detectAndCompute(src1, None)
kp2, des2 = sift.detectAndCompute(model, None)
# 创建FLANN匹配器
flann = cv2.FlannBasedMatcher_create()
matches = flann.knnMatch(des1, des2, k=2)
# 筛选匹配点
good = []
alist = []
for m, n in matches:
if m.distance < 0.4 * n.distance: # Lowe's比率测试
alist.append((m.queryIdx, m.trainIdx)) # 匹配成功的(指纹1中的索引,指纹model中的索引)
good.append((m, n))
# 在图像上标记匹配点
for i, j in alist:
x, y = kp1[i].pt
m, n = kp2[j].pt
cv2.circle(src1, center=(int(x), int(y)), radius=3, color=(0, 0, 255), thickness=-1)
cv2.circle(model, center=(int(m), int(n)), radius=3, color=(0, 0, 255), thickness=-1)
# 显示标记后的图像
cv_show('Marked src1', src1)
cv_show('Marked model', model)
# 绘制匹配点连线
draw_img = cv2.drawMatchesKnn(src1, kp1, model, kp2, good, None, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv_show('Matches', draw_img)


- 解析:
1. 匹配点索引存储
python
alist.append((m.queryIdx, m.trainIdx))
这里不仅筛选出好的匹配点,还保存了匹配点对在两个图像中的索引。queryIdx是源图像中关键点的索引,trainIdx是模板图像中关键点的索引。
2. 坐标提取与标记
python
x, y = kp1[i].pt
m, n = kp2[j].pt
通过索引从关键点列表中提取实际坐标,然后在两个图像上分别用红色实心圆标记出来,便于直观观察匹配点的分布。
3. 可视化匹配关系
python
draw_img = cv2.drawMatchesKnn(src1, kp1, model, kp2, good, None, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv2.drawMatchesKnn函数创建一个新图像,将两个输入图像并排显示,并用线条连接匹配的关键点。flags参数设置为NOT_DRAW_SINGLE_POINTS表示不单独绘制未匹配的关键点,只显示匹配对。
4.2 指纹数据识别
接下来是一个更复杂的系统,实现了从指纹数据库中进行身份识别的功能:
python
import os
import cv2
# 计算两个指纹间匹配点的个数
def getNum(src, model):
img1 = cv2.imread(src)
img2 = cv2.imread(model)
sift = cv2.SIFT_create() # orb_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
flann = cv2.FlannBasedMatcher_create()
matches = flann.knnMatch(des1, des2, k=2)
ok = []
for m, n in matches:
if m.distance < 0.8 * n.distance:
ok.append(m)
num = len(ok)
return num
# 获取指纹编号
def getID(src, database):
max = 0
name = ""
for file in os.listdir(database):
model = os.path.join(database, file)
num = getNum(src, model)
print("文件名:", file, "匹配点个数:", num)
if num > max:
max = num
name = file
if max < 200: # src图片不一定是库里面人的指纹
ID = 9999
else:
# 假设文件名格式如 "0_finger.bmp",取第一个字符作为ID
ID = name.split('_')[0] if '_' in name else name[0]
return ID
# 根据指纹编号,获取对应姓名
def getName(ID):
nameID = {0: '张三', 1: '李四', 2: '王五', 3: '赵六', 4: '朱老七', 5: '钱八', 6: '曹九', 7: '王二麻子', 8: 'andy',
9: 'Anna', 9999: '没找到'}
name = nameID.get(int(ID))
return name
# 主函数
if __name__ == "__main__":
src = "src.bmp"
database = "database"
ID = getID(src, database)
name = getName(ID)
print("识别结果为:", name)

- 解析:
1. 数据搜索
python
for file in os.listdir(database):
model = os.path.join(database, file)
num = getNum(src, model)
系统遍历数据库中的所有指纹模板,逐一与待识别指纹进行匹配。这种暴力搜索方法适用于小型数据库,对于大型数据库可能需要更高效的索引方法。
2. 匹配阈值
python
if max < 200: # src图片不一定是库里面人的指纹
ID = 9999
设置了200个匹配点的阈值,只有最大匹配点数量超过这个值才认为识别成功。这个阈值需要根据具体应用场景进行调整。
3. ID映射
python
nameID = {0: '张三', 1: '李四', 2: '王五', ...}
使用字典将数字ID映射到实际姓名,便于扩展和维护。当需要添加新用户时,只需在字典中添加新的键值对。