内容来自OpenCV-Python Tutorials 自己翻译整理
目标:
学习匹配一副图片和其他图片的特征。
学习使用OpenCV中的Brute-Force匹配和FLANN匹配。
暴力匹配(Brute-Force)基础
暴力匹配很简单。首先在模板特征点描述符的集合当中找到第一个特征点,然后匹配目标图片的特征点描述符集合当中的所有特征点,匹配方式使用“距离”来衡量,返回“距离”最近的那个。
对于Brute-Force匹配,首先我们要使用cv2.BFMatcher()方法来创建一个BF匹配器的对象。
该方法包含两个可选参数
normType
crossCheck
normType指定了要使用的“距离”测量方法。缺省条件下,的参数是cv2.NORM_L2。
在使用SIFT方法和SURF方法等等进行匹配时,这种“距离”测量方法效果很好(cv2.NORM_L1也一样)。
在使用基于二进制字符串的描述符,像ORB,BRIEF,BRISK等等方法时,应该使用cv2.NORM_HAMMING,这种方法使用汉明距离来测量。如果ORB算法的参数设置为WAT_K==3或者4,那么应该使用cv2.NORM_HAMMING2。
crossCheck参数是boolean类型,缺省的情况下是false。如果crossCheck是true,那么匹配器返回只返回一个最佳的匹配(i,j),其中i在特征点描述符集合A当中,j在特征点描述符集合B当中,反之亦然。也就是两个集合当中的特征点都彼此配对。这种方法返回了一致的结果,并且可以很好的用来替代SIFT算法论文当中测试。
暴力匹配器有两个重要的方法,分别是BFMatcher.match() 和BFMatcher.knnMatch()。第一个返回最佳匹配,第二个返回前k个最佳的匹配,k值由用户指定。当我们需要做一些额外的工作时,这种方法会很有用。
就像在图像上绘制关键点的函数cv2.drawKeypoints()一样, cv2.drawMatches()函数可以绘制匹配结果。该方法将两张图片水平排列,然后从第一张图片到第二张图片绘制直线来现实最佳的匹配结果。cv2.drawMatchesKnn函数会画出所有k个最佳匹配。如果k=2,那么将会画出每个关键点之间的匹配直线。所以,如果我们想有选择的画出,那么要传递进一个蒙版。
下面的例子使用了SURF和ORB算法(分别使用了不同的“距离”测量方法)
ORB的暴力匹配:
下面的例子实现了匹配两个图片的特征点,本例子当中要去查询图片和训练图片。我们要在训练图片当中使用特征匹配来找到查询图片。
使用ORB描述符来匹配特征(文档里写成SIFT算法了)。
import numpy as np
import cv2
from matplotlib import pyplot as plt
img1 = cv2.imread('1.jpg',0)
img2 = cv2.imread('26.jpg',0)
orb = cv2.ORB_create()
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)
bf = cv2.BFMatcher(cv2.NORM_HAMMING, crossCheck=True)
matches = bf.match(des1,des2)
matches = sorted(matches, key = lambda x:x.distance)
img3=np.empty((300,300))
img3 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], img3,flags=2)
plt.imshow(img3),plt.show()
原图
原来凤姐最美的是眼睛,不是嘴啊-_-||| drawMatches函数的参数如下
outImg = cv.drawMatches( img1, keypoints1, img2, keypoints2, matches1to2, outImg[, matchColor[, singlePointColor[, matchesMask[, flags]]]] ) - img1 第一张图片
- keypoints1第一张图片的关键点
- img2第二张图片
- keypoints2第二章图片的关键点
- matches1to2 选择第一张图到第二张图的多少个匹配点
- outImg 输出图片
- matchColor 匹配点颜色
- singlePointColor 画出没匹配上的点
- matchesMask 给出一个蒙版,表示那部分的匹配点不用画出来
- flags DEFAULT = 0, DRAW_OVER_OUTIMG = 1, NOT_DRAW_SINGLE_POINTS = 2, DRAW_RICH_KEYPOINTS = 4
什么事匹配器对象? matches = bf.match(des1,des2)结果返回一个列表,DMatch 有如下性质 - DMatch.distance 描述符的“距离”,越小越好
- DMatch.trainIdx 目标描述符的下标
- DMatch.queryIdx 查询图像描述符的下标
- DMatch.imgIdx 目标图像的下标
SIFT暴力匹配和比率测试 这次试用BFMatcher.knnMatch()来找到k个最佳匹配。在这个例子当中,我们选择k=2,这样可以使用Lowe论文中的比率测试了。 import numpy as np import cv2 from matplotlib import pyplot as plt
img1 = cv2.imread('1.jpg',0) img2 = cv2.imread('26.jpg',0)
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1,None) kp2, des2 = sift.detectAndCompute(img2,None)
bf = cv2.BFMatcher()
matches = bf.knnMatch(des1,des2,k=2)
good = [] for m,n in matches: if m.distance < 0.75*n.distance: good.append([m])
img3=np.empty((300,300))
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good, img3,flags=2)
plt.imshow(img3),plt.show() 不咋准…-_- 基于FLANN的匹配器 FLANN的意思是快速最近邻搜索库。它包含一个对大数据集合和高维特征实现最近邻搜索的算法集合,而且这些算法是优化固偶读。面对大数据集时,效果要比暴力搜索好。 FLANN要传递两个字典作为参数。
第一个参数是使用的搜索算法,详细内容见此处
第二个参数是搜索次数,次数越多,结果越精确,但是速度也越慢。 mport numpy as np import cv2 from matplotlib import pyplot as plt
img1 = cv2.imread('1.jpg',0) img2 = cv2.imread('26.jpg',0)
sift = cv2.xfeatures2d.SIFT_create()
kp1, des1 = sift.detectAndCompute(img1,None) kp2, des2 = sift.detectAndCompute(img2,None)
FLANN_INDEX_KDTREE = 0#kd树 index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) search_params = dict(checks=50) # or pass empty dictionary
flann = cv2.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 range(len(matches))]
# ratio test as per Lowe's paper for i,(m,n) in enumerate(matches): if m.distance < 0.7*n.distance: matchesMask=[1,0]
draw_params = dict(matchColor = (0,255,0), singlePointColor = (255,0,0), matchesMask = matchesMask, flags = 0)
img3=np.empty((300,300))
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches, img3,flags=2)
plt.imshow(img3),plt.show() 效果没有ORB算法实现的好呀
|