OpenCv高阶(六)——指纹识别

发布于:2025-05-22 ⋅ 阅读:(17) ⋅ 点赞:(0)


前言

本文通过Python代码实现了一个基于SIFT特征和FLANN匹配器的指纹识别系统,能够从数据库中快速匹配目标指纹并输出识别结果。

指纹识别代码解释

一、环境依赖与工具函数

import cv2
import os

def cv_show(name, img):
    cv2.imshow(name, img)
    cv2.waitKey(0)

功能说明:

cv_show() 是一个可视化辅助函数,用于显示图像并等待键盘输入后关闭窗口。

虽然主流程未调用此函数,但在调试阶段可用于查看中间图像处理结果(如关键点匹配效果)。

二、核心验证函数:verification()

def verification(src,model):
    #创建SIFT特征提取器
    sift=cv2.SIFT_create()

    #检测关键点和计算描述符(特征向量)的原图像
    kp1,des1=sift.detectAndCompute(src,None)    #第二个参数是掩膜
    # 检测关键点和计算描述符  模板图像
    kp2,des2=sift.detectAndCompute(model,None)

    #创建Flann匹配器
    flann = cv2.FlannBasedMatcher()

    #使用K近邻匹配(des1中的每个描述符周围距离它最近的des2的点,K值就是设置点的个数
    matches=flann.knnMatch(des1,des2,k=2)

#match的参数:match的值会显示,测试的第几个点与模板第几个点之间的距离。
    #distance:使用欧式距离计算距离
    #queryIdx: 测试图像的特征点描述符的下标(第几个特征点的描述符),同时也是描述符对应特征点的下标,测试的第几个点,

    #trainIdx:样本(模板)图像的特征点描述符下标,同时也是描述符对应特征点的下标,模板图片的第几个点


    #进行比较筛选
    ok=[]

    #因为前面设置了K近邻的点数,所以match有两个值,一个是距离比较近,另一个则很远,这种情况是比较符合的,如果两个点距离待匹配图像
    #特征点的距离相差不多,则这个点不符合要求,应该过滤掉。
    for m,n in matches:

        #这里的if表示距离较近的距离小于较长距离的0.8,则表示两个距离相差很大。
        if m.distance < 0.8 *n.distance:
            ok.append(m)

    num=len(ok)
    #如何模板图和待识别图有超过500以上的特征可以被分为一类,则说明认证成功,否则认证失败
    if num >=500:
        result = "认证成功"
    else:
        result="认证失败"

    return result

功能解析:

特征提取:

使用SIFT算法提取输入图像(src)和模板图像(model)的关键点(kp)和描述符(des)。

SIFT对旋转、缩放、光照变化具有鲁棒性,适合指纹特征识别。

特征匹配:

采用FLANN快速近似最近邻匹配器加速特征匹配过程。

knnMatch()返回每个特征点的最近2个邻域匹配结果。

筛选优质匹配:

根据Lowe’s比率测试(0.8阈值)过滤误匹配,保留高置信度匹配对。

认证逻辑:

若优质匹配数≥500,则认为认证成功,否则失败。

三、相似特征统计函数:get_num()

def get_num(src, model):
	"""
    :param src: 要识别指纹的路径
    :param model: 模板路径
    :return: 返回模板与测试图片之间,相似特征的数量
    """
    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, k=2)
    
    ok = []
    for m, n in matches:
        if m.distance < 0.8 * n.distance:
            ok.append(m)
    return len(ok)

功能解析:

与verification()逻辑相似,但返回具体匹配数量而非认证结果。

用于后续遍历数据库时量化两个指纹的相似度。

四、数据库搜索函数:get_ID()

def get_ID(src, database):
    max = 0
    for file in os.listdir(database):
        model = os.path.join(database, file)
        num = get_num(src, model)
        print("文件名:", file, "匹配点个数", num)
        if num > max:
            max = num
            name = file
    
		ID = name[0]
    return 9999 if max < 100 else ID

实现逻辑:

遍历数据库:

遍历指定database路径下的所有模板文件,逐个计算与输入指纹的匹配数。

最佳匹配筛选:

记录最高匹配数对应的文件名,并提取文件名首字符作为用户ID(假设文件名格式为ID_name.jpg)。

阈值判定:

若最高匹配数<100,返回9999表示未找到匹配。

五、ID转姓名映射函数:get_name()

def get_name(ID):
    nameID = {
        0: '张三', 1: '李四', 2: '王五', 3: '赵六', 
        4: '朱七', 5: '钱八', 6: '曹九', 
        7: '王二麻子', 8: 'andy', 9: 'anna', 
        9999: '未找到目标'
    }
    return nameID.get(int(ID))

功能说明:

通过预设字典将数字ID映射为真实姓名,增强结果可读性。

六、主程序流程

if __name__ == '__main__':
    src = '../data/newzw.bmp'
    database = '../data/database'
    ID = get_ID(src, database)
    name = get_name(ID)
    print('识别结果为:', name)

执行步骤:

指定待识别指纹路径(src)和模板数据库路径(database)。

调用get_ID()搜索最佳匹配,获得用户ID。

将ID转换为姓名并输出结果。
指纹库
在这里插入图片描述
待识别的指纹
在这里插入图片描述

最终识别结果
在这里插入图片描述
匹配原理,通过比较能匹配上的点的个数,匹配上的点数越多说明指纹越相近,越可能是同一个人的指纹。

完整代码

import cv2
import os
def cv_show(name,img):
    cv2.imshow(name,img)
    cv2.waitKey(0)

def verification(src,model):
    #创建SIFT特征提取器
    sift=cv2.SIFT_create()

    #检测关键点和计算描述符(特征向量)的原图像
    kp1,des1=sift.detectAndCompute(src,None)    #第二个参数是掩膜
    # 检测关键点和计算描述符  模板图像
    kp2,des2=sift.detectAndCompute(model,None)

    #创建Flann匹配器
    flann = cv2.FlannBasedMatcher()

    #使用K近邻匹配(des1中的每个描述符周围距离它最近的des2的点,K值就是设置点的个数
    matches=flann.knnMatch(des1,des2,k=2)

#match的参数:match的值会显示,测试的第几个点与模板第几个点之间的距离。
    #distance:使用欧式距离计算距离
    #queryIdx: 测试图像的特征点描述符的下标(第几个特征点的描述符),同时也是描述符对应特征点的下标,测试的第几个点,

    #trainIdx:样本(模板)图像的特征点描述符下标,同时也是描述符对应特征点的下标,模板图片的第几个点


    #进行比较筛选
    ok=[]

    #因为前面设置了K近邻的点数,所以match有两个值,一个是距离比较近,另一个则很远,这种情况是比较符合的,如果两个点距离待匹配图像
    #特征点的距离相差不多,则这个点不符合要求,应该过滤掉。
    for m,n in matches:

        #这里的if表示距离较近的距离小于较长距离的0.8,则表示两个距离相差很大。
        if m.distance < 0.8 *n.distance:
            ok.append(m)

    num=len(ok)
    #如何模板图和待识别图有超过500以上的特征可以被分为一类,则说明认证成功,否则认证失败
    if num >=500:
        result = "认证成功"
    else:
        result="认证失败"

    return result

def get_num(src,model):
    """

    :param src: 要识别指纹的路径
    :param model: 模板路径
    :return: 返回模板与测试图片之间,相似特征的数量
    """
    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,k=2)

    ok=[]
    for m,n in matches:
        if m.distance<0.8*n.distance:
            ok.append(m)

    num=len(ok)
    return num

def get_ID(src,database):
    max=0

    for file in os.listdir(database):
        model = os.path.join(database,file)
        num=get_num(src,model)
        print("文件名:",file,"匹配点个数",num)
        if num>max:
            max=num
            name=file

    ID=name[0]
    if max <100:
        ID=9999
    return ID

def get_name(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='../data/newzw.bmp'
    database='../data/database'
    ID=get_ID(src,database)
    name=get_name(ID)
    print('识别结果为:',name)

需注意自己的指纹库与待识别的指纹路径需要更改,要与自己的实际路径一致。

总结

本代码实现了一套完整的指纹识别系统,结合SIFT的稳定性与FLANN的高效匹配,适用于小规模数据库的快速身份认证场景。