Advertisement

opencv4 图像特征匹配_openCV - 图像特征匹配

阅读量:

目标

本章节中

  • 我们将实现如何不同图像之间匹配特征.
  • 将使用两种匹配器,openCV提供了Brute-Force 和 FLANN

Brute-Force 匹配器的基本原理

Brute-Force匹配器很简单。它采用第一个集合中一个特征的描述符,并通过距离计算与第二个集合中的所有其他特征匹配,返回最近的一个。对于BF匹配器,首先必须使用cv.BFMatcher()创建BFMatcher对象。它需要两个可选参数。第一个是normType。它指定要使用的距离度量。默认情况下,它是cv.NORM_L2。适用于SIFT、SURF等。cv.NORM_L1也在那里)。对于基于二进制字符串的描述符,如ORB、BRIEF、lively等,使用cv.NORM_HAMMING,它使用Hamming distance作为度量。如果ORB使用WTA_K == 3或4,则使用cv.NORM_HAMMING2。

第二个参数是布尔变量crossCheck,默认为false。如果为真,Matcher只返回值为(i,j)的匹配项,以便集合A中的第i个描述符与集合B中的第j个描述符具有最佳匹配,反之亦然。也就是说,两个集合中的两个特性应该相互匹配。它可以得到可靠的结果,是D.Lowe的论文中提出的一个比值检验很好的替代法。创建之后,两个重要的方法是BFMatcher.match()和BFMatcher.knnMatch()。第一个返回最佳匹配。第二个方法返回由用户指定的k的最佳匹配。当我们需要在这方面做额外的工作时,它可能是有用的。

就像我们使用了cv.drawKeypoints()来绘制关键点一样,cv.drawMatches()帮助我们绘制匹配项。它水平地堆叠两个图像,并从第一个图像到第二个图像绘制线,以显示最佳匹配。还有cv.drawMatchesKnn可以画出所有k个最佳匹配项。如果k=2,它将为每个关键点绘制两条匹配线。所以我们必须传递一个蒙版如果我们想有选择地画它。让我们来分别看看用SURF和ORB的示例 (它们都使用不同的距离测量)。

BF 匹配 ORB 描述子

在这里,我们将看到一个关于如何在两个图像之间匹配特性的简单示例。在本例中,我有一个queryImage和一个trainImage。我们将尝试使用特征匹配在trainImage中找到queryImage。

( 实例图像 /samples/c/box.png and /samples/c/box_in_scene.png)

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

复制代码
    import numpy as npimport cv2 as cvimport matplotlib.pyplot as pltimg1 = cv.imread('box.png',0) # queryImageimg2 = cv.imread('box_in_scene.png',0) # trainImage# Initiate ORB detectororb = cv.ORB_create()# find the keypoints and descriptors with ORBkp1, des1 = orb.detectAndCompute(img1,None)kp2, des2 = orb.detectAndCompute(img2,None)

接下来,我们创建一个带有距离测量的BFMatcher对象。cv.NORM_HAMMING(因为我们使用ORB)和crossCheck被打开以获得更好的结果。然后我们使用Matcher.match()方法在两个图像中获得最佳匹配。我们按照它们之间距离的升序对它们进行排序,以便最好的匹配(低距离)出现在前面。然后我们只绘制前10个匹配项(只是为了便于查看)。你可以随意增加)

复制代码
    # create BFMatcher objectbf = 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()

以下就是我们得到的结果:
1c26b883e4a0c9d825c7bc8d033626ad.png

什么是匹配器对象?

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

  • DMatch.distance - 描述子之间的距离. 越小越好.
  • DMatch.trainIdx - 训练集中的描述子的索引
  • DMatch.queryIdx - 检索集中的描述子的索引
  • DMatch.imgIdx - 训练集图像的索引.

BF 匹配 SIFT 描述子和比值检测

这次,我们将使用BFMatcher.knnMatch()获得k个最佳匹配。在这个例子中,我们取k=2,这样我们就可以应用D.Lowe在论文中解释的比值检验。

复制代码
    import numpy as npimport cv2 as cvfrom matplotlib import pyplot as pltimg1 = cv.imread('box.png',0) # queryImageimg2 = cv.imread('box_in_scene.png',0) # trainImage# Initiate SIFT detectorsift = cv.SIFT()# find the keypoints and descriptors with SIFTkp1, des1 = sift.detectAndCompute(img1,None)kp2, des2 = sift.detectAndCompute(img2,None)# BFMatcher with default paramsbf = cv.BFMatcher()matches = bf.knnMatch(des1,des2, k=2)# Apply ratio testgood = []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()

以下得到结果:
72232ee4f31d941bab94794747db42fa.png

基于FLANN 匹配器

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

对于基于FLANN的匹配器,我们需要通过两个字典来指定要使用的算法及其相关参数等。第一个是IndexParams。对于各种算法,要传递的信息在FLANN文档中进行了解释。作为总结,对于SIFT、SURF等算法,您可以通过以下步骤:

复制代码
    FLANN_INDEX_KDTREE = 1index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)

在使用ORB时,您可以传递以下内容。注释值是根据文档推荐的,但在某些情况下它没有提供所需的结果。其他的值可能会更好:

复制代码
    FLANN_INDEX_LSH = 6index_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 npimport cv2 as cvfrom matplotlib import pyplot as pltimg1 = cv.imread('box.png',0) # queryImageimg2 = cv.imread('box_in_scene.png',0) # trainImage# Initiate SIFT detectorsift = cv.SIFT()# find the keypoints and descriptors with SIFTkp1, des1 = sift.detectAndCompute(img1,None)kp2, des2 = sift.detectAndCompute(img2,None)# FLANN parametersFLANN_INDEX_KDTREE = 1index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)search_params = dict(checks=50) # or pass empty dictionaryflann = cv.FlannBasedMatcher(index_params,search_params)matches = flann.knnMatch(des1,des2,k=2)# Need to draw only good matches, so create a maskmatchesMask = [[0,0] for i in xrange(len(matches))]# ratio test as per Lowe's paperfor 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()

请看结果如下:
b77bf90a9cbc35b3aeb8bf73ce2c8207.png

全部评论 (0)

还没有任何评论哟~