计算机视觉opencv之指纹识别补充图片拼接思考
一、指纹识别
1.上篇博客中讲到指纹识别以及对匹配上的点标出,这次我们实现让匹配对应的点连接起来,从连接的线上反应匹配的程度
这里和上篇博客中代码一样,只不过在函数中稍改动了,添加了src_matches=[]这个变量,以及后面对其的使用
import cv2 def cv_show(name,img): cv2.imshow(name,img) cv2.waitKey(0) def verification(src,model,show_matchs=False): sift=cv2.SIFT_create() kp1,des1=sift.detectAndCompute(src,None) kp2,des2=sift.detectAndCompute(model,None) flann=cv2.FlannBasedMatcher() matches=flann.knnMatch(des1,des2,k=2) ok=[] good_matches=[] src_matches=[] model_matches=[] for m,n in matches: if m.distance<0.4*n.distance: ok.append((m,n)) good_matches.append(m) src_matches.append(kp1[m.queryIdx].pt) model_matches.append(kp2[m.trainIdx].pt) num=len(ok) if num >=50: result='认证通过' else: result='认证失败' if show_matchs and len(src_matches)>0: src_with_matches=src.copy() model_with_matches=model.copy() for (x,y) in src_matches[:100]: cv2.circle(src_with_matches,(int(x),int(y)),3,(0,0,255),-1) for (x,y) in model_matches[:100]: cv2.circle(model_with_matches,(int(x),int(y)),3,(0,0,255),-1) cv2.imshow('src_matches',src_with_matches) cv2.imshow('model_matches',model_with_matches) cv2.waitKey(0) match_img=cv2.drawMatches(src,kp1,model,kp2,good_matches[:100],None,flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS) cv2.imshow('pipei',match_img) cv2.waitKey(0)#1 return result,num,src_matches,model_matches if __name__=='__main__': src1=cv2.imread('zhiwen1.bmp') src2=cv2.imread('zhiwen2.bmp') model = cv2.imread('zhiwen_model.bmp') cv2.imshow('src1',src1) cv2.imshow('src2',src2) cv2.imshow('model',model) cv2.waitKey(0) reselt1,num1,src1_matches,model1_matches=verification(src1,model,show_matchs=True) reselt2,num2,src2_matches,model2_matches=verification(src2,model,show_matchs=True) print('src1的结果为:',reselt1,'匹配点数:{}'.format(num1)) print('src2的结果为:',reselt2,'匹配点数:{}'.format(num2))2.指纹识别并输出对应人名
这段和之前指纹识别的是一样的
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 = 0 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 ID = name[0] if max < 200: # src图片不一定是库里面人的指纹 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 = "src.bmp" database = "database" ID = getID(src, database) name = getName(ID) print("识别结果为:", name)二、图片拼接
目的让这两张图无缝衔接成一张图片
做准备:
import cv2 import numpy as np import sys def cv_show(name, img): cv2.imshow(name, img) cv2.waitKey(0) def detectAndDescribe(image): gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) # 将彩色图片转换成灰度图 sift = cv2.SIFT_create() # 建立SIFT生成器 # 检测SIFT特征点,并计算描述符,第二个参数为掩膜 (kps, des) = sift.detectAndCompute(gray, None) # 将结果转换成NumPy数组 kps_float = np.float32([kpc.pt for kpc in kps]) # kpc 包含两个值,分别是关键点在图像中的 x 和 y 坐标。这些坐标通常是浮点数,可以精确地描述关键点在图像中的位置。 return (kps, kps_float, des) # 返回特征点集,及对应的描述特征'''读取拼接图片''' imageA = cv2.imread("zuo.jpg") cv_show('imageA', imageA) imageB = cv2.imread("you.jpg") cv_show('imageB', imageB)'''计算图片特征点及描述符''' (kpsA, kps_floatA, desA) = detectAndDescribe(imageA) (kpsB, kps_floatB, desB) = detectAndDescribe(imageB)'''建立匹配器BFMatcher,在匹配大图训练集合时使用FlannBasedMatcher速度更快。''' matcher = cv2.BFMatcher() rawMatches = matcher.knnMatch(desB, desA, k=2) good = [] matches = [] for m in rawMatches: # 当最近距离跟次近距离的比值小于0.65时,保留此匹配对 if len(m) == 2 and m[0].distance < 0.65 * m[1].distance: good.append(m) # 存储两个点在featuresA、featuresB中的索引值 matches.append((m[0].queryIdx, m[0].trainIdx)) print(len(good)) print(matches) vis = cv2.drawMatchesKnn(imageB, kpsB, imageA, kpsA, good, outImg=None, flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv_show("Keypoint Matches", vis)计算透视变换矩阵
findHomography(srcPoints, dstPoints, method=None, ransacReprojThreshold=None, mask=None, maxIters=None, confidence=None)
- 计算视角变换矩阵,透视变换函数,与cv2.getPerspectiveTransform()的区别在于可多个数据点变换
- 参数srcPoints:图片A的匹配点坐标
- 参数dstPoints:图片B的匹配点坐标
- 参数method:计算变换矩阵的方法。
- ransacReprojThreshold: 最大允许重投影错误阈值。该参数只有在method参数为RANSAC与RHO的时启用,默认为3
findHomography的四种方法:
- H = cv2.findHomography(ptsA, ptsB, 0),0 - 使用所有匹配点计算变换矩阵,最小二乘。
- H = cv2.findHomography(ptsA, ptsB, cv2.RANSAC, 5.0),RANSAC - 随机采样少量点计算模型,测试其他点是否符合。
- H = cv2.findHomography(ptsA, ptsB, cv2.LMEDS), LMEDS - 最小化误差的中位数,而不是平均值
- H = cv2.findHomography(ptsA, ptsB, cv2.RHO), RHO - RANSAC的改进版,使用更智能的采样策略
findHomography返回值解释:
- 返回值:中值为变换矩阵,mask是掩模标志,指示哪些点对应内点,哪些是外点。
- 内点:指那些与估计的模型非常接近的数据点,通常是正确匹配或真实数据。
- 外点:指那些与估计的模型不接近的数据点,通常是错误匹配或噪声数据。
'''透视变换''' if len(matches) > 4: # 当筛选后的匹配对大于4时,计算视角变换矩阵。 # 获取匹配对的点坐标 ptsB = np.float32([kps_floatB[i] for (i, _) in matches]) # matches是通过阈值筛选之后的特征点对象 ptsA = np.float32([kps_floatA[i] for (_, i) in matches]) # kps_floatA是图片A中的全部特征点坐标 H, mask = cv2.findHomography(ptsB, ptsA, cv2.RANSAC, 10) else: print('图片未找到4个以上的匹配点') sys.exit() result = cv2.warpPerspective(imageB, H, (imageB.shape[1] + imageA.shape[1], imageB.shape[0])) cv_show('resultB', result) # 将图片A传入resultB后显示 result[0:imageA.shape[0], 0:imageA.shape[1]] = imageA cv_show('result', result) cv2.imwrite('pingjie.jpg', result)展示zuo和you,并对匹配上的特征进行连线,这点和指纹识别是一样。
展示you图经过透视之后的变化以及最后拼接成功的结果。我们能看出还是有拼接痕迹的,就比如纸箱处。
三、思考
上面我们图像拼接是对b图进行透视转化,把透视的b图拼接在a图的右侧,思考我们能不能对图a进行透视,把a图拼接在b图的左侧。得到下面这种结果的拼接。
