O3.3 opencv指纹识别
一·指纹识别
逻辑
- 导入必要的库
python
import os
import cv2
导入os
库用于操作系统相关的操作,如文件和目录的操作;导入cv2
库(OpenCV)用于图像处理和计算机视觉任务。
- 计算两个指纹间匹配点的个数
python
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()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
getNum
函数接受两个参数,src
表示待识别指纹图像的路径,model
表示数据库中指纹图像的路径。- 使用
cv2.imread
分别读取这两个指纹图像。 - 创建
cv2.SIFT_create()
对象来进行 SIFT 特征提取(代码中注释了orb_create()
,可能是之前考虑过使用 ORB 特征提取)。 - 对两个图像分别调用
detectAndCompute
方法,同时检测关键点并计算描述符。kp1
和kp2
分别是两个图像的关键点列表,des1
和des2
分别是对应的描述符。 - 创建
cv2.FlannBasedMatcher()
对象,这是一种基于快速近似最近邻搜索(FLANN)的匹配器。 - 使用
knnMatch
方法进行 K 近邻匹配,k = 2
表示对每个描述符在另一组描述符中寻找 2 个最近邻。 - 通过遍历匹配结果,使用比率测试(如果第一个最近邻的距离小于第二个最近邻距离的 0.8 倍)来筛选出较好的匹配点,将这些匹配点添加到
ok
列表中。 - 最后返回匹配点的数量。
- 获取指纹编号
python
def getID(src, database):max = 0for file in os.listdir(database):model = os.path.join(database, file)num = getNum(src, model)print("文件名:", file, "匹配点个数:", num)if num > max:max = numname = fileID = name[0]if max < 100: # src图片不一定是库里面人的指纹ID = 9999return ID
getID
函数接受待识别指纹图像路径src
和数据库目录路径database
。- 初始化最大匹配点数
max
为 0。 - 使用
os.listdir
遍历数据库目录中的所有文件。 - 对于每个文件,使用
os.path.join
构建完整的文件路径model
。 - 调用
getNum
函数计算待识别指纹与当前数据库指纹的匹配点个数num
,并打印文件名和匹配点个数。 - 如果当前匹配点个数大于
max
,更新max
并记录对应的文件名name
。 - 取文件名的第一个字符作为指纹编号
ID
。 - 如果最大匹配点数小于 100,认为待识别指纹可能不属于数据库中的任何人,将
ID
设为 9999。 - 最后返回指纹编号
ID
。
- 根据指纹编号,获取对应姓名
python
def getName(ID):nameID = {0: '张三', 1: '李四', 2: '王五', 3: '赵六', 4: '朱老七', 5: '钱八',6: '曹九', 7: '王二麻子', 8: 'andy', 9: 'Anna', 9999: "没找到"}name = nameID.get(int(ID))return name
getName
函数接受指纹编号ID
。- 定义一个字典
nameID
,将指纹编号映射到对应的姓名。 - 使用字典的
get
方法,根据ID
获取对应的姓名。如果ID
不存在于字典中,get
方法返回None
,但这里通过设置字典默认返回值为 “没找到” 来处理这种情况。 - 最后返回姓名。
- 主函数
python
if __name__ == "__main__":src = "src.BMP"database = "database"ID = getID(src, database)name = getName(ID)print("识别结果为:", name)
- 在主程序入口,定义待识别指纹图像路径
src
为"src.BMP"
,数据库目录路径database
为"database"
。 - 调用
getID
函数获取指纹编号ID
。 - 使用
ID
调用getName
函数获取对应的姓名name
。 - 最后打印识别结果
代码
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()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 = 0for file in os.listdir(database):model = os.path.join(database, file)num = getNum(src, model)print("文件名:", file, "匹配点个数:", num)if num >max:max = numname = fileID = name[0]if max < 100: # src图片不一定是库里面人的指纹ID = 9999return 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)
二·指纹验证
逻辑
- 导入必要的库
python
import cv2
导入cv2
库,即 OpenCV 库,用于图像处理和计算机视觉任务。
- 定义图像显示函数
python
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)
cv_show
函数用于显示图像。它接受两个参数:name
是显示图像窗口的名称,img
是要显示的图像。函数内部使用cv2.imshow
显示图像,并通过cv2.waitKey(0)
等待用户按下任意键,确保图像窗口不会立即关闭。
- 定义验证函数
python
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中的最近两个描述符进行匹配)matches = flann.knnMatch(des1, des2, k=2)# distance:匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近。# queryIdx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。# trainIdx:样本图像的特征点描述符下标, 同时也是描述符对应特征点的下标。# 进行比较筛选ok = []for m, n in matches:# 根据Lowe's比率测试,选择最佳匹配if m.distance < 0.8 * n.distance:ok.append(m)# 统计通过筛选的匹配数量num = len(ok)if num >= 500:result = "认证通过"else:result = "认证失败"return result
verification
函数接受两个参数:src
为源图像(待验证图像),model
为模板图像。- 使用
cv2.SIFT_create()
创建 SIFT 特征提取器对象sift
。 - 对源图像
src
和模板图像model
分别调用sift.detectAndCompute
方法,同时检测关键点并计算描述符。kp1
和kp2
分别是源图像和模板图像的关键点列表,des1
和des2
分别是对应的描述符。detectAndCompute
方法的第二个参数None
表示不使用掩膜。 - 创建
cv2.FlannBasedMatcher()
对象flann
,这是一种基于快速近似最近邻搜索(FLANN)的匹配器。 - 使用
flann.knnMatch
方法进行 K 近邻匹配,这里k = 2
,意味着对源图像的每个描述符des1
,在模板图像的描述符des2
中寻找最近的两个匹配。 - 通过遍历匹配结果
matches
,使用 Lowe's 比率测试筛选出较好的匹配点。如果第一个最近邻的距离小于第二个最近邻距离的 0.8 倍,认为这是一个较好的匹配点,将其添加到ok
列表中。 - 统计
ok
列表中匹配点的数量num
。 - 如果匹配点数量
num
大于或等于 500,返回 “认证通过”;否则,返回 “认证失败”。
- 主函数
python
if __name__ == "__main__":src1 = cv2.imread("src1.BMP")cv_show('src1', src1)src2 = cv2.imread("src2.BMP")cv_show('src2', src2)model = cv2.imread("model.BMP")cv_show('model', model)result1 = verification(src1, model)result2 = verification(src2, model)print("src1验证结果为:", result1)print("src2验证结果为:", result2)
- 在主程序入口,使用
cv2.imread
分别读取src1.BMP
、src2.BMP
作为待验证图像,model.BMP
作为模板图像。 - 调用
cv_show
函数分别显示src1
、src2
和model
图像。 - 对
src1
和src2
分别调用verification
函数与模板图像model
进行验证,并将结果分别存储在result1
和result2
中。 - 最后打印出
src1
和src2
的验证结果
代码
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) # 第二个参数:掩膜# 检测关键点和计算描述符 模板图像kp2, des2 = sift.detectAndCompute(model, None)# 创建FLANN匹配器flann = cv2.FlannBasedMatcher()# 使用k近邻匹配(des1中的每个描述符与des2中的最近两个描述符进行匹配)matches = flann.knnMatch(des1, des2, k=2)
# distance:匹配的特征点描述符的欧式距离,数值越小也就说明俩个特征点越相近。
# queryIdx:测试图像的特征点描述符的下标(第几个特征点描述符),同时也是描述符对应特征点的下标。
# trainIdx:样本图像的特征点描述符下标, 同时也是描述符对应特征点的下标。# 进行比较筛选ok = []for m, n in matches:# 根据Lowe's比率测试,选择最佳匹配if m.distance < 0.8 * n.distance:ok.append(m)# 统计通过筛选的匹配数量num = len(ok)if num >= 500:result = "认证通过"else:result = "认证失败"return result
if __name__ == "__main__":src1 = cv2.imread("src1.BMP")cv_show('src1', src1)src2 = cv2.imread("src2.BMP")cv_show('src2', src2)model = cv2.imread("model.BMP")cv_show('model', model)result1= verification(src1, model)result2= verification(src2, model)print("src1验证结果为:", result1)print("src2验证结果为:", result2)
三·画出指纹匹配的成功点
逻辑
整体功能
这段代码旨在解决指纹验证案例中的一个作业要求,即找出指纹 1(src1.BMP)与模板图片(model.BMP)之间匹配成功的点,并在两张图片上分别标记出这些点的坐标,同时绘制出匹配点之间的连线。
代码结构与逻辑
导入与辅助函数定义:python
import cv2
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)导入cv2库,它是 OpenCV 库的 Python 接口,用于各种图像处理任务。cv_show函数用于在窗口中显示图像,并等待用户按键关闭窗口。函数接受两个参数:name为窗口名称,img为要显示的图像。图像读取与展示:python
src1 = cv2.imread("src1.BMP")
cv_show('src1',src1)
model = cv2.imread("model.BMP")
cv_show('model',model)使用cv2.imread函数分别读取指纹 1 图像(src1.BMP)和模板图像(model.BMP),并通过cv_show函数在单独的窗口中展示这两张原始图像,以便用户直观查看。特征提取与匹配:python
sift = cv2.SIFT_create()
kp1, des1 = sift.detectAndCompute(src1, None)
kp2, des2 = sift.detectAndCompute(model, None)
flann = cv2.FlannBasedMatcher()
matches = flann.knnMatch(des1, des2, k=2)创建 SIFT(尺度不变特征变换)特征提取器对象sift。对指纹 1 图像src1和模板图像model分别调用sift.detectAndCompute方法,该方法同时检测图像中的关键点并计算这些关键点的描述符。kp1和kp2分别是指纹 1 和模板图像的关键点列表,des1和des2分别是对应的描述符。创建基于 FLANN(快速近似最近邻搜索)的匹配器对象flann,然后使用flann.knnMatch方法进行 K 近邻匹配,这里k = 2表示为指纹 1 图像的每个描述符在模板图像的描述符中寻找最近的两个匹配。筛选匹配点:python
good=[]
alist=[]
for m, n in matches:if m.distance < 0.4 * n.distance: alist.append((m.queryIdx,m.trainIdx))good.append((m,n))初始化两个空列表good和alist。遍历所有的匹配结果matches,根据 Lowe's 比率测试筛选出较好的匹配点。当最近匹配距离m.distance小于次近匹配距离n.distance的 0.4 倍时,认为该匹配是有效的。将匹配点在指纹 1 和模板图像中的索引对(m.queryIdx, m.trainIdx)添加到alist中,同时将匹配对(m, n)添加到good列表中。m.queryIdx是指纹 1 中描述符的索引,m.trainIdx是模板图像中描述符的索引。标记匹配点:python
for i,j in alist:x, y = kp1[i].ptm, n = kp2[j].ptcv2.circle(src1, (int(x), int(y)), 3, (0, 0, 255), -1)cv2.circle(model, (int(m), int(n)), 3, (0, 0, 255), -1)遍历alist中的索引对,通过索引从关键点列表kp1和kp2中获取匹配关键点的坐标(x, y)和(m, n)。使用cv2.circle函数在指纹 1 图像src1和模板图像model上分别绘制半径为 3、颜色为红色((0, 0, 255))的实心圆(-1表示实心),从而标记出匹配成功点的坐标。显示标记后的图像与匹配连线:python
cv_show('Marked src1', src1)
cv_show('Marked model', model)
matched_image = cv2.drawMatchesKnn(src1, kp1, model, kp2, good, None,flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv_show('Matched Points', matched_image)通过cv_show函数分别显示标记了匹配点的指纹 1 图像(窗口名称为Marked src1)和模板图像(窗口名称为Marked model)。使用cv2.drawMatchesKnn函数绘制匹配点之间的连线。该函数接受指纹 1 图像src1及其关键点kp1、模板图像model及其关键点kp2、筛选后的匹配对good等参数。flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS参数表示不绘制没有匹配项的关键点。绘制结果保存在matched_image中,最后通过cv_show函数在名为Matched Points的窗口中显示绘制了匹配连线的图像。总体而言,代码逻辑清晰,按照作业要求逐步实现了指纹匹配点的查找、标记及连线绘制的功能。不过,需要注意的是,SIFT 算法在较新的 OpenCV 版本中已移入opencv - contrib - python库,如果运行代码时出现找不到cv2.SIFT_create()的错误,需要安装该扩展库
代码
'''
作业:
指纹验证案例中,指纹1与模板图片匹配成功了,分别在两图内标出匹配成功点的坐标
要求:匹配结果最近的distance小于次接近distance的0.4
提示:cv2.circle(src, (x,y), 3, (0, 0, 255), -1),绘制实心圆
'''
import cv2
def cv_show(name, img):cv2.imshow(name, img)cv2.waitKey(0)
# 读取图像
src1 = cv2.imread("src1.BMP")
cv_show('src1',src1)
model = cv2.imread("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()
# 使用k近邻匹配
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].ptm, n = kp2[j].ptcv2.circle(src1, (int(x), int(y)), 3, (0, 0, 255), -1)cv2.circle(model, (int(m), int(n)), 3, (0, 0, 255), -1)# 显示标记后的图像
cv_show('Marked src1', src1)
cv_show('Marked model', model)
# 绘制匹配点连线
# drawMatchesKnn(img1, keypoints1, img2, keypoints2, matches1to2, outImg, matchColor=None, singlePointColor=None, matchesMask=None, flags=None)绘制匹配图片
# 参数:img1:第一张原始图像。
# keypoints1:第一张原始图像的关键点。
# img2:第二张原始图像。
# keypoints2:第二张原始图像的关键点。
# matches1to2:从第一个图像到第二个图像的匹配,这意味着keypoints1[i]在keypoints2[Matches[i]中有一个对应的点。
# outImg:绘制结果图像。
# matchColor:匹配连线与关键点点的颜色,当matchColor == Scalar::all(-1)时,代表取随机颜色。
# singlePointColor:没有匹配项的关键点的颜色,当singlePointColor == Scalar::all(-1)时,代表取随机颜色。
# matchesMask:确定绘制哪些匹配项的掩码。如果掩码为空,则绘制所有匹配项。
# flags:绘图功能的一些标志。具体有:
# cv.DRAW_MATCHES_FLAGS_DEFAULT
# cv.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS
# cv.DRAW_MATCHES_FLAGS_DRAW_OVER_OUTIMG
# cv.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS
matched_image = cv2.drawMatchesKnn(src1, kp1, model, kp2, good, None,flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
cv_show('Matched Points', matched_image)