ICode9

精准搜索请尝试: 精确搜索
首页 > 编程语言> 文章详细

python+OpenCV笔记(三十四):特征匹配——蛮力匹配、蛮力KNN和比率检验过滤匹配

2022-02-04 18:35:41  阅读:227  来源: 互联网

标签:KNN 匹配 BFMatcher matches cv2 蛮力 img2 关键点


        计算机视觉中,描述符是一种描述关键点的方法,它完全依赖于用来提取描述符的特定算法,并且与关键点(在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

标签:KNN,匹配,BFMatcher,matches,cv2,蛮力,img2,关键点
来源: https://blog.csdn.net/qq_45832961/article/details/122769960

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有