【翻译:OpenCV-Python教程】特征匹配

⚠️由于自己的拖延症,3.4.3翻到一半,OpenCV发布了4.0.1了正式版,所以接下来是按照4.0.1翻译的。

⚠️除了版本之外,其他还是照旧,Feature Matching,原文

目标

在这章

  • 我们将看到如何将一张图片中的特征与其他图片进行匹配。
  • 我们会使用 OpenCV 里的 蛮力匹配器 以及 FLANN 匹配器。

蛮力匹配器的基础

蛮力匹配器很简单。它取一个特征在第一个集合中的描述符,然后去匹配在第二个集合中的所有其他的特征,通过某种距离计算。然后返回距离最近的那个。

对于蛮力匹配器,首先我们必须创建一个蛮力匹配器对象,使用函数 cv.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 默认是false。如果是 true,匹配器只返回那些(i,j)匹配,意思就是说在A集合中的第i个描述符,和B集合中的第j个描述符,有着最优匹配,反之亦然。也就是说,两个集合中的这两个特性应该相互是匹配的。它提供了一致的结果,这是一个对于比率检定(Ratio Test)来说非常棒的修改,它由 D.Lowe 提出在SIFT的论文里。

它(蛮力匹配器对象)创建完成之后,两个重要的方法需要被提及 BFMatcher.match()BFMatcher.knnMatch() 。第一个返回最佳的匹配,第二个方法返回k个最接近的匹配,k由用户指定(译者注:第一个方法其实就是k=1的情况)。当我们需要在这方面做额外的工作时,它可能是有用的。

就像我们使用过 cv.drawKeypoints() 来画出关键点一样,cv.drawMatches() 帮助我们画出这些匹配。它水平地堆叠两个图像,并从第一个图像到第二个图像绘制线,以显示最佳匹配。同样也有 cv.drawMatchesKnn 个函数来绘制k个最佳匹配关系。如果 k=2,它会为每个关键点画出两条匹配线条。因此我们必须传入一个遮罩图层,如果我们需要有选择的画出来的话。

让我们来分别针对SURF 和 ORB算法来看一个例子(它俩使用不同的距离衡量方式)。

蛮力匹配 ORB 描述符

现在,我们会看到一个关于如何匹配两张图像特征的,简单的例子。在这个例子中,我有一个搜索图像和一个训练图像。我会尝试使用特征匹配从训练图像中找出搜索图像。( 图像是 /samples/c/box.png 和 /samples/c/box_in_scene.png)

(译者附,这个原图在官网的samples上已经找不到了,我帮你们把图偷过来了。)

我们使用 ORB 描述符来匹配特征。让我们从加载图像开始,找出描述符等等。

import numpy as np
import cv2 as cv
import matplotlib.pyplot as plt
img1 = cv.imread('box.png',0)          # queryImage
img2 = cv.imread('box_in_scene.png',0) # trainImage
# Initiate ORB detector
orb = cv.ORB_create()
# find the keypoints and descriptors with ORB
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

接下来,我们创建一个蛮力匹配符对象使用 cv.NORM_HAMMING 汉明距离匹配方式。(因为我们使用的算法是ORB) 并且把 crossCheck 参数开启来获取更好的结果。然后我们使用 Matcher.match() 方法来获取两张图像之间的最佳匹配。我们按升序来排列它们,这样最佳的匹配(也就是距离最近的匹配)就排到了前面。然后我们只画出前10个最佳匹配。(只是处于可见性的考虑。你可以按你的喜欢来增加这个数值。)

# create BFMatcher object
bf = cv.BFMatcher(cv.NORM_HAMMING, crossCheck=True)
# Match descriptors.
matches = bf.match(des1,des2)
# Sort them in the order of their distance.
matches = sorted(matches, key = lambda x:x.distance)
# Draw first 10 matches.
img3 = cv.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2)
plt.imshow(img3),plt.show()

我得到了如下结果:

matcher_result1.jpg

这个匹配器对象是什么?

这一段代码 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
from matplotlib import pyplot as plt
img1 = cv.imread('box.png',0)          # queryImage
img2 = cv.imread('box_in_scene.png',0) # trainImage
# Initiate SIFT detector
sift = cv.SIFT()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# BFMatcher with default params
bf = cv.BFMatcher()
matches = bf.knnMatch(des1,des2, k=2)
# Apply ratio test
good = []
for m,n in matches:
    if m.distance < 0.75*n.distance:
        good.append([m])
# cv.drawMatchesKnn expects list of lists as matches.
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2)
plt.imshow(img3),plt.show()

看下面的结果:

matcher_result2.jpg

基于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(checks=100)。

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

import numpy as np
import cv2 as cv
from matplotlib import pyplot as plt
img1 = cv.imread('box.png',0)          # queryImage
img2 = cv.imread('box_in_scene.png',0) # trainImage
# Initiate SIFT detector
sift = cv.SIFT()
# find the keypoints and descriptors with SIFT
kp1, des1 = sift.detectAndCompute(img1,None)
kp2, des2 = sift.detectAndCompute(img2,None)
# FLANN parameters
FLANN_INDEX_KDTREE = 1
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)   # or pass empty dictionary
flann = cv.FlannBasedMatcher(index_params,search_params)
matches = flann.knnMatch(des1,des2,k=2)
# Need to draw only good matches, so create a mask
matchesMask = [[0,0] for i in xrange(len(matches))]
# ratio test as per Lowe's paper
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 = 0)
img3 = cv.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)
plt.imshow(img3,),plt.show()

看下面的结果:

matcher_flann.jpg

额外资源

练习


上篇:【翻译:OpenCV-Python教程】更快速且支持旋转的BRIEF算法

下篇:【翻译:OpenCV-Python教程】特征匹配加单应性找出物体

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
根据提供的引用内容,cv2.error是OpenCV库中的一个错误类型。在引用中,报错信息是"OpenCV(4.8.0) D:\a\opencv-python\opencv-python\opencv\modules\core\src\alloc.cpp:73: error: (-4:Insufficient memory)",意味着内存不足。而在引用中,报错信息是"OpenCV(4.8.0) D:\a\opencv-python\opencv-2:Unspecified error) The function is not implemented. Rebuild the library with Windows, GTK+ 2.x or Cocoa support. If you are on Ubuntu or Debian, install libgtk2.0-dev and pkg-config, then re-run cmake or configure script in function 'cvShowImage'",意味着函数未实现或缺少相关支持库。 这些错误通常是由于OpenCV库的版本不匹配或者缺少相关依赖库引起的。解决这些错误的方法如下: 1. 内存不足错误: - 检查系统内存使用情况,确保有足够的可用内存。 - 如果内存不足,可以尝试释放一些内存或者增加系统内存。 - 如果问题仍然存在,可以尝试降低图像或数据的分辨率,以减少内存使用量。 2. 函数未实现或缺少支持库错误: - 确认OpenCV库的版本是否与代码兼容。如果版本不匹配,可以尝试升级或降级OpenCV库。 - 检查是否缺少相关的支持库。根据错误信息中提到的支持库,可以尝试安装libgtk2.0-dev和pkg-config等库,并重新运行cmake或配置脚本。 请注意,具体的解决方法可能因具体情况而异。建议根据错误信息中提供的详细信息和您的系统环境进行进一步调查和尝试。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值