Brute-Force匹配器基礎(chǔ)
Brute-Force匹配器很簡單歌憨,它取第一個(gè)集合里一個(gè)特征的描述子并用第二個(gè)集合里所有其他的特征和他通過一些距離計(jì)算進(jìn)行匹配。最近的返回。
對于BF匹配器惠险,首先我們得用cv2.BFMatcher()創(chuàng)建BF匹配器對象.它取兩個(gè)可選參數(shù)呜达,第一個(gè)是normType唆貌。它指定要使用的距離量度滑潘。默認(rèn)是cv2.NORM_L2。對于SIFT,SURF很好锨咙。(還有cv2.NORM_L1)众羡。對于二進(jìn)制字符串的描述子,比如ORB蓖租,BRIEF粱侣,BRISK等,應(yīng)該用cv2.NORM_HAMMING蓖宦。使用Hamming距離度量齐婴,如果ORB使用VTA_K == 3或者4,應(yīng)該用cv2.NORM_HAMMING2
第二個(gè)參數(shù)是布爾變量稠茂,crossCheck模式是false柠偶,如果它是true,匹配器返回那些和(i, j)匹配的睬关,這樣集合A里的第i個(gè)描述子和集合B里的第j個(gè)描述子最匹配诱担。兩個(gè)集合里的兩個(gè)特征應(yīng)該互相匹配,它提供了連續(xù)的結(jié)果电爹,
當(dāng)它創(chuàng)建以后蔫仙,兩個(gè)重要的方法是BFMatcher.match()和BFMatcher.knnMatch()。第一個(gè)返回最匹配的丐箩,第二個(gè)方法返回k個(gè)最匹配的摇邦,k由用戶指定。當(dāng)我們需要多個(gè)的時(shí)候很有用屎勘。
想我們用cv2.drawKeypoints()來畫關(guān)鍵點(diǎn)一樣施籍,cv2.drawMatches()幫我們畫匹配的結(jié)果,它把兩個(gè)圖像水平堆疊并且從第一個(gè)圖像畫線到第二個(gè)圖像來顯示匹配概漱。還有一個(gè)cv2.drawMatchesKnn來畫k個(gè)最匹配的丑慎。如果k=2,它會給每個(gè)關(guān)鍵點(diǎn)畫兩根匹配線瓤摧。所以我們得傳一個(gè)掩圖竿裂,如果我們想選擇性的畫的話。
讓我們各看一個(gè)SURF和ORB的例子(都使用了不同的距離度量)
使用ORB描述子的Brute-Force匹配
這里我們會看到如何匹配兩個(gè)圖片的里的特征姻灶。在這個(gè)例子里铛绰,我有一個(gè)查詢圖像和一個(gè)訓(xùn)練圖像诈茧,我們用特征匹配來在訓(xùn)練圖像里找查詢圖像产喉。
我們使用SIFT描述子來匹配特征,所以讓我們先加載圖像,找到描述子曾沈。
import numpy as np
import cv2
from matplotlib import pyplot as pltimg1 = cv2.imread('box.png',0)? ? ? ? ? # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage# Initiate SIFT detector
orb = cv2.ORB()# find the keypoints and descriptors with SIFT
kp1, des1 = orb.detectAndCompute(img1,None)
kp2, des2 = orb.detectAndCompute(img2,None)
接著我們用距離度量cv2.NORM_HAMMING創(chuàng)建一個(gè)BFMatcher對象这嚣,crossCheck設(shè)為真。然后我們用Matcher.match()方法來獲得兩個(gè)圖像里最匹配的塞俱。我們按他們距離升序排列姐帚,這樣最匹配的(距離最小)在最前面障涯。然后我們畫出最開始的10個(gè)匹配(為了好看罐旗,你可以增加)
# create BFMatcher object
bf = cv2.BFMatcher(cv2.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 = cv2.drawMatches(img1,kp1,img2,kp2,matches[:10], flags=2)plt.imshow(img3),plt.show()
下面是結(jié)果:
什么是匹配器對象?
matches = bf.match(des1, des2)的結(jié)果是DMatch對象列表唯蝶。這個(gè)DMatch對象有下面的屬性:
·DMatch.distance - 描述子之間的距離九秀。越低越好
·DMatch.trainIdx - 訓(xùn)練描述子里的描述子索引
·DMatch.queryIdx - 查詢描述子里的描述子索引
·DMatch.imgIdx - 訓(xùn)練圖像的索引
用SIFT描述子和比率測試的Brute-Force 匹配
這次,我們使用BFMatcher.knnMatch()來獲得k個(gè)最匹配的粘我。在這個(gè)例子里鼓蜒,我們設(shè)置k=2這樣我們可以應(yīng)用比率檢測。
import numpy as np
import cv2
from matplotlib import pyplot as pltimg1 = cv2.imread('box.png',0)? ? ? ? ? # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage# Initiate SIFT detector
sift = cv2.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 = cv2.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])# cv2.drawMatchesKnn expects list of lists as matches.
img3 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,good,flags=2)plt.imshow(img3),plt.show()
看下面的結(jié)果
基于FLANN的匹配器
FLANN是快速估計(jì)最近鄰的庫征字。它包含了一些為大數(shù)據(jù)集內(nèi)搜索快速近鄰和高維特征的優(yōu)化算法都弹。它在大數(shù)據(jù)集的時(shí)候比BFMatcher更快。
對于基于FLANN的匹配器匙姜,我們需要傳兩個(gè)字典指定要用的算法畅厢,他們相關(guān)的參數(shù)等。第一個(gè)是IndexParams氮昧。對于更多算法或详,要傳的信息參看FLANN的文檔。作為總結(jié)郭计,對于像SIFT霸琴,SURF等的算法,你可以傳下面的:
index_params=dict(algorithm=FLANN_INDEX_KDTREE,trees=5)
當(dāng)使用ORB昭伸,你可以傳下面的梧乘。注釋里的值是推薦的值。但是在有些情況下不提供需要的結(jié)果庐杨。其他的值工作正常选调。
index_params = dict(algorithm=FLANN_INDEX_LSH,
? ? table_number = 6, ?# 12
? ? key_size = 12, ? ?# 20
? ? multi_probe_level = 1) ?#2
第二個(gè)字典是SearchParams,它指定了索引里的樹應(yīng)該被遞歸遍歷的次數(shù)灵份。更高的值帶來更高的準(zhǔn)確率仁堪。但是也花更多時(shí)間,如果你想改變值填渠,search_params = dict(checks=100).
通過這些信息弦聂,我們可以開始了:
import numpy as np
import cv2
from matplotlib import pyplot as pltimg1 = cv2.imread('box.png',0)? ? ? ? ? # queryImage
img2 = cv2.imread('box_in_scene.png',0) # trainImage# Initiate SIFT detector
sift = cv2.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 = 0
index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5)
search_params = dict(checks=50)? # or pass empty dictionaryflann = 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 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 = cv2.drawMatchesKnn(img1,kp1,img2,kp2,matches,None,**draw_params)
plt.imshow(img3,),plt.show()
結(jié)果:
END