python+OpenCV笔记(三十四):特征匹配——蛮力匹配、蛮力KNN和比率检验过滤匹配
2022/2/4 20:13:16
本文主要是介绍python+OpenCV笔记(三十四):特征匹配——蛮力匹配、蛮力KNN和比率检验过滤匹配,对大家解决编程问题具有一定的参考价值,需要的程序猿们随着小编来一起学习吧!
计算机视觉中,描述符是一种描述关键点的方法,它完全依赖于用来提取描述符的特定算法,并且与关键点(在KeyPoint类中定义)不同,除了每一个描述符表示一个关键点这一点之外,描述符没有共同的结构。
我们可以使用detect函数来检测图像中的一组关键点。类似地,可以使用compute函数从关键点中提取描述符。由于OpenCV中特征检测器与描述提取符组织方法的缘故,将它们联合使用是一件极其容易的事情,即detectAndCompute函数,可以同时进行关键点检测及特征提取,并且比单独调用两个函数更快。
一、蛮力匹配
蛮力匹配器是一个描述符匹配器,它比较两组关键点描述符并生成匹配列表。之所以称为蛮力匹配,是因为在该算法中几乎不涉及优化。对于第一个集合中的每个关键点描述符,匹配器将之与第二个集合中的每个关键点描述符进行比较。每次比较产生一个距离值,并基于最小距离选择最佳匹配。
OpenCV提供了一个cv2.BFMatcher类,支持几种蛮力特征匹配的方法。
下面,我们使用ORB进行特征匹配,使用 cv2.BFMatcher类的 match 方法:
import numpy as np import cv2 from matplotlib import pyplot as plt # 读入图像 imgname1 = 'E:/qi.png' imgname2 = 'E:/qiqiqi.png' img1 = cv2.imread(imgname1) gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) # 灰度处理图像 img2 = cv2.imread(imgname2) gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 灰度处理图像 # 创建ORB特征检测器和描述符 orb = cv2.ORB_create() kp1, des1 = orb.detectAndCompute(img1, None) # des是描述子 kp2, des2 = orb.detectAndCompute(img2, None) # des是描述子 # BFMatcher解决匹配 bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True) matches = bf.match(des1, des2) # 根据匹配的质量,对匹配进行排序,显示前n个排序 matches = sorted(matches, key=lambda x: x.distance) # 绘制前25个最佳匹配 img_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches[:25], img2, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) cv2.imshow("BFmatch", img_matches) cv2.waitKey(0) cv2.destroyAllWindows()
(我们可以看到,很多匹配都是假匹配,这也很典型。为了改善匹配结果,我们需要应用其他技术来过滤糟糕的匹配)
二、蛮力KNN和比率检验过滤匹配
现在,我们来考虑修改后的蛮力匹配算法的实现,该算法以上述方式自适应地选择距离阈值。
上一步,我们使用cv2.BFMatcher类的match方法来获得包含每个查询关键点的单个最佳匹配(最小距离)的列表。这样的实现丢弃了有关所有可能的糟糕匹配的距离分值的信息,而这类信息是自适应方法所需要的。
幸运的是,cv2.BFMatcher还提供了 knnMatch 方法,该方法接受一个参数k,可以指定希望为每个查询关键点保留的最佳(最短距离)匹配的最大数量。
我们会使用knnMatch方法为每个查询关键点请求两个最佳匹配的列表。基于每个查询关键点至多有一个正确匹配的假设,我们确信次优匹配是错误的。次优匹配的距离分值乘以一个小于1的值,就可以获得阈值。然后,只有当距离分值小于阈值时,才将最佳匹配视为良好的匹配。这种方法被称为比率检验。
下面,我们使用ORB进行特征匹配,使用 cv2.BFMatcher类的 knnMatch 方法:
将上一步的部分代码改为:
# BFMatcher解决匹配 bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False) pairs_of_matches = bf.knnMatch(des1, des2, k=2) matches = sorted(pairs_of_matches, key=lambda x: x[0].distance)
同时必须使用drawMatchesKnn 函数
img_matches = cv2.drawMatchesKnn(img1,kp1,img2,kp2,pairs_of_matches[:25], img2,flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS)
结果:
到目前为止,我们并没有过滤掉所有糟糕的匹配,实际上,还故意包含了我们认为是糟糕的次优匹配。
现在,我们应用比率检验,将阈值设置为次优匹配距离分值的0.7倍(自行设置),如果KnnMatch无法提供次优匹配,那么就拒绝最佳匹配,因为无法对其应用检验。
matches = [x[0] for x in pairs_of_matches if len(x) > 1 and x[0].distance < 0.6 * x[1].distance]
应用比率检验后,使用drawMatches 进行绘制。
完整的蛮力knn和比率检验匹配代码:
import numpy as np import cv2 from matplotlib import pyplot as plt # 读入图像 imgname1 = 'E:/qiqiqi.png' imgname2 = 'E:/qi.png' img1 = cv2.imread(imgname1) gray1 = cv2.cvtColor(img1, cv2.COLOR_BGR2GRAY) # 灰度处理图像 img2 = cv2.imread(imgname2) gray2 = cv2.cvtColor(img2, cv2.COLOR_BGR2GRAY) # 灰度处理图像 # 创建ORB特征检测器和描述符 orb = cv2.ORB_create() kp1, des1 = orb.detectAndCompute(img1, None) # des是描述子 kp2, des2 = orb.detectAndCompute(img2, None) # des是描述子 # BFMatcher解决匹配 bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=False) pairs_of_matches = bf.knnMatch(des1, des2, k=2) matches = [x[0] for x in pairs_of_matches if len(x) > 1 and x[0].distance < 0.7 * x[1].distance] img_matches = cv2.drawMatches(img1, kp1, img2, kp2, matches[:25], img2, flags=cv2.DRAW_MATCHES_FLAGS_NOT_DRAW_SINGLE_POINTS) cv2.imshow("KNNmatch", img_matches) cv2.waitKey(0) cv2.destroyAllWindows()
接下来,将使用名为FLANN的更快的匹配器来代替蛮力匹配器。
【参考】:OpenCV 4计算机视觉 Python语言实现(原书第三版) 作者:Joseph Howse
这篇关于python+OpenCV笔记(三十四):特征匹配——蛮力匹配、蛮力KNN和比率检验过滤匹配的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!
- 2024-11-21Python编程基础教程
- 2024-11-20Python编程基础与实践
- 2024-11-20Python编程基础与高级应用
- 2024-11-19Python 基础编程教程
- 2024-11-19Python基础入门教程
- 2024-11-17在FastAPI项目中添加一个生产级别的数据库——本地环境搭建指南
- 2024-11-16`PyMuPDF4LLM`:提取PDF数据的神器
- 2024-11-16四种数据科学Web界面框架快速对比:Rio、Reflex、Streamlit和Plotly Dash
- 2024-11-14获取参数学习:Python编程入门教程
- 2024-11-14Python编程基础入门