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和比率检验过滤匹配的文章就介绍到这儿,希望我们推荐的文章对大家有所帮助,也希望大家多多支持为之网!


扫一扫关注最新编程教程