opencv学习:FLANN匹配器算法实现指纹验证与指纹识别

概念

        FLANN(Fast Library for Approximate Nearest Neighbors)是一个开源的C++库,用于在高维空间中进行近似最近邻搜索。它被广泛用于计算机视觉和机器学习领域,特别是在处理具有大量特征点的图像匹配问题时。FLANN旨在提供一个快速且灵活的近似最近邻搜索解决方案。

最近邻搜索:给定一个查询点,最近邻搜索的目标是找到一个数据点,使得与查询点之间的距离最小。在特征匹配中,这通常用于找到与查询图像中特征点最相似的特征点。

近似最近邻搜索:与精确最近邻搜索不同,近似最近邻搜索不保证找到距离最小的点,但可以在更短的时间内找到一个距离相对较小的点。这对于处理大规模数据集或实时应用非常有用。

特征匹配方法

        在 OpenCV 中,matchradiusMatch,和 knnMatch 是三种不同的特征匹配方法,它们都属于 DescriptorMatcher 类。下面是每种方法的简要说明和使用场景:

  1. match

    • match 方法为每个查询描述符找到训练描述符集中的单个最佳匹配。
    • 它返回一个 DMatch 对象的列表,其中每个对象表示一个匹配对。
    • 通常用于当你知道每个查询描述符在训练集中只有一个最佳匹配时。
      match(self, queryDescriptors, trainDescriptors, mask=None)
  2. knnMatch

    • knnMatch 方法为每个查询描述符找到训练描述符集中的 k 个最佳匹配。
    • 它返回一个列表的列表,其中每个内部列表包含 k 个 DMatch 对象,按距离递增排序。
    • 通常用于找到多个潜在匹配,然后可以通过 Lowe's ratio test 来选择最佳匹配。
    • 参数 k 通常设置为 2,这样每个查询描述符会有两个最近邻。
      knnMatch(self, queryDescriptors, trainDescriptors, k, mask=None, compactResult=None)
  3. radiusMatch

    • radiusMatch 方法为每个查询描述符找到所有在指定半径内的训练描述符。
    • 它返回一个列表的列表,其中每个内部列表包含所有在指定半径内的匹配对。
    • 这种方法不是基于最近邻的,而是基于距离阈值的,可以找到所有与查询描述符距离在一定范围内的训练描述符。
  4. 适用于当你需要找到所有可能的匹配,而不仅仅是最近的那些。
    radiusMatch(self, queryDescriptors, trainDescriptors, maxDistance, mask=None, compactResult=None)

指纹验证

运行结果

代码流程

函数用于显示图像

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

验证两幅图像是否相似

        1.创建了一个 SIFT 特征检测器,对源图像进行 SIFT 特征检测和描述

# 创建了一个SIFT特征检测器。
    sift=cv2.SIFT_create()
    kp1,des1=sift.detectAndCompute(src,None)
    # 对源图像进行SIFT特征检测和描述,得到关键点kp1和描述符des1。
    kp2,des2=sift.detectAndCompute(model,None)

         2.创建了一个基于 FLANN 的匹配器,使用 FLANN 匹配器对描述符进行 K 最近邻匹配

# 创建了一个基于FLANN的匹配器。
    flann=cv2.FlannBasedMatcher()
    # 使用FLANN匹配器对描述符进行K最近邻匹配。
    matches=flann.knnMatch(des1,des2,2)

        3.筛选出好的匹配,如果好的匹配数量 num 超过 500,则认为验证成功,否则验证失败。

  for i,j in matches:
        # 如果当前匹配的距离小于其最近邻距离的80%,则认为是一个好的匹配。
        if i.distance<0.8*j.distance:
            m.append(i)
    num=len(m)

    if num>500:
        result='验证成功'
    else:
        result=('验证失败')
    return result

完整代码

import cv2
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)
    # 对源图像进行SIFT特征检测和描述,得到关键点kp1和描述符des1。
    kp2,des2=sift.detectAndCompute(model,None)
    # 创建了一个基于FLANN的匹配器。
    flann=cv2.FlannBasedMatcher()
    # 使用FLANN匹配器对描述符进行K最近邻匹配。
    matches=flann.knnMatch(des1,des2,2)
    m=[]
    for i,j in matches:
        # 如果当前匹配的距离小于其最近邻距离的80%,则认为是一个好的匹配。
        if i.distance<0.8*j.distance:
            m.append(i)
    num=len(m)

    if num>500:
        result='验证成功'
    else:
        result=('验证失败')
    return result

if __name__ == '__main__':
    a1=cv2.imread('zhiwen1.bmp')
    a2=cv2.imread('zhiwen2.bmp')
    model=cv2.imread('zhiwenmodel.bmp')

    result1=verification(a1,model)
    result2=verification(a2,model)
    print(result1)
    print(result2)

指纹识别

运行结果

完整代码

import cv2
import os
# 定义函数getNum,用于计算两幅图像之间的匹配点数量
def getNum(src, model):
    img1 = cv2.imread(src)  # 读取源图像
    img2 = cv2.imread(model)  # 读取模型图像
    sift = cv2.SIFT_create()  # 创建SIFT特征检测器
    kp1, des1 = sift.detectAndCompute(img1, None)  # 检测源图像的关键点和描述符
    kp2, des2 = sift.detectAndCompute(img2, None)  # 检测模型图像的关键点和描述符
    flann = cv2.FlannBasedMatcher()  # 创建FLANN匹配器
    matches = flann.knnMatch(des1, des2, 2)  # 使用FLANN匹配器进行K最近邻匹配
    m = []  # 初始化匹配点列表
    # 遍历匹配结果,使用Lowe's ratio test筛选好的匹配
    for i, j in matches:
        if i.distance < 0.8 * j.distance:
            m.append(i)
    num = len(m)  # 计算好的匹配点数量
    return num  # 返回匹配点数量

# 定义函数getID,用于在数据库中找到与源图像最相似的模型图像
def getID(src, database):
    max = 0  # 初始化最大匹配点数量
    for file in os.listdir(database):  # 遍历数据库中的每个模型图像
        model = os.path.join(database, file)  # 获取模型图像的完整路径
        num = getNum(src, model)  # 使用getNum函数计算匹配点数量
        print('file', file, '距离', num)  # 打印模型图像文件名和匹配点数量
        # 如果当前模型图像的匹配点数量大于已知的最大值,则更新最大值和对应的文件名
        if num > max:
            max = num
            name = file
    ID = name[0]  # 将匹配点数量最多的模型图像的文件名的第一位作为ID
    if max < 100:  # 如果最大匹配点数量小于100,则将ID设置为99999
        ID = 99999
    return ID  # 返回ID

# 定义函数getName,用于将ID转换为对应的名称
def getName(ID):
    nameID = {0: '一', 1: '二', 2: '三', 3: '四', 4: '五', 5: '六', 6: '七', 7: '八', 8: '九', 9: '十'}  # 定义ID到名称的映射
    name = nameID.get(int(ID))  # 获取ID对应的名称
    return name  # 返回名称

# 主程序入口
if __name__ == '__main__':
    src = 'src.bmp'  # 源图像路径
    database = 'database'  # 数据库目录路径
    ID = getID(src, database)  # 调用getID函数获取ID
    name = getName(ID)  # 调用getName函数获取名称
    print('识别结果', name)  # 打印识别结果
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值