【图像处理】——特征匹配(SIFT特征检测器+FLANN特征匹配方法+KNN近邻最优匹配筛选)——cv.xfeatures2d.SIFT_create()sift.detectAndCompute
轉(zhuǎn)載請(qǐng)注明地址
目錄
1、特征檢測(cè)和特征匹配方法
(1)特征檢測(cè)算法
(2)特征匹配算法
(3)各種特征檢測(cè)算法的比較
2、特征匹配的基本步驟(附帶主要的函數(shù))
(1)圖像預(yù)處理——灰度化(模板——查詢集queryImg,待匹配圖像——訓(xùn)練集trainingImg)
(2)創(chuàng)建特征檢測(cè)器——用于檢測(cè)模板和圖像上的特征點(diǎn)
(3)利用上述特征檢測(cè)器獲得特征點(diǎn)和特征描述符
特征點(diǎn)的解釋:
特征描述符的解釋:
(4)創(chuàng)建特征匹配器——用于對(duì)模板和待匹配圖像間進(jìn)行特征點(diǎn)之間的匹配
匹配的一般思路:
(5)選取優(yōu)良的匹配點(diǎn)——Lowe's算法+KNN近鄰算法
(6)繪制匹配對(duì)間的匹配線
3、Python代碼實(shí)現(xiàn)和主要函數(shù)分析
(1)導(dǎo)入包
(2)kps,des = sift.detectAndCompute(IMg, None)函數(shù)
參數(shù)
返回值
(3)cv.FlannBasedMatcher(indexParams,searchParams)
(4)matches=flann.knnMatch(queryDescriptors, trainDescriptors, k, mask=None, compactResult=None)
參數(shù):
返回值:
matches含有三個(gè)屬性:queryIdx,trainIdx,distance(特征點(diǎn)描述符的歐式距離)
(5)drawMatchesKnn(img1, keypoints1, img2, keypoints2,**drawparams)
參數(shù):
問題1:怎么提取出kps中關(guān)鍵點(diǎn)的坐標(biāo)?
問題2:matches的shape是怎樣的?
問題3:opencv中match與KnnMatch的區(qū)別
4、其他函數(shù)
(1)cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
(2)dst = cv2.perspectiveTransform(pts, M)
5、OpenCV仿射變換、投影變換的重要函數(shù)
Q&A:
6、實(shí)際代碼
(1)KNNMATCH+DRAWKNNMATCH+LOWE'S TEST
(2)match+drawmatch
?
????? 看了很多文章,比較雜亂,打算自己整理一下1特征匹配這方面的知識(shí),主要思路是先拋出一個(gè)例子和代碼,然后對(duì)代碼逐步解析,和對(duì)關(guān)鍵代碼的參數(shù)以及返回值作解析
1、特征檢測(cè)和特征匹配方法
參考:
https://blog.csdn.net/m0_37598482/article/details/78846215
https://www.jianshu.com/p/14b92d3fd6f8
一幅圖像中總存在著其獨(dú)特的像素點(diǎn),這些點(diǎn)我們可以認(rèn)為就是這幅圖像的特征,成為特征點(diǎn)。計(jì)算機(jī)視覺領(lǐng)域中的很重要的圖像特征匹配就是一特征點(diǎn)為基礎(chǔ)而進(jìn)行的,所以,如何定義和找出一幅圖像中的特征點(diǎn)就非常重要。這篇文章我總結(jié)了視覺領(lǐng)域最常用的幾種特征點(diǎn)以及特征匹配的方法。
在計(jì)算機(jī)視覺領(lǐng)域,興趣點(diǎn)(也稱關(guān)鍵點(diǎn)或特征點(diǎn))的概念已經(jīng)得到了廣泛的應(yīng)用, 包括目標(biāo)識(shí)別、 圖像配準(zhǔn)、 視覺跟蹤、 三維重建等。 這個(gè)概念的原理是, 從圖像中選取某些特征點(diǎn)并對(duì)圖像進(jìn)行局部分析,而非觀察整幅圖像。 只要圖像中有足夠多可檢測(cè)的興趣點(diǎn),并且這些興趣點(diǎn)各不相同且特征穩(wěn)定, 能被精確地定位,上述方法就十分有效。
(1)特征檢測(cè)算法
- Harris:該算法用于檢測(cè)角點(diǎn);
- SIFT:該算法用于檢測(cè)斑點(diǎn);https://blog.csdn.net/qq_40369926/article/details/88597406
- SURF:該算法用于檢測(cè)角點(diǎn);
- FAST:該算法用于檢測(cè)角點(diǎn);
- BRIEF:該算法用于檢測(cè)斑點(diǎn);
- ORB:該算法代表帶方向的FAST算法與具有旋轉(zhuǎn)不變性的BRIEF算法;
(2)特征匹配算法
- 暴力(Brute-Force)匹配法;
- 基于FLANN匹配法;
- 可以采用單應(yīng)性進(jìn)行空間驗(yàn)證。
(3)各種特征檢測(cè)算法的比較
參考:https://www.cnblogs.com/jsxyhelu/p/7834416.html
- 計(jì)算速度: ORB>>SURF>>SIFT(各差一個(gè)量級(jí))
- 旋轉(zhuǎn)魯棒性: SURF>ORB~SIFT(表示差不多)
- 模糊魯棒性: SURF>ORB~SIFT
- 尺度變換魯棒性: SURF>SIFT>ORB(ORB并不具備尺度變換性)
2、特征匹配的基本步驟(附帶主要的函數(shù))
https://blog.csdn.net/qq_41007606/article/details/81875193
(1)圖像預(yù)處理——灰度化(模板——查詢集queryImg,待匹配圖像——訓(xùn)練集trainingImg)
#1、#讀取要匹配的灰度照片 queryImage=cv.imread("b2_ROI_Template3.jpg",0) trainingImage=cv.imread("b2_target.jpg",0)(2)創(chuàng)建特征檢測(cè)器——用于檢測(cè)模板和圖像上的特征點(diǎn)
sift=cv.xfeatures2d.SIFT_create()(3)利用上述特征檢測(cè)器獲得特征點(diǎn)和特征描述符
kp1, des1 = sift.detectAndCompute(queryImage,None) kp2, des2 = sift.detectAndCompute(trainingImage,None)特征點(diǎn)的解釋:
??????? 具體的概念根據(jù)不同的特征檢測(cè)算法而異,如果要看確切的關(guān)鍵點(diǎn)的概念,可以深入到每一種特征檢測(cè)算法當(dāng)中去
??????? 如FAST特征檢測(cè)算法的定義是:
??????? 跟Harris檢測(cè)器的情況一樣, FAST算法源于對(duì)構(gòu)成角點(diǎn)的定義。FAST對(duì)角點(diǎn)的定義基于候選特征點(diǎn)周圍的圖像強(qiáng)度值。 以某個(gè)點(diǎn)為中心作一個(gè)圓, 根據(jù)圓上的像素值判斷該點(diǎn)是否為關(guān)鍵點(diǎn)。 如果存在這樣一段圓弧, 它的連續(xù)長(zhǎng)度超過周長(zhǎng)的3/4, 并且它上面所有像素的強(qiáng)度值都與圓心的強(qiáng)度值明顯不同(全部更黑或更亮) , 那么就認(rèn)定這是一個(gè)關(guān)鍵點(diǎn)。
??????? 關(guān)鍵點(diǎn)我們可以理解為可以用來代表一個(gè)物體的特征的點(diǎn),如一個(gè)長(zhǎng)方體,特征點(diǎn)就是8個(gè)點(diǎn),就能夠說明他的大小和形狀了
特征描述符的解釋:
https://blog.csdn.net/shiyongraow/article/details/78347234
???????? 是一種算法和方法,輸入1個(gè)圖像,返回多個(gè)特征向量(主要用來處理圖像的局部,往往會(huì)把多個(gè)特征向量組成一個(gè)一維的向量)。主要用于圖像匹配(視覺檢測(cè)),匹配圖像中的物品。
???????? 通俗一點(diǎn)就是通過一種算法對(duì)該特征點(diǎn)一定區(qū)域的灰度值或者說特征進(jìn)行了計(jì)算,將計(jì)算得到的多個(gè)結(jié)果組成一個(gè)一維數(shù)組,而這個(gè)數(shù)組就可以稱之為該點(diǎn)的特征描述符
??????? 還是以長(zhǎng)方體為例:【面積、周長(zhǎng)、最小外接球心、最大內(nèi)接球心...】這一組數(shù)據(jù)就是該長(zhǎng)方體的特征描述符,不同的是,圖像的特征描述符一般具有尺度不變性等,如一個(gè)圖片的HU不變矩組合成了一個(gè)7元素的一維矩陣,也可以作為描述符
Hu不變矩
(4)創(chuàng)建特征匹配器——用于對(duì)模板和待匹配圖像間進(jìn)行特征點(diǎn)之間的匹配
flann=cv.FlannBasedMatcher(indexParams,searchParams)匹配的一般思路:
從模板中取一個(gè)特征點(diǎn),然后在從待匹配圖像中根據(jù)匹配算法(匹配度)尋找最優(yōu)匹配點(diǎn),記錄該匹配點(diǎn)對(duì)。
但是在lowes大神提出了另一種方法來優(yōu)化它,即通過優(yōu)化來選取比較優(yōu)良的匹配點(diǎn)
(5)選取優(yōu)良的匹配點(diǎn)——Lowe's算法+KNN近鄰算法
matches=flann.knnMatch(des1,des2,k=2) for i, (m,n) in enumerate(matches):#返回索引號(hào)和兩個(gè)匹配的信息if m.distance< 0.5*n.distance: #m表示大圖像上最匹配點(diǎn)的距離,n表示次匹配點(diǎn)的距離,若比值小于0.5則舍棄matchesMask[i]=[1,0]?????? 我們需要進(jìn)一步篩選匹配點(diǎn),來獲取優(yōu)秀的匹配點(diǎn),這就是所謂的“去粗取精”。這里我們采用了Lowe’s算法來進(jìn)一步獲取優(yōu)秀匹配點(diǎn)。
??????? 為了排除因?yàn)閳D像遮擋和背景混亂而產(chǎn)生的無匹配關(guān)系的關(guān)鍵點(diǎn),SIFT的作者Lowe提出了比較最近鄰距離與次近鄰距離的SIFT匹配方式:取一幅圖像中的一個(gè)SIFT關(guān)鍵點(diǎn),并找出其與另一幅圖像中歐式距離最近的前兩個(gè)關(guān)鍵點(diǎn),在這兩個(gè)關(guān)鍵點(diǎn)中,如果最近的距離除以次近的距離得到的比率ratio少于某個(gè)閾值T,則接受這一對(duì)匹配點(diǎn)。
??????? 因?yàn)閷?duì)于錯(cuò)誤匹配,由于特征空間的高維性,相似的距離可能有大量其他的錯(cuò)誤匹配,從而它的ratio值比較高。顯然降低這個(gè)比例閾值T,SIFT匹配點(diǎn)數(shù)目會(huì)減少,但更加穩(wěn)定,反之亦然。Lowe推薦ratio的閾值為0.8,但作者對(duì)大量任意存在尺度、旋轉(zhuǎn)和亮度變化的兩幅圖片進(jìn)行匹配,結(jié)果表明ratio取值在0. 4~0. 6 之間最佳,小于0. 4的很少有匹配點(diǎn),大于0. 6的則存在大量錯(cuò)誤匹配點(diǎn),所以建議ratio的取值原則如下:
ratio=0. 4:對(duì)于準(zhǔn)確度要求高的匹配;
ratio=0. 6:對(duì)于匹配點(diǎn)數(shù)目要求比較多的匹配;
ratio=0. 5:一般情況下。
(6)繪制匹配對(duì)間的匹配線
resultimage=cv.drawMatchesKnn(queryImage,kp1,trainingImage,kp2,matches,None,**drawParams)3、Python代碼實(shí)現(xiàn)和主要函數(shù)分析
(1)導(dǎo)入包
import cv2 as cv from matplotlib import pyplot as plt還需要安裝這個(gè)包:pip install opencv-contrib-python==3.4.2.16
(2)kps,des = sift.detectAndCompute(IMg, None)函數(shù)
參數(shù)
img:需要提取特征點(diǎn)的灰度圖
None:照寫即可
返回值
kps:返回的是特征點(diǎn)所包含的信息,是一個(gè)Dmatch數(shù)據(jù)類型
這里的kps就是關(guān)鍵點(diǎn)。它所包含的信息有:
angle:角度,表示關(guān)鍵點(diǎn)的方向,通過Lowe大神的論文可以知道,為了保證方向不變形,SIFT算法通過對(duì)關(guān)鍵點(diǎn)周圍鄰域進(jìn)行梯度運(yùn)算,求得該點(diǎn)方向。-1為初值。
class_id——當(dāng)要對(duì)圖片進(jìn)行分類時(shí),我們可以用class_id對(duì)每個(gè)特征點(diǎn)進(jìn)行區(qū)分,未設(shè)定時(shí)為-1,需要靠自己設(shè)定
octave——代表是從金字塔哪一層提取的得到的數(shù)據(jù)。
pt——關(guān)鍵點(diǎn)點(diǎn)的坐標(biāo)
response——響應(yīng)程度,代表該點(diǎn)強(qiáng)壯大小,更確切的說,是該點(diǎn)角點(diǎn)的程度。
size——該點(diǎn)直徑的大小
des:返回特征點(diǎn)的特征描述符,是一個(gè)一維列表,列表元素為Dmatch類型
(3)cv.FlannBasedMatcher(indexParams,searchParams)
根據(jù)設(shè)置好的參數(shù)返回一個(gè)特征匹配器,參數(shù)是通過字典的方式傳送給函數(shù)的
FLANN_INDEX_KDTREE=0 indexParams=dict(algorithm=FLANN_INDEX_KDTREE,trees=5)#指定匹配的算法和kd樹的層數(shù) searchParams= dict(checks=50)#指定返回的個(gè)數(shù)#4、根據(jù)設(shè)置的參數(shù)創(chuàng)建特征匹配器 flann=cv.FlannBasedMatcher(indexParams,searchParams)(4)matches=flann.knnMatch(queryDescriptors, trainDescriptors, k, mask=None, compactResult=None)
參數(shù):
opencv中match與KnnMatch的區(qū)別(看問題3)
queryDescriptors:查詢集的特征描述符,即模板
trainDescriptors:訓(xùn)練集的特征描述符,即待匹配圖像
k:根據(jù)KNN近鄰算法來返回最匹配的前K個(gè)匹配點(diǎn),默認(rèn)為1
返回值:
matches:返回的是最匹配的兩個(gè)特征點(diǎn)的信息,返回的類型是一個(gè)列表,列表元素的類型是Dmatch數(shù)據(jù)類型,每一個(gè)列表元素又是一個(gè)列表,這個(gè)列表元素的個(gè)數(shù)和k一樣,因?yàn)榉庋b的就是匹配前k個(gè)點(diǎn)的信息matches含有三個(gè)屬性:queryIdx,trainIdx,distance(特征點(diǎn)描述符的歐式距離)
參考:https://blog.csdn.net/weixin_44072651/article/details/89262277
queryIdx:測(cè)試圖像的特征點(diǎn)描述符的下標(biāo)(第幾個(gè)特征點(diǎn)描述符),同時(shí)也是描述符對(duì)應(yīng)特征點(diǎn)的下標(biāo)。
trainIdx:樣本圖像的特征點(diǎn)描述符下標(biāo),同時(shí)也是描述符對(duì)應(yīng)特征點(diǎn)的下標(biāo)。
distance:代表這怡翠匹配的特征點(diǎn)描述符的歐式距離,數(shù)值越小也就說明倆個(gè)特征點(diǎn)越相近。
注意:這里的遍歷matches時(shí),需要理解matches一次返回的是幾個(gè)點(diǎn),即k=幾得清楚
bf = cv.BFMatcher_create() matches = bf.match(des1, des2) for matche in matches:print(matche)print(matche.queryIdx)print(matche.trainIdx)print(matche.distance)(5)drawMatchesKnn(img1, keypoints1, img2, keypoints2,**drawparams)
#繪制的參數(shù),匹配連線的顏色,特征點(diǎn)的顏色,需要畫哪些匹配,flags=0繪制點(diǎn)和線,=2不畫特征點(diǎn) drawParams=dict(matchColor=(0,0,255),singlePointColor=(255,0,0),matchesMask=matchesMask,flags=0) #給特征點(diǎn)和匹配的線定義顏色 resultimage=cv.drawMatchesKnn(queryImage,kp1,trainingImage,kp2,matches,None,**drawParams) #畫出匹配的結(jié)果參數(shù):
img1:模板灰度圖像
kp1:模板特征點(diǎn)信息
img2:待匹配灰度圖像
kp2:待匹配圖像特征點(diǎn)信息
**drawparam:繪制特征點(diǎn)匹配時(shí)的參數(shù),用字典的形式傳入,含有matchColor、singlePointColor、matchesMask、flags=0等參數(shù),其中matchColor表示匹配連線顏色,singlePointColor表示特征點(diǎn)顏色,matchesMask表示畫哪些匹配,flags=0表示畫特征點(diǎn)和連線,flags=2表示不畫特征點(diǎn)
問題1:怎么提取出kps中關(guān)鍵點(diǎn)的坐標(biāo)?
答:通過特征描述符的索引下表和特征點(diǎn)的.pt屬性獲取
# 獲取關(guān)鍵點(diǎn)的坐標(biāo)src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)print(src_pts)dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)問題2:matches的shape是怎樣的?
答:假設(shè)取前k個(gè)匹配點(diǎn),查詢機(jī)即模板含有m個(gè)關(guān)鍵點(diǎn),則matches.shape = (1,m,k)
問題3:opencv中match與KnnMatch的區(qū)別
答:區(qū)別主要在于前面一個(gè)返回的是一個(gè)特征點(diǎn)的信息,后面返回的是多個(gè)特征點(diǎn)的信息,即前面的是返回最優(yōu)匹配的點(diǎn),而后面這個(gè)則是返回最優(yōu)和次優(yōu)匹配兩個(gè)點(diǎn)
參考:https://blog.csdn.net/weixin_44072651/article/details/89262277
4、其他函數(shù)
(1)cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)
參考:https://blog.csdn.net/martinkeith/article/details/104995093
https://blog.csdn.net/ei1990/article/details/78338928
計(jì)算多個(gè)二維點(diǎn)對(duì)之間的最優(yōu)單映射變換矩陣 H(3行x3列) ,使用最小均方誤差或者RANSAC方法
(2)dst = cv2.perspectiveTransform(pts, M)
理論參考:https://blog.csdn.net/oppo62258801/article/details/78642218
對(duì)二維或者三維矢量進(jìn)行透射變換,也就是對(duì)輸入二維坐標(biāo)點(diǎn)或者三維坐標(biāo)點(diǎn)進(jìn)行投射變換
5、OpenCV仿射變換、投影變換的重要函數(shù)
estimateRigidTransform():計(jì)算多個(gè)二維點(diǎn)對(duì)或者圖像之間的最優(yōu)仿射變換矩陣 (2行x3列),H可以是部分自由度,比如各向一致的切變。
getAffineTransform():計(jì)算3個(gè)二維點(diǎn)對(duì)之間的仿射變換矩陣H(2行x3列),自由度為6.
warpAffine():對(duì)輸入圖像進(jìn)行仿射變換
findHomography: 計(jì)算多個(gè)二維點(diǎn)對(duì)之間的最優(yōu)單映射變換矩陣 H(3行x3列) ,使用最小均方誤差或者RANSAC方法 。
getPerspectiveTransform():計(jì)算4個(gè)二維點(diǎn)對(duì)之間的透射變換矩陣 H(3行x3列)
warpPerspective(): 對(duì)輸入圖像進(jìn)行透射變換
perspectiveTransform():對(duì)二維或者三維矢量進(jìn)行透射變換,也就是對(duì)輸入二維坐標(biāo)點(diǎn)或者三維坐標(biāo)點(diǎn)進(jìn)行投射變換。
estimateAffine3D:計(jì)算多個(gè)三維點(diǎn)對(duì)之間的最優(yōu)三維仿射變換矩陣H (3行x4列)
transform():對(duì)輸入的N維矢量進(jìn)行變換,可用于進(jìn)行仿射變換、圖像色彩變換.
findFundamentalMat:計(jì)算多個(gè)點(diǎn)對(duì)之間的基矩陣H。
?
cvStereoCalibrate():中T類型要求了3*1,對(duì)與其他形參float和double都支持
cvStereoRectigy():只支持double類型
cvStereoRectifyUncalibrated():立體校正算法Hartley算法效果和F矩陣及圖像數(shù)量有關(guān),
ps:
【如果用cvStereoCalibrate()函數(shù)計(jì)算處理的F矩陣效果和Bouguet算法(cvStereoRectigy())效果一樣】
【如果用cvFindFundamentalMat()函數(shù)計(jì)算F矩陣,沒有Bougut算法好】
【用Hartley算法(cvStereoRectifyUncalibrated())校正時(shí),別忘了實(shí)現(xiàn)要用cvUndistortPoints()去除相機(jī)畸變,Bouguet算法(cvStereoRectigy())沒有這個(gè)要求,實(shí)際上它在函數(shù)內(nèi)部校正了相機(jī)的畸變。】
?
Q&A:
問題1:如何計(jì)算3個(gè)二維點(diǎn)對(duì)之間的仿射變換矩陣?
答:使用getAffineTransform()。
問題2:如何計(jì)算多個(gè)二維點(diǎn)對(duì)之間的仿射變換矩陣(使用誤差最小準(zhǔn)則 )?
答:使用estimateRigidTransform()。
問題3:如何計(jì)算多個(gè)二維點(diǎn)對(duì)之間的投影變換矩陣(使用誤差最小準(zhǔn)則 )
答:findHomography()。
問題4:如何計(jì)算4個(gè)二維點(diǎn)對(duì)之間的透射變換?
答:使用getPerspectiveTransform()。
問題5:如何計(jì)算多個(gè)三維點(diǎn)對(duì)之間的仿射變換?
答:使用estimateAffine3D。
問題6:如何對(duì)輸入圖像進(jìn)行仿射變換?
答:使用warpAffine()。
問題7:如何對(duì)輸入圖像進(jìn)行透射變換?
答:使用perspectiveTransform()。
問題8:如何對(duì)輸入的二維點(diǎn)對(duì)進(jìn)行仿射變換?
答:使用transform()。
問題9:如何對(duì)輸入的三維點(diǎn)對(duì)進(jìn)行投影變換?
答:使用perspectiveTransform()。
6、實(shí)際代碼
代碼參考:https://blog.csdn.net/zhuisui_woxin/article/details/84400439
(1)KNNMATCH+DRAWKNNMATCH+LOWE'S TEST
# ''' 基于FLANN的匹配器(FLANN based Matcher) 1.FLANN代表近似最近鄰居的快速庫(kù)。它代表一組經(jīng)過優(yōu)化的算法,用于大數(shù)據(jù)集中的快速最近鄰搜索以及高維特征。 2.對(duì)于大型數(shù)據(jù)集,它的工作速度比BFMatcher快。 3.需要傳遞兩個(gè)字典來指定要使用的算法及其相關(guān)參數(shù)等 對(duì)于SIFT或SURF等算法,可以用以下方法: index_params = dict(algorithm = FLANN_INDEX_KDTREE, trees = 5) 對(duì)于ORB,可以使用以下參數(shù): index_params= dict(algorithm = FLANN_INDEX_LSH,table_number = 6, # 12 這個(gè)參數(shù)是searchParam,指定了索引中的樹應(yīng)該遞歸遍歷的次數(shù)。值越高精度越高key_size = 12, # 20multi_probe_level = 1) #2 ''' import cv2 as cv from matplotlib import pyplot as plt#1、#讀取要匹配的灰度照片 queryImage=cv.imread("b2_ROI_Template3.jpg",0) trainingImage=cv.imread("b2_target.jpg",0)#2、#創(chuàng)建sift檢測(cè)器,這個(gè)sift檢測(cè)器主要是用于檢測(cè)模板和待匹配圖像的特征關(guān)鍵點(diǎn)點(diǎn), sift=cv.xfeatures2d.SIFT_create() #利用創(chuàng)建好的特征點(diǎn)檢測(cè)器去檢測(cè)兩幅圖像的特征關(guān)鍵點(diǎn), # 其中kp含有角度、關(guān)鍵點(diǎn)坐標(biāo)等多個(gè)信息,具體怎么提取出坐標(biāo)點(diǎn)的坐標(biāo)不清楚, # des是特征描述符,每一個(gè)特征點(diǎn)對(duì)應(yīng)了一個(gè)特征描述符,由一維特征向量構(gòu)成 kp1, des1 = sift.detectAndCompute(queryImage,None) kp2, des2 = sift.detectAndCompute(trainingImage,None)#3、設(shè)置Flannde參數(shù),這里是為了下一步匹配做準(zhǔn)備 FLANN_INDEX_KDTREE=0 indexParams=dict(algorithm=FLANN_INDEX_KDTREE,trees=5)#指定匹配的算法和kd樹的層數(shù) searchParams= dict(checks=50)#指定返回的個(gè)數(shù)#4、根據(jù)設(shè)置的參數(shù)創(chuàng)建特征匹配器 flann=cv.FlannBasedMatcher(indexParams,searchParams) #利用創(chuàng)建好的特征匹配器利用k近鄰算法來用模板的特征描述符去匹配圖像的特征描述符,k指的是返回前k個(gè)最匹配的特征區(qū)域 matches=flann.knnMatch(des1,des2,k=2)#返回的是最匹配的兩個(gè)特征點(diǎn)的信息,返回的類型是一個(gè)列表,列表元素的類型是Dmatch數(shù)據(jù)類型,具體是什么我也不知道 #設(shè)置好初始匹配值,用來存放特征點(diǎn) matchesMask=[[0,0] for i in range (len(matches))]#[[0, 0], [0, 0]... [0, 0]]個(gè)數(shù)為len(matches) for i, (m,n) in enumerate(matches):#返回索引號(hào)和兩個(gè)匹配的信息'''比較最近鄰距離與次近鄰距離的SIFT匹配方式:取一幅圖像中的一個(gè)SIFT關(guān)鍵點(diǎn),并找出其與另一幅圖像中歐式距離最近的前兩個(gè)關(guān)鍵點(diǎn),在這兩個(gè)關(guān)鍵點(diǎn)中,如果最近的距離除以次近的距離得到的比率ratio少于某個(gè)閾值T,則接受這一對(duì)匹配點(diǎn)。因?yàn)閷?duì)于錯(cuò)誤匹配,由于特征空間的高維性,相似的距離可能有大量其他的錯(cuò)誤匹配,從而它的ratio值比較高。顯然降低這個(gè)比例閾值T,SIFT匹配點(diǎn)數(shù)目會(huì)減少,但更加穩(wěn)定,反之亦然。Lowe推薦ratio的閾值為0.8,但作者對(duì)大量任意存在尺度、旋轉(zhuǎn)和亮度變化的兩幅圖片進(jìn)行匹配,結(jié)果表明ratio取值在0. 4~0. 6 之間最佳,小于0. 4的很少有匹配點(diǎn),大于0. 6的則存在大量錯(cuò)誤匹配點(diǎn),所以建議ratio的取值原則如下:ratio=0. 4:對(duì)于準(zhǔn)確度要求高的匹配;ratio=0. 6:對(duì)于匹配點(diǎn)數(shù)目要求比較多的匹配;ratio=0. 5:一般情況下。'''if m.distance< 0.5*n.distance: #m表示大圖像上最匹配點(diǎn)的距離,n表示次匹配點(diǎn)的距離,若比值小于0.5則舍棄matchesMask[i]=[1,0] #繪制的參數(shù),匹配連線的顏色,特征點(diǎn)的顏色,需要畫哪些匹配,flags=0繪制點(diǎn)和線,=2不畫特征點(diǎn) drawParams=dict(matchColor=(0,0,255),singlePointColor=(255,0,0),matchesMask=matchesMask,flags=0) #給特征點(diǎn)和匹配的線定義顏色 resultimage=cv.drawMatchesKnn(queryImage,kp1,trainingImage,kp2,matches,None,**drawParams) #畫出匹配的結(jié)果 plt.imshow(resultimage,),plt.show()繪制出了所有的特征點(diǎn),以及相互匹配的特征點(diǎn)的匹配線
?
(2)match+drawmatch
# 基于FLANN的匹配器(FLANN based Matcher)定位圖片 import numpy as np import cv2 from matplotlib import pyplot as pltMIN_MATCH_COUNT = 5 # 設(shè)置最低特征點(diǎn)匹配數(shù)量為10 template = cv2.imread('h3_target_Template.jpg', 0) # queryImage target = cv2.imread('h3_target.jpg', 0) # trainImage # Initiate SIFT detector創(chuàng)建sift檢測(cè)器 sift = cv2.xfeatures2d.SIFT_create() # find the keypoints and descriptors with SIFT kp1, des1 = sift.detectAndCompute(template, None) kp2, des2 = sift.detectAndCompute(target, None) # 創(chuàng)建設(shè)置FLANN匹配 FLANN_INDEX_KDTREE = 0 index_params = dict(algorithm=FLANN_INDEX_KDTREE, trees=5) search_params = dict(checks=50) flann = cv2.FlannBasedMatcher(index_params, search_params) matches = flann.knnMatch(des1, des2, k=2) # store all the good matches as per Lowe's ratio test. good = [] # 舍棄大于0.7的匹配 for m, n in matches:if m.distance < 0.7 * n.distance:good.append(m) print(good) if len(good) >= MIN_MATCH_COUNT:# 獲取關(guān)鍵點(diǎn)的坐標(biāo)src_pts = np.float32([kp1[m.queryIdx].pt for m in good]).reshape(-1, 1, 2)print(src_pts)dst_pts = np.float32([kp2[m.trainIdx].pt for m in good]).reshape(-1, 1, 2)# 計(jì)算變換矩陣和MASK# 計(jì)算多個(gè)二維點(diǎn)對(duì)之間的最優(yōu)單映射變換矩陣 H(3行x3列) ,使用最小均方誤差或者RANSAC方法M, mask = cv2.findHomography(src_pts, dst_pts, cv2.RANSAC, 5.0)matchesMask = mask.ravel().tolist()#先將mask變成一維,再將矩陣轉(zhuǎn)化為列表h, w = template.shape# 使用得到的變換矩陣對(duì)原圖像的四個(gè)角進(jìn)行變換,獲得在目標(biāo)圖像上對(duì)應(yīng)的坐標(biāo)pts = np.float32([[0, 0], [0, h - 1], [w - 1, h - 1], [w - 1, 0]]).reshape(-1, 1, 2)dst = cv2.perspectiveTransform(pts, M)cv2.polylines(target, [np.int32(dst)], True, 0, 2, cv2.LINE_AA) else:print("Not enough matches are found - %d/%d" % (len(good), MIN_MATCH_COUNT))matchesMask = None draw_params = dict(matchColor=(0, 255, 0),singlePointColor=None,matchesMask=matchesMask,flags=2) result = cv2.drawMatches(template, kp1, target, kp2, good, None, **draw_params) plt.imshow(result, 'gray') plt.show()總結(jié)
以上是生活随笔為你收集整理的【图像处理】——特征匹配(SIFT特征检测器+FLANN特征匹配方法+KNN近邻最优匹配筛选)——cv.xfeatures2d.SIFT_create()sift.detectAndCompute的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【图像处理】——改变图像的大小(降采样重
- 下一篇: idea ssm项目移包报错问题