一、指纹识别
1.上篇博客中讲到指纹识别以及对匹配上的点标出,这次我们实现让匹配对应的点连接起来,从连接的线上反应匹配的程度
这里和上篇博客中代码一样,只不过在函数中稍改动了,添加了src_matches=[]这个变量,以及后面对其的使用
python
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.指纹识别并输出对应人名
这段和之前指纹识别的是一样的
python
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
如果要对应上人的姓名这里我们新增两个函数,一是在这这个函数里面进行指纹匹配,获取匹配成功这个指纹图片的编号,二是创建字典每个编号对应一个人
python
# 获取指纹编号
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
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
指纹识别,和哪个编号的指纹对应上就调用函数对应的个人名字。
python
# 主函数
if __name__ == "__main__":
src = "src.bmp"
database = "database"
ID = getID(src, database)
name = getName(ID)
print("识别结果为:", name)
二、图片拼接


目的让这两张图无缝衔接成一张图片
做准备:
python
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) # 返回特征点集,及对应的描述特征
python
'''读取拼接图片'''
imageA = cv2.imread("zuo.jpg")
cv_show('imageA', imageA)
imageB = cv2.imread("you.jpg")
cv_show('imageB', imageB)
python
'''计算图片特征点及描述符'''
(kpsA, kps_floatA, desA) = detectAndDescribe(imageA)
(kpsB, kps_floatB, desB) = detectAndDescribe(imageB)
python
'''建立匹配器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是掩模标志,指示哪些点对应内点,哪些是外点。
- 内点:指那些与估计的模型非常接近的数据点,通常是正确匹配或真实数据。
- 外点:指那些与估计的模型不接近的数据点,通常是错误匹配或噪声数据。
python
'''透视变换'''
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图的左侧。得到下面这种结果的拼接。
