计算机系统应用教程网站

网站首页 > 技术文章 正文

openCV - 图像特征匹配

btikc 2024-09-04 03:20:46 技术文章 42 ℃ 0 评论

目标

本章节中

  • 我们将实现如何不同图像之间匹配特征.
  • 将使用两种匹配器,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 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)

接下来,我们创建一个带有距离测量的BFMatcher对象。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()

以下就是我们得到的结果:



什么是匹配器对象?

代码行中 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 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()

以下得到结果:

基于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
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()

请看结果如下:



Tags:

本文暂时没有评论,来添加一个吧(●'◡'●)

欢迎 发表评论:

最近发表
标签列表