特征匹配 OpenCV-Python v4.7.0

目标

在本章中

  • 我们将看到如何将一个图像中的特征与其他图像进行匹配。
  • 我们将使用OpenCV中的Brute-Force匹配器和FLANN匹配器。

暴力匹配器的基础知识

Brute-Force 匹配器很简单。它将第一组中的一个特征的描述符与第二组中的所有其他特征使用某种距离计算进行匹配。然后返回最接近的一个。

对于BF匹配器,首先我们必须使用cv.BFMatcher()创建BFMatcher对象。它需要两个可选的参数。第一个是normType。它指定了要使用的距离测量。默认情况下,它是cv.NORM_L2。它适用于SIFT、SURF等(cv.NORM_L1也是如此)。对于基于二进制字符串的描述符,如ORB、BRIEF、BRISK等,应该使用cv.NORM_HAMMING,它使用汉明距离作为测量。如果ORB使用WTA_K == 3或4,应该使用cv.NORM_HAMMING2

第二个参数是布尔变量,crossCheck,默认为假。如果它为真,Matcher只返回那些具有(i,j)值的匹配,即A组的第i个描述符与B组的第j个描述符是最佳匹配,反之亦然。也就是说,两组中的两个特征应该是相互匹配的。它提供了一致的结果,是D.Lowe在SIFT论文中提出的比率测试的良好替代。

一旦它被创建,两个重要的方法是BFMatcher.match()BFMatcher.knnMatch()。第一个方法返回最佳匹配。第二个方法返回k个最佳匹配,其中k是由用户指定的。当我们需要做额外的工作时,它可能是有用的。

就像我们用cv.drawKeypoints()来画关键点一样,cv.drawMatches()帮助我们画出匹配。它将两张图片水平堆叠,并从第一张图片画线到第二张图片,显示最佳匹配。还有一个cv.drawMatchesKnn可以画出所有的k个最佳匹配。如果k=2,它将为每个关键点画两条匹配线。因此,如果我们想有选择地绘制它,我们必须传递一个掩码。

让我们看看SIFT和ORB各一个例子(两者使用不同的距离测量)。

用ORB描述符进行暴力匹配

在这里,我们将看到一个简单的例子,说明如何在两个图像之间进行特征匹配。在这种情况下,我有一个queryImage和一个trainImage。我们将尝试使用特征匹配在trainImage中找到queryImage。( 图片是 /samples/data/box.png 和 /samples/data/box_in_scene.png)

我们正在使用ORB描述符来匹配特征。因此,让我们开始加载图像,寻找描述符等。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('box.png',cv.IMREAD_GRAYSCALE)          # queryImage
img2 = cv.imread('box_in_scene.png',cv.IMREAD_GRAYSCALE) # trainImage
# 启动ORB检测器
orb = cv.ORB_create()
# 用ORB找到关键点和描述符
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

接下来我们创建一个BFMatcher对象,其距离测量值为cv.NORM_HAMMING(因为我们使用的是ORB),为了获得更好的结果,交叉检查被打开了。然后我们使用Matcher.match()方法来获得两张图片中的最佳匹配。我们按照距离的升序对它们进行排序,使最佳匹配(低距离)排在前面。然后我们只画出前10个匹配的图片(只是为了可见性,你可以根据自己的需要增加)。

# 创建BFMatcher对象
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
# 匹配描述符
matches = bf.match(des1,des2)
# 按照它们的距离顺序进行排序
matches = sorted(matches, key = lambda x:x.distance)
# D绘制前10个匹配结果
img3 = cv.drawMatches(img1,kp1,img2,kp2,matches[:10],None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
plt.imshow(img3),plt.show()

以下是我得到的结果:
在这里插入图片描述

这个匹配器对象是什么?

matches = bf.match(des1,des2) 行的结果是一个DMatch对象的列表。这个DMatch对象有以下属性:

  • DMatch.distance - 描述符之间的距离。越低越好。
  • DMatch.trainIdx - 描述符在训练描述符中的索引。
  • DMatch.queryIdx - 查询描述符中描述符的索引。
  • DMatch.imgIdx - 训练图像的索引。
用SIFT描述符和比率测试进行暴力匹配

这一次,我们将使用BFMatcher.knnMatch()来获得k个最佳匹配。在这个例子中,我们将采用k=2,这样我们就可以应用D.Lowe在他的论文中解释的比率测试。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('box.png',cv.IMREAD_GRAYSCALE)          # queryImage
img2 = cv.imread('box_in_scene.png',cv.IMREAD_GRAYSCALE) # trainImage
# 启动SIFT检测器
sift = cv.SIFT_create()
# 用SIFT找到关键点和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# 带有默认参数的BFMatcher
bf = cv.BFMatcher()
matches = bf.knnMatch(des1,des2,k=2)
# 应用比率测试
good = []
for m,n in matches:
    if m.distance < 0.75*n.distance:
        good.append([m])
# cv.drawMatchesKnn希望将列表作为匹配
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,None,flags=cv.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)
plt.imshow(img3),plt.show()

请看下面的结果:
在这里插入图片描述

基于FLANN的匹配器

FLANN是Fast Library for Approximate Nearest Neighbors的缩写。它包含一个算法集合,为在大数据集和高维特征中进行快速近邻搜索而优化。对于大数据集,它比BFMatcher工作得更快。我们将看到第二个例子,即基于FLANN的匹配器。

对于基于FLANN的匹配器,我们需要传递两个字典,以指定要使用的算法及其相关参数等。第一个是IndexParams。对于各种算法,需要传递的信息在FLANN文档中有所解释。总的来说,对于像SIFT、SURF等算法,你可以传递以下信息:

FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)

当使用ORB时,你可以传递以下内容。根据文档,建议使用注释值,但在某些情况下,它没有提供所需的结果。其他值可以正常工作:

FLANN_INDEX_LSH = 6
index_params= dict(algorithm = FLANN_INDEX_LSH,
                   table_number = 6, # 12
                   key_size = 12,     # 20
                   multi_probe_level = 1) #2

第二个字典是 SearchParams。它指定了索引中的树应该被递归遍历的次数。更高的值可以提供更好的精度,但也需要更多的时间。如果你想改变这个值,传递 search_params = dict(check=100)。

有了这些信息,我们就可以开始了。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('box.png',cv.IMREAD_GRAYSCALE)          # queryImage
img2 = cv.imread('box_in_scene.png',cv.IMREAD_GRAYSCALE) # trainImage
# 启动SIFT检测器
sift = cv.SIFT_create()
# 用SIFT找到关键点和描述符
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# FLANN参数
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # 或者传递空字典
flann = cv.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)
# 需要只画出好的匹配,所以创建一个蒙版
matchesMask = [[0,0] for i in range(len(matches))]
# 按照Lowe的论文,进行比率测试
for i,(m,n) in enumerate(matches):
    if m.distance < 0.7*n.distance:
        matchesMask[i]=[1,0]
draw_params = dict(matchColor = (0,255,0),
                   singlePointColor = (255,0,0),
                   matchesMask = matchesMask,
                   flags = cv.DrawMatchesFlags_DEFAULT)
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)
plt.imshow(img3,),plt.show()

请看下面的结果:
在这里插入图片描述

  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
### 回答1: 这个错误通常是因为 OpenCV 无法找到特定的窗口或图像文件。可能有几个原因导致这个问题,比如: 1. 图像路径错误:请确保您提供的图像路径是正确的,并且图像文件确实存在。 2. 窗口名错误:如果您正在尝试访问一个不存在的窗口,请确保您输入的窗口名是正确的。 3. OpenCV 版本问题:某些版本的 OpenCV 可能会遇到此问题。尝试更新到最新版本或回退到较旧的版本。 4. 编译问题:如果您是自己编译的 OpenCV,那么可能会出现编译问题。请检查您的编译选项是否正确,并且您的代码与您所编译的版本兼容。 您可以尝试通过检查以上原因来解决这个问题。如果还有问题,您可以提供更多的错误信息和代码,以便更好地帮助您解决问题。 ### 回答2: cv2.error是OpenCV库的一个错误类型。该错误通常发生在使用opencv-python库时,具体位于highgui模块的window.cpp文件的第971行。 这个错误可能有多种原因。一种可能是在调用opencv-python库中的图形用户界面函数时出现了问题。这些函数负责创建和管理窗口,显示和处理图像等。可能是参数传递错误或者部分必需的库文件缺失导致的。 解决这个错误的方法有几种。首先,我们可以检查所使用的OpenCV版本是否与报错中的版本匹配。如果版本不一致,可以尝试升级或降级到与所安装的库匹配的版本。 其次,我们可以检查所使用的参数是否正确。确保正确设置窗口的相关属性和参数。 另外,还应该确保所使用的库文件完整且正确安装。有时候,缺少某些关键的库文件会导致该错误的发生。可以尝试重新安装opencv-python库,或者手动安装所需的库文件。 如果上述方法都不起作用,还可以尝试卸载并重新安装opencv-python库。这将清除可能存在的任何错误或冲突,并重新安装库文件,以便修复错误。 总之,cv2.error: OpenCV(4.7.0) D:\a\opencv-python\opencv-python\opencv\modules\highgui\src\window.cpp:971:... 是OpenCV库在窗口管理函数中的一个错误。通过检查版本、参数和库文件的完整性,可以解决这个问题。 ### 回答3: 这个错误提示显示了在使用OpenCV库的高级图形用户界面模块时发生了一个错误,程序找不到具体的窗口.cpp文件。通常,这种错误是由于以下几个原因之一: 1. OpenCV库版本不兼容:发生这个错误的可能性之一是您安装的OpenCV库版本与当前程序代码不兼容。解决这个问题的方法是确保OpenCV库的版本与您的程序代码所需的版本匹配。 2. 缺少依赖库:OpenCV库需要一些其他的依赖库来正常工作,如图形库、视频库等。这个错误有可能是由于缺少这些依赖库造成的。您可以通过检查您的系统环境和OpenCV库的依赖项来解决这个问题。 3. 文件路径错误:这个错误显示了cpp文件的具体路径,可能是由于您的程序代码中引用的OpenCV库文件的路径不正确导致的。您可以检查程序代码中的路径设置和文件引用,确保它们指向正确的文件路径。 解决这个问题的方法是首先确定OpenCV库的版本和您的代码要求的版本是否匹配。然后,您可以检查系统环境和库的依赖项,确认所有的依赖库都已正确安装。最后,您可以检查程序代码中的文件路径设置和文件引用,确保它们正确指向OpenCV库文件的路径。如果问题仍然存在,您可以查阅OpenCV的官方文档和社区,了解更多关于这个错误的详细信息和解决方案。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值