一、图像透视转换对该发票图像进行处理只识别这个发票1.函数设置import numpy as np import cv2 def cv_show(name,img): cv2.imshow(name,img) cv2.waitKey(0)将给定的4个点通常是从图像中检测到的四边形角点按固定顺序排列这里为什么不直接用x和y的值对比是因为当图片不是平行于xy的时候可能会出现排序的其他情况这里使用x和y的相加和相减适用于不是很严重的扭曲的四边形而不知服务于这一张图片。xy左上是最小的y-x右上是最小的xy右下是最大的y-x左下是最大的def order_points(pts): rect np.zeros((4, 2), dtype float32)#用来存储排序之后的坐标位置 #按顺序找到对应坐标0123分别是左上右上右下左下 s pts.sum(axis1)#对pts矩阵的每一行进行求和操作xy rect[0] pts[np.argmin(s)] rect[2] pts[np.argmax(s)] diffnp.diff(pts,axis1)#对pts矩阵的每一行进行求差操作。(y-x) rect[1] pts[np.argmin(diff)] rect[3] pts[np.argmax(diff)] return rect图像透视变换 cv2.getPerspectiveTransform(src,dst[,solveMethod]) MP获得转换之间的关系src:变换前图像四边形顶点坐标dst:变换后图像四边形顶点坐标cv2.warpPerspective(src, MP, dsizel, dst[, flags[, borderNode[, borderValue]]]]) dst参数说明:src:原图MP:透视变换矩阵3行3列dsize:输出图像的大小二元元组(widthheight)def four_point_transform(image, pts): # 获取输入坐标点把四个点进行排序左上右上右下左下 rect order_points(pts) #计算原始四边形的宽和高也许不是矩形所以宽高两边不一定相等 (tl, tr, br, bl) rect widthA np.sqrt(((br[0] - bl[0]) ** 2) ((br[1] - bl[1]) ** 2)) widthB np.sqrt(((tr[0] - tl[0]) ** 2) ((tr[1] - tl[1]) ** 2)) maxWidth max(int(widthA), int(widthB))#取最大值作为输出宽度 heightA np.sqrt(((tr[0] - br[0]) ** 2) ((tr[1] - br[1]) ** 2)) heightB np.sqrt(((tl[0] - bl[0]) ** 2) ((tl[1] - bl[1]) ** 2)) maxHeight max(int(heightA), int(heightB))#取最大值作为输出高度 # 变换后对应坐标位置 dst np.array( [[0, 0],#左上 [maxWidth - 1, 0],#右下 [maxWidth - 1, maxHeight - 1], #右下 [0, maxHeight - 1]], dtype float32)#左下 #计算透视变换矩阵 M cv2.getPerspectiveTransform(rect, dst) #应用变换 warped cv2.warpPerspective(image, M,(maxWidth, maxHeight)) return warped将图像中倾斜、扭曲的四边形区域如倾斜拍摄的文档、车牌、票据等转换为正面的矩形视图def resize(image,widthNone,heightNone,intercv2.INTER_AREA): dimNone (h,w)image.shape[:2] if width is None and height is None: return image if width is None: rheight/float(h) dim(int(w*r),height) else: rwidth/float(w) dim(width,int(h*r)) resizedcv2.resize(image,dim,interpolationinter) #默认为cv2.INTER_AREA即面积插值适用于缩放图像。 return resized#读取输入 imagecv2.imread(fapiao.jpg) # cv_show(image,image) #图片过大进行缩小处理 radioimage.shape[0]/500#计算缩小比率 origimage.copy() imageresize(orig,height500) # cv_show(1,image)#轮廓检测 print(step1:轮廓检测) graycv2.cvtColor(image,cv2.COLOR_BGR2GRAY) edgedcv2.threshold(gray,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]#自动寻找阈值二值化 cntscv2.findContours(edged.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)[-2] image_contourscv2.drawContours(image.copy(),cnts,-1,(0,0,255),1) # cv_show(image_contours,image_contours) print(step2:最大轮廓获取) screencntsorted(cnts,keycv2.contourArea,reverseTrue)[0]#获取面积最大的轮廓 print(screencnt.shape) pericv2.arcLength(screencnt,True)#计算轮廓周长 screencntcv2.approxPolyDP(screencnt,0.05*peri,True)#轮廓近似 print(screencnt.shape) image_contourcv2.drawContours(image.copy(),[screencnt],-1,(0,255,0),2) # cv2.imshow(image_contour,image_contour) # cv2.waitKey(0)cv2.namedWindow( xx2,cv2.WINDOW_NORMAL)能让窗口能放大拉小warped four_point_transform(orig, screencnt.reshape(4, 2) * radio) cv2.namedWindow( xx2,cv2.WINDOW_NORMAL) # cv2.imshow(xx1, warped3) cv2.imshow(xx2, warped) cv2.waitKey(0)输出结果想要更清晰的结果可以对该图片继续处理二值化腐蚀等……也可以用图片旋转把他旋转正这里我们需要注意如果我们想让文字变粗该图片二值化之后是白底黑字用的是腐蚀因为腐蚀是让黑色区域变大如果我们二值化的时候就把黑白颠倒使得图片是黑底白字就要用膨胀因为膨胀是让白色区域更大二、角点检测角点指图像中局部区域与周围区域有较大灰度变化的点或像素。不仅限于上下有较大变化左右也有很大变化的时候才是角点。eg左上图上下时候有明显改变但左右平移的时候颜色就没有明显改变的无角点左下图左右有明显改变但上下没有所以无角点右图中1到3有明显改变1到2也有明显改变那么1中有角点cornerHarris(img, blockSize, ksize, k[, dst[, borderType]]) - dstimg:输入图像。blockSize:角点检测中要考虑的领域大小。ksize:Sobel求导中使用的窗口大小。k:Harris角点检测方程中的自由参数,取值参数为[0.04,0.06]。dst:返回numpy.ndarray对象大小和src相同值越大对应像素点是角的概率越高import cv2 imgcv2.imread(rD:\project\whitex.jpg) graycv2.cvtColor(img,cv2.COLOR_BGR2GRAY) dstcv2.cornerHarris(gray,4,3,0.04)#blocksize,ksize,k #标记检测到的角点 #这里通过对角点响应进行阈值处理标记出检测到的角点。 #0.05*dst.max()是一个阈值大于这个值的像素点会被标记为红色。 img[dst0.01*dst.max()][0,255,255]#超过最大值的百分之五就被划为角点 cv2.namedWindow( img,cv2.WINDOW_NORMAL) cv2.imshow(img,img) cv2.waitKey(0)三、sift特征检测检测图像中的关键点cv2.SIFT_create()cv2.xfeatures2d.SIFT_create()创建一个sift特征的提取对象sift.detect(img)在图像中查找关键点kpkp.pt:关键点的(x,y) 坐标。kp.size:关键点的大小(尺度).kp.angle:关键点的方向.kp.response:关键点的响应值。kp.0ctave:关键点所在的金字塔层级.查找关键点drawkeypoints(image, keypoints, outImage, colorNone, flagsNone)image:原始图片 keypoints:从原图中获得的关键点这也是画图时所用到的数据outpytimag:输出图像可以是原始图片,也可以是None color:颜色设置通过修改(b,9,r)的值,更改画笔的颜色b蓝色g绿色r红色。flags:绘图功能的标识设置,绘制富有信息的关键点。import cv2 import numpy as np imgcv2.imread(qqqqss.jpg) graycv2.cvtColor(img,cv2.COLOR_BGR2GRAY) siftcv2.SIFT_create()#sift对象 kpsift.detect(gray) graycv2.drawKeypoints(img,kp,None,flagscv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imshow(gray,gray) cv2.waitKey(0) #使用sift.compute()计算关键点描述符方便后期的特征匹配 kp,dessift.compute(img,kp) print(np.array(kp).shape,des.shape) #输出关键点的形状和描述符的形状。 # np.array(kp).shape表示关键点的数量和属性。 #des.shape表示描述符的数量和属性。四、指纹识别import cv2 def cv_show(name,img): cv2.imshow(name,img) cv2.waitKey(0)def verification(src,model): siftcv2.SIFT_create()#创建sift特征提取器 # 检测关键点和计算描述符特征向量源图像 kp1,des1sift.detectAndCompute(src,None) # 检测关键点和计算描述符特征向量模板图像 kp2,des2sift.detectAndCompute(model,None) #创建flann匹配器 flanncv2.FlannBasedMatcher() #使用k近邻匹配des1中的每个描述符与des2中的最近链各个描述符进行匹配 matchesflann.knnMatch(des1,des2,k2) #distance匹配的特征点描述符的欧式距离数值越小也就越说明两个特征点越相近 #queryidx测试图像的特征点描述符的下标第几个特征点描述符同时也是描述对应特征点的下标 #trainidx样本图像的特征点描述符下标同时也是描述符对应特征点的下标 #进行比较筛选 ok[] for m,n in matches: #根据lowe比率测试选择最佳匹配 if m.distance0.4*n.distance:#值越小越严格 ok.append((m,n)) numlen(ok)#统计通过筛选匹配的数量 if num 50:#共同点设置标准多少为成功是可以调整的要根据上面数值进行设置 result认证通过 else: result认证失败 return resultif __name____main__: src1cv2.imread(zhiwen1.bmp) src2cv2.imread(zhiwen2.bmp) model cv2.imread(zhiwen_model.bmp) cv2.imshow(src1,src1) cv2.imshow(src2,src2) cv2.imshow(model,model) cv2.waitKey(0) reselt1verification(src1,model) reselt2verification(src2,model) print(src1的结果为,reselt1) print(src2的结果为,reselt2)这里能进行识别但是没有展示出指纹那些点匹配上了如果要展示哪些点匹配上了我们需要修改函数verification绘制匹配点连线 drawMatchesKnn(img1,keypoints1,img2,keypoints2,matches1to2,outImg,matchColorNone,singlePointColorNone,matchesMaskNone) 绘制匹配图片 参数img1第一张原始图片keypoints1第一张原始图像的关键点matches1to2从第一个图像到第二个图像的匹配也就是说keypoints1[i]keypoints2[i]中有一个对应的点outImg绘制结果图像matchColor匹配连线与关键点的颜色当matchColor Scalar::all(-1)时代表取随机颜色。singlePointColor:没有匹配项的关键点的颜色当singlePointColor Scalar::all(-1)时代表取随机颜色。matchesMask:确定绘制哪些匹配项的掩码。如果掩码为空则绘制所有匹配项。flags:绘图功能的一些标志。cv2.drawMatches()和cv2.drawMatchesKnn()函数的绘制标志控制如何绘制匹配点有:cv2.DRAW_MATCHES_FLAGS_DEFAULT默认模式只绘制匹配点之间的连线不单独绘制关键点除非该点没有匹配关键点显示为小圆圈最简洁适合大多数情况cv2. DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS丰富关键点模式绘制匹配连线绘制完整的关键点圆圈带方向尺度信息圆圈大小表示关键点尺度圆圈上的线段表示关键点方向能显示关键点的更多信息用于调试和分析cv2.DRAW_MATCHES_FLAGS_ DRAW_OVER_OUTIMG在原图上绘制模式不在新建的画布上绘制直接在提供的输出图像上outImg上绘制需要先创建输出图像outImgnp.zeros需要自定义背景或叠加到现有图像上cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS不绘制单点模式不绘制没有匹配的关键点只绘制有匹配的关键点和连线只想看匹配成功的点过滤掉未匹配的点。def verification(src,model,show_matchsFalse): siftcv2.SIFT_create()#创建sift特征提取器 kp1,des1sift.detectAndCompute(src,None) kp2,des2sift.detectAndCompute(model,None) flanncv2.FlannBasedMatcher() matchesflann.knnMatch(des1,des2,k2) ok[] src_matches[] model_matches[] for m,n in matches:#m是最佳匹配n为次家匹配 if m.distance0.4*n.distance: ok.append((m,n)) src_matches.append(kp1[m.queryIdx].pt)#测试图像中匹配点的坐标 model_matches.append(kp2[m.trainIdx].pt)#模版图像中的匹配点坐标 numlen(ok) if num 50: result认证通过 else: result认证失败 if show_matchs and len(src_matches)0:#复制图像避免修改原图 src_with_matchessrc.copy() model_with_matchesmodel.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) return result,num,src_matches,model_matches最后主函数中修改reselt1,num1,src1_matches,model1_matchesverification(src1,model,show_matchsTrue) reselt2,num2,src2_matches,model2_matchesverification(src2,model,show_matchsTrue) print(src1的结果为,reselt1,匹配点数{}.format(num1)) print(src2的结果为,reselt2,匹配点数{}.format(num2))
计算机视觉opencv之图像透视转换角点检测sift特征检测指纹识别
一、图像透视转换对该发票图像进行处理只识别这个发票1.函数设置import numpy as np import cv2 def cv_show(name,img): cv2.imshow(name,img) cv2.waitKey(0)将给定的4个点通常是从图像中检测到的四边形角点按固定顺序排列这里为什么不直接用x和y的值对比是因为当图片不是平行于xy的时候可能会出现排序的其他情况这里使用x和y的相加和相减适用于不是很严重的扭曲的四边形而不知服务于这一张图片。xy左上是最小的y-x右上是最小的xy右下是最大的y-x左下是最大的def order_points(pts): rect np.zeros((4, 2), dtype float32)#用来存储排序之后的坐标位置 #按顺序找到对应坐标0123分别是左上右上右下左下 s pts.sum(axis1)#对pts矩阵的每一行进行求和操作xy rect[0] pts[np.argmin(s)] rect[2] pts[np.argmax(s)] diffnp.diff(pts,axis1)#对pts矩阵的每一行进行求差操作。(y-x) rect[1] pts[np.argmin(diff)] rect[3] pts[np.argmax(diff)] return rect图像透视变换 cv2.getPerspectiveTransform(src,dst[,solveMethod]) MP获得转换之间的关系src:变换前图像四边形顶点坐标dst:变换后图像四边形顶点坐标cv2.warpPerspective(src, MP, dsizel, dst[, flags[, borderNode[, borderValue]]]]) dst参数说明:src:原图MP:透视变换矩阵3行3列dsize:输出图像的大小二元元组(widthheight)def four_point_transform(image, pts): # 获取输入坐标点把四个点进行排序左上右上右下左下 rect order_points(pts) #计算原始四边形的宽和高也许不是矩形所以宽高两边不一定相等 (tl, tr, br, bl) rect widthA np.sqrt(((br[0] - bl[0]) ** 2) ((br[1] - bl[1]) ** 2)) widthB np.sqrt(((tr[0] - tl[0]) ** 2) ((tr[1] - tl[1]) ** 2)) maxWidth max(int(widthA), int(widthB))#取最大值作为输出宽度 heightA np.sqrt(((tr[0] - br[0]) ** 2) ((tr[1] - br[1]) ** 2)) heightB np.sqrt(((tl[0] - bl[0]) ** 2) ((tl[1] - bl[1]) ** 2)) maxHeight max(int(heightA), int(heightB))#取最大值作为输出高度 # 变换后对应坐标位置 dst np.array( [[0, 0],#左上 [maxWidth - 1, 0],#右下 [maxWidth - 1, maxHeight - 1], #右下 [0, maxHeight - 1]], dtype float32)#左下 #计算透视变换矩阵 M cv2.getPerspectiveTransform(rect, dst) #应用变换 warped cv2.warpPerspective(image, M,(maxWidth, maxHeight)) return warped将图像中倾斜、扭曲的四边形区域如倾斜拍摄的文档、车牌、票据等转换为正面的矩形视图def resize(image,widthNone,heightNone,intercv2.INTER_AREA): dimNone (h,w)image.shape[:2] if width is None and height is None: return image if width is None: rheight/float(h) dim(int(w*r),height) else: rwidth/float(w) dim(width,int(h*r)) resizedcv2.resize(image,dim,interpolationinter) #默认为cv2.INTER_AREA即面积插值适用于缩放图像。 return resized#读取输入 imagecv2.imread(fapiao.jpg) # cv_show(image,image) #图片过大进行缩小处理 radioimage.shape[0]/500#计算缩小比率 origimage.copy() imageresize(orig,height500) # cv_show(1,image)#轮廓检测 print(step1:轮廓检测) graycv2.cvtColor(image,cv2.COLOR_BGR2GRAY) edgedcv2.threshold(gray,0,255,cv2.THRESH_BINARY | cv2.THRESH_OTSU)[1]#自动寻找阈值二值化 cntscv2.findContours(edged.copy(),cv2.RETR_LIST,cv2.CHAIN_APPROX_SIMPLE)[-2] image_contourscv2.drawContours(image.copy(),cnts,-1,(0,0,255),1) # cv_show(image_contours,image_contours) print(step2:最大轮廓获取) screencntsorted(cnts,keycv2.contourArea,reverseTrue)[0]#获取面积最大的轮廓 print(screencnt.shape) pericv2.arcLength(screencnt,True)#计算轮廓周长 screencntcv2.approxPolyDP(screencnt,0.05*peri,True)#轮廓近似 print(screencnt.shape) image_contourcv2.drawContours(image.copy(),[screencnt],-1,(0,255,0),2) # cv2.imshow(image_contour,image_contour) # cv2.waitKey(0)cv2.namedWindow( xx2,cv2.WINDOW_NORMAL)能让窗口能放大拉小warped four_point_transform(orig, screencnt.reshape(4, 2) * radio) cv2.namedWindow( xx2,cv2.WINDOW_NORMAL) # cv2.imshow(xx1, warped3) cv2.imshow(xx2, warped) cv2.waitKey(0)输出结果想要更清晰的结果可以对该图片继续处理二值化腐蚀等……也可以用图片旋转把他旋转正这里我们需要注意如果我们想让文字变粗该图片二值化之后是白底黑字用的是腐蚀因为腐蚀是让黑色区域变大如果我们二值化的时候就把黑白颠倒使得图片是黑底白字就要用膨胀因为膨胀是让白色区域更大二、角点检测角点指图像中局部区域与周围区域有较大灰度变化的点或像素。不仅限于上下有较大变化左右也有很大变化的时候才是角点。eg左上图上下时候有明显改变但左右平移的时候颜色就没有明显改变的无角点左下图左右有明显改变但上下没有所以无角点右图中1到3有明显改变1到2也有明显改变那么1中有角点cornerHarris(img, blockSize, ksize, k[, dst[, borderType]]) - dstimg:输入图像。blockSize:角点检测中要考虑的领域大小。ksize:Sobel求导中使用的窗口大小。k:Harris角点检测方程中的自由参数,取值参数为[0.04,0.06]。dst:返回numpy.ndarray对象大小和src相同值越大对应像素点是角的概率越高import cv2 imgcv2.imread(rD:\project\whitex.jpg) graycv2.cvtColor(img,cv2.COLOR_BGR2GRAY) dstcv2.cornerHarris(gray,4,3,0.04)#blocksize,ksize,k #标记检测到的角点 #这里通过对角点响应进行阈值处理标记出检测到的角点。 #0.05*dst.max()是一个阈值大于这个值的像素点会被标记为红色。 img[dst0.01*dst.max()][0,255,255]#超过最大值的百分之五就被划为角点 cv2.namedWindow( img,cv2.WINDOW_NORMAL) cv2.imshow(img,img) cv2.waitKey(0)三、sift特征检测检测图像中的关键点cv2.SIFT_create()cv2.xfeatures2d.SIFT_create()创建一个sift特征的提取对象sift.detect(img)在图像中查找关键点kpkp.pt:关键点的(x,y) 坐标。kp.size:关键点的大小(尺度).kp.angle:关键点的方向.kp.response:关键点的响应值。kp.0ctave:关键点所在的金字塔层级.查找关键点drawkeypoints(image, keypoints, outImage, colorNone, flagsNone)image:原始图片 keypoints:从原图中获得的关键点这也是画图时所用到的数据outpytimag:输出图像可以是原始图片,也可以是None color:颜色设置通过修改(b,9,r)的值,更改画笔的颜色b蓝色g绿色r红色。flags:绘图功能的标识设置,绘制富有信息的关键点。import cv2 import numpy as np imgcv2.imread(qqqqss.jpg) graycv2.cvtColor(img,cv2.COLOR_BGR2GRAY) siftcv2.SIFT_create()#sift对象 kpsift.detect(gray) graycv2.drawKeypoints(img,kp,None,flagscv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS) cv2.imshow(gray,gray) cv2.waitKey(0) #使用sift.compute()计算关键点描述符方便后期的特征匹配 kp,dessift.compute(img,kp) print(np.array(kp).shape,des.shape) #输出关键点的形状和描述符的形状。 # np.array(kp).shape表示关键点的数量和属性。 #des.shape表示描述符的数量和属性。四、指纹识别import cv2 def cv_show(name,img): cv2.imshow(name,img) cv2.waitKey(0)def verification(src,model): siftcv2.SIFT_create()#创建sift特征提取器 # 检测关键点和计算描述符特征向量源图像 kp1,des1sift.detectAndCompute(src,None) # 检测关键点和计算描述符特征向量模板图像 kp2,des2sift.detectAndCompute(model,None) #创建flann匹配器 flanncv2.FlannBasedMatcher() #使用k近邻匹配des1中的每个描述符与des2中的最近链各个描述符进行匹配 matchesflann.knnMatch(des1,des2,k2) #distance匹配的特征点描述符的欧式距离数值越小也就越说明两个特征点越相近 #queryidx测试图像的特征点描述符的下标第几个特征点描述符同时也是描述对应特征点的下标 #trainidx样本图像的特征点描述符下标同时也是描述符对应特征点的下标 #进行比较筛选 ok[] for m,n in matches: #根据lowe比率测试选择最佳匹配 if m.distance0.4*n.distance:#值越小越严格 ok.append((m,n)) numlen(ok)#统计通过筛选匹配的数量 if num 50:#共同点设置标准多少为成功是可以调整的要根据上面数值进行设置 result认证通过 else: result认证失败 return resultif __name____main__: src1cv2.imread(zhiwen1.bmp) src2cv2.imread(zhiwen2.bmp) model cv2.imread(zhiwen_model.bmp) cv2.imshow(src1,src1) cv2.imshow(src2,src2) cv2.imshow(model,model) cv2.waitKey(0) reselt1verification(src1,model) reselt2verification(src2,model) print(src1的结果为,reselt1) print(src2的结果为,reselt2)这里能进行识别但是没有展示出指纹那些点匹配上了如果要展示哪些点匹配上了我们需要修改函数verification绘制匹配点连线 drawMatchesKnn(img1,keypoints1,img2,keypoints2,matches1to2,outImg,matchColorNone,singlePointColorNone,matchesMaskNone) 绘制匹配图片 参数img1第一张原始图片keypoints1第一张原始图像的关键点matches1to2从第一个图像到第二个图像的匹配也就是说keypoints1[i]keypoints2[i]中有一个对应的点outImg绘制结果图像matchColor匹配连线与关键点的颜色当matchColor Scalar::all(-1)时代表取随机颜色。singlePointColor:没有匹配项的关键点的颜色当singlePointColor Scalar::all(-1)时代表取随机颜色。matchesMask:确定绘制哪些匹配项的掩码。如果掩码为空则绘制所有匹配项。flags:绘图功能的一些标志。cv2.drawMatches()和cv2.drawMatchesKnn()函数的绘制标志控制如何绘制匹配点有:cv2.DRAW_MATCHES_FLAGS_DEFAULT默认模式只绘制匹配点之间的连线不单独绘制关键点除非该点没有匹配关键点显示为小圆圈最简洁适合大多数情况cv2. DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS丰富关键点模式绘制匹配连线绘制完整的关键点圆圈带方向尺度信息圆圈大小表示关键点尺度圆圈上的线段表示关键点方向能显示关键点的更多信息用于调试和分析cv2.DRAW_MATCHES_FLAGS_ DRAW_OVER_OUTIMG在原图上绘制模式不在新建的画布上绘制直接在提供的输出图像上outImg上绘制需要先创建输出图像outImgnp.zeros需要自定义背景或叠加到现有图像上cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS不绘制单点模式不绘制没有匹配的关键点只绘制有匹配的关键点和连线只想看匹配成功的点过滤掉未匹配的点。def verification(src,model,show_matchsFalse): siftcv2.SIFT_create()#创建sift特征提取器 kp1,des1sift.detectAndCompute(src,None) kp2,des2sift.detectAndCompute(model,None) flanncv2.FlannBasedMatcher() matchesflann.knnMatch(des1,des2,k2) ok[] src_matches[] model_matches[] for m,n in matches:#m是最佳匹配n为次家匹配 if m.distance0.4*n.distance: ok.append((m,n)) src_matches.append(kp1[m.queryIdx].pt)#测试图像中匹配点的坐标 model_matches.append(kp2[m.trainIdx].pt)#模版图像中的匹配点坐标 numlen(ok) if num 50: result认证通过 else: result认证失败 if show_matchs and len(src_matches)0:#复制图像避免修改原图 src_with_matchessrc.copy() model_with_matchesmodel.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) return result,num,src_matches,model_matches最后主函数中修改reselt1,num1,src1_matches,model1_matchesverification(src1,model,show_matchsTrue) reselt2,num2,src2_matches,model2_matchesverification(src2,model,show_matchsTrue) print(src1的结果为,reselt1,匹配点数{}.format(num1)) print(src2的结果为,reselt2,匹配点数{}.format(num2))