在OpenCV里使用特征匹配

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。
本文链接: https://blog.csdn.net/caimouse/article/details/102683479

特征匹配(Feature Matching)

前面我们花费了大量时间来学习特征检测和描述,其实主要的目的就是为了图像是否匹配的问题。在OpenCV里提供了两个匹配技术:Brute-Force和FLANN。

 

Brute-Force匹配算法是比较简单的,它首先从一个特征集合里取一个特征与另外一个特征集合里每个特征进行比较,如果发现最接近的特征就返回。要使用BF匹配,得用cv.BFMatcher()函数创建BFMatcher对象,创建对象时有两个可选的参数,第一个是normType,指明了怎么样度量距离,默认是cv.NORM_L2,比较适合SIFT和SURF等算法。对于二值字符串的算法ORB、BRIEF、BRISK等,应该使用 cv.NORM_HAMMING,使用Hamming距离来度量。如果ORB算法中WTA_K == 3 或 4,这是要使用 cv.NORM_HAMMING2参数。

 

第二个参数是布尔变量,crossCheck ,默认值是false。如果设置为true时,匹配成功时返回值value(i,j)表示A中第i个特征与B中第j个特征匹配。也就是说,两个集合中的两个特性应该相互匹配。它提供了一致的结果,是d.lowe在sift论文中提出的比率测试的一个很好的替代品。

 

当创建成功之后,就可以使用BFMatcher.match() 和 BFMatcher.knnMatch()函数来返回比较值,第一个函数返回最佳匹配结果,第二个函数返回前k个最好匹配结果。可以使用 cv.drawKeypoints()来显示关键点,cv.drawMatches()来显示匹配点,它是把两个图片水平放在一起,然后从一幅图像画到另一幅图像。有时候也使用cv.drawMatchesKnn 来画k个匹配结果。如果k=2,就是画两条直线。

可以用例子演示如下:

#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt

#读取文件
img1 = cv2.imread('szcen1.png')
img2 = cv2.imread('szcen2.png')

#初始化ORB检测器
orb = cv2.ORB_create()

#用ORB查找关键点
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

#创建BFMatcher对象
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)

#匹配描述
matches = bf.match(des1,des2)

#根据距排序
matches = sorted(matches, key = lambda x:x.distance)

# 画前10个匹配结果
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10],None,
                       flags=cv2.DrawMatchesFlags_NOT_DRAW_SINGLE_POINTS)

#显示图片
cv2.imshow('img3',img3)
           
cv2.waitKey(0)
cv2.destroyAllWindows()

结果输出如下:

在例子里把一幅图像里抽取一部分出来,并且旋转90度后,再进行比较,可以得到相同匹配的结果。在这行代码matches = bf.match(des1,des2)里返回比较对象matches,它具有以下属性:

DMatch.distance - 距离描述,越低越好。

DMatch.trainIdx - 训练描述符的索引

DMatch.queryIdx - 查询描述符的索引

DMatch.imgIdx - 训练图像的索引

 

二者的区别在于BFMatcher总是尝试所有可能的匹配,从而使得它总能够找到最佳匹配,这也是Brute Force(暴力法)的原始含义。而FlannBasedMatcher中FLANN的含义是Fast Library forApproximate Nearest Neighbors,从字面意思可知它是一种近似法,算法更快但是找到的是最近邻近似匹配,所以当我们需要找到一个相对好的匹配但是不需要最佳匹配的时候往往使用FlannBasedMatcher。当然也可以通过调整FlannBasedMatcher的参数来提高匹配的精度或者提高算法速度,但是相应地算法速度或者算法精度会受到影响。

为了使用FLANN的匹配功能,需要传送两个字典参数,第一个是ndexParams,主要是选择不同的算法。第二个是SearchParams,说明有多少倍数量的树索引进行递归。

例子进行演示如下:

#python 3.7.4,opencv4.1
#蔡军生 https://blog.csdn.net/caimouse/article/details/51749579
#
import numpy as np
import cv2
from matplotlib import pyplot as plt

#读取文件
img1 = cv2.imread('szcen1.png')
img2 = cv2.imread('szcen2.png')

#初始化ORB检测器
orb = cv2.ORB_create()

#用ORB查找关键点
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)

# FLANN参数
FLANN_INDEX_LSH = 6
index_params = dict(algorithm = FLANN_INDEX_LSH,
                    table_number = 6, 
                    key_size = 12,     
                    multi_probe_level = 1)
search_params = dict(checks=50)   #或者使用一个空的字典
flann = cv2.FlannBasedMatcher(index_params,search_params)

matches = flann.knnMatch(des1,des2,k=2)

#只显示最佳匹配的内容
matchesMask = [[0,0] for i in range(len(matches))]

# 比率
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 = cv2.DrawMatchesFlags_DEFAULT)

img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)

#显示图片
cv2.imshow('img3',img3)
           
cv2.waitKey(0)
cv2.destroyAllWindows()

结果输出如下:

https://blog.csdn.net/caimouse/article/details/51749579

猜你喜欢

转载自blog.csdn.net/caimouse/article/details/102683479