sift特征检测和FLANN 匹配器进行指纹匹配
目录
- [sift特征检测和FLANN 匹配器进行指纹匹配](#sift特征检测和FLANN 匹配器进行指纹匹配)
-
- [1 sift特征检测](#1 sift特征检测)
-
- [1.1 概念](#1.1 概念)
- [1.2 优缺点](#1.2 优缺点)
- [2 FLANN 匹配器](#2 FLANN 匹配器)
-
- [2.1 概念](#2.1 概念)
- [2.2 工作原理与匹配方式](#2.2 工作原理与匹配方式)
- [2.3 FLANN 匹配器的使用步骤](#2.3 FLANN 匹配器的使用步骤)
- [2.4 优缺点](#2.4 优缺点)
- [3 函数](#3 函数)
-
- [3.1 特征检测匹配](#3.1 特征检测匹配)
- [3.2 匹配符合条件点并绘制](#3.2 匹配符合条件点并绘制)
- [3 代码测试](#3 代码测试)
-
- [3.1 单个指纹模板匹配](#3.1 单个指纹模板匹配)
- [3.2 多个指纹匹配](#3.2 多个指纹匹配)
1 sift特征检测
1.1 概念
SIFT(尺度不变特征变换)是一种用于图像处理中检测和描述图像中局部结构的算法 。它是由David Lowe在1999年提出的,并在2004年进行了详细阐述。SIFT特征具有尺度不变性,这意味着即使图像的尺度发生变化,SIFT特征也能保持稳定。
1.2 优缺点
SIFT特征的优点:
- 尺度不变性:能够适应图像的尺度变化。
- 旋转不变性:能够适应图像的旋转变化。
- 对光照、仿射变换和噪声具有一定的鲁棒性。
SIFT特征的缺点:
- 计算复杂度较高,实时性较差。
- 对于非线性变换和大幅度的视角变化,SIFT特征的性能可能会下降。
2 FLANN 匹配器
2.1 概念
FLANN 匹配器(Fast Library for Approximate Nearest Neighbors,快速近似最近邻搜索库)是 OpenCV 中用于高效匹配特征描述符的工具 。它通过近似算法加速最近邻搜索,特别适合处理高维数据(如 SIFT 或 SURF 描述符)。
2.2 工作原理与匹配方式
- 最近邻搜索 :
- 给定一个特征描述符集合,FLANN 的目标是找到与查询描述符最接近的匹配点。
- 精确的最近邻搜索(如暴力匹配)在高维数据中计算量很大,FLANN 通过近似算法加速搜索。
- 近似算法 :
- FLANN 使用了一种基于树结构的算法(如 KD-Tree 或 Hierarchical K-Means Tree)来组织数据,从而快速缩小搜索范围。
- 通过牺牲一定的精度,换取更快的搜索速度。
- 匹配方式 :
- FLANN 支持两种匹配方式:
- 单匹配:为每个查询描述符找到一个最近邻。
- KNN 匹配:为每个查询描述符找到 K 个最近邻。
2.3 FLANN 匹配器的使用步骤
-
创建 FLANN 匹配器 :
使用 cv2.FlannBasedMatcher 创建 FLANN 匹配器对象。
-
准备特征描述符 :
使用特征检测算法(如 SIFT、SURF 或 ORB)提取图像的特征描述符。
-
进行匹配 :
使用 knnMatch 方法进行 KNN 匹配,返回每个查询描述符的 K 个最近邻。
-
筛选匹配点 :
根据距离比例 或其他条件筛选出可靠的匹配点。
2.4 优缺点
优点:
- 高效:比暴力匹配(Brute-Force Matcher)更快,特别适合处理高维数据。
- 灵活:支持多种算法和参数配置,可以根据需求调整精度和速度。
缺点:
- 近似匹配:结果是近似的,可能存在一定的误差。
- 参数调优:需要根据具体任务调整参数,否则可能影响匹配效果。
3 函数
3.1 特征检测匹配
- 特征关键点检测
- sift = cv2.SIFT_create(),创建 SIFT 特征检测器
- kp1, des1 = sift.detectAndCompute(src, None),检测并计算 src 图像的关键点(kp1) 和描述符(des1 )
- 匹配器匹配
- flann = cv2.FlannBasedMatcher(),创建FLANN 匹配器
- matches = flann.knnMatch(des1, des2, 2) , 使用 KNN 算法进行特征(des1, des2)匹配 ,k=2 表示每个描述符返回两个最佳匹配
3.2 匹配符合条件点并绘制
python
ok = [] # 存储符合条件的匹配点
ok_n = [] # 存储对应的次佳匹配点
# 遍历所有匹配点
for m, n in matches:
# 如果最佳匹配点的距离小于次佳匹配点距离的 0.65 倍,则认为是一个好的匹配
if m.distance < 0.65 * n.distance:
ok.append(m) # 将好的匹配点加入 ok 列表
ok_n.append(n) # 将对应的次佳匹配点加入 ok_n 列表
# 计算好的匹配点的数量
num = len(ok)
# 如果好的匹配点数量大于等于 400,则认为验证通过
if num >= 400:
result = '认证通过' # 设置验证结果为通过
# 遍历所有匹配点
for m, n in matches:
# 再次筛选好的匹配点
if m.distance < 0.65 * n.distance:
ok.append(m)
x1 = int(kp1[m.queryIdx].pt[0])
y1 = int(kp1[m.queryIdx].pt[1])
x2 = int(kp2[n.queryIdx].pt[0])
y2 = int(kp2[n.queryIdx].pt[1])
src = cv2.circle(src, (x1, y1), 3, (0, 0, 255), -1)
model = cv2.circle(model, (x2, y2), 3, (0, 0, 255), -1)
3 代码测试
3.1 单个指纹模板匹配
图片1:
图片2:
模板:
代码展示:
python
import cv2
def cv_chow(name,img):
cv2.imshow(name,img)
cv2.waitKey(0)
def verification(src,model):
sift =cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(src, None)
kp2, des2 = sift.detectAndCompute(model, None)
flann = cv2.FlannBasedMatcher()
matches = flann.knnMatch(des1, des2, 2)
ok = []
ok_n = []
for m, n in matches:
if m.distance < 0.65 * n.distance:
ok.append(m)
ok_n.append(n)
## m,n,在kp的pt
num = len(ok)
if num>=400:
result = '认证通过'
for m, n in matches:
if m.distance < 0.65 * n.distance:
ok.append(m)
x1 = int(kp1[m.queryIdx].pt[0])
y1 = int(kp1[m.queryIdx].pt[1])
x2 = int(kp2[n.queryIdx].pt[0])
y2 = int(kp2[n.queryIdx].pt[1])
src = cv2.circle(src, (x1, y1), 3, (0, 0, 255), -1)
model = cv2.circle(model, (x2, y2), 3, (0, 0, 255), -1)
cv_chow('src', src)
cv_chow('model', model)
else:
result = '认证失败'
return result
if __name__=='__main__':
src1 = cv2.imread('zhiwen1.bmp')
cv_chow('src1',src1)
src2 = cv2.imread('zhiwen2.bmp')
cv_chow('src2', src2)
model = cv2.imread('zhiwenp.bmp')
cv_chow('model_', model)
result1 = verification(src1,model)
result2 = verification(src2, model)
print(f'src1验证结果:{result1}')
print(f'src2验证结果:{result2}')
运行结果:
3.2 多个指纹匹配
指纹文件库:
代码展示:
python
import os
def getNum(src,model):
img1 = cv2.imread(src)
img2 = cv2.imread(model)
sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1, None)
kp2, des2 = sift.detectAndCompute(img2, None)
flann = cv2.FlannBasedMatcher()
matches = flann.knnMatch(des1, des2, 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
for file in os.listdir(database):
print(file)
model = os.path.join(database,file)
num = getNum(src,model)
print(f'文件名:{file},匹配点个数:{num}')
if num>max:
max = num
name = file
ID = name[0]
if max<100:
ID = 9999
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 = "scrpp.bmp"
database = "database//database"
ID = getID(src,database)
name = getname(ID)
print(f'识别结果:{name}')
运行结果: