Flann特徵點匹配簡述(Lowe's algorithm)
/***好記性不如爛筆頭,記下來便於以後複習***/
特徵匹配的結果會得到兩個特徵集合的對應關係列表。第一組特徵集被稱為訓練集(train),第二組被稱為查詢集(query)。Flann 在呼叫匹配函式之前,為了提高匹配速度,訓練一個匹配器。訓練階段是為了優化cv::FlannBasedMatcher的效能。train類將會建立特徵集的索引樹。將 query image 的每一個特徵點和 train 匹配器進行匹配,找出最佳匹配;也就是從query image 的特徵中逐個去和訓練器做匹配,也就是說每一個query image 特徵點都會有一個最佳匹配,後期還需要驗證這匹配的正確性,可以通過設定截斷值來去除誤差大的匹配;
去除了誤差大的匹配即可以使用 Lowe's策略進行匹配的再一次篩選;
knnMatch()找每個query image特徵的K近鄰匹配,效率不夠高,幀率很低。
Lowe’s演算法:為了進一步篩選匹配點,來獲取優秀的匹配點,這就是所謂的“去粗取精”。一般會採用Lowe’s演算法來進一步獲取優秀匹配點。
為了排除因為影象遮擋和背景混亂而產生的無匹配關係的關鍵點,SIFT的作者Lowe提出了比較最近鄰距離與次近鄰距離的SIFT匹配方式:取一幅影象中的一個SIFT關鍵點,並找出其與另一幅影象中歐式距離最近的前兩個關鍵點,在這兩個關鍵點中,如果最近的距離除以次近的距離得到的比率ratio少於某個閾值T,則接受這一對匹配點。因為對於錯誤匹配,由於特徵空間的高維性,相似的距離可能有大量其他的錯誤匹配,從而它的ratio值比較高。顯然降低這個比例閾值T,SIFT匹配點數目會減少,但更加穩定,反之亦然。
Lowe推薦ratio的閾值為0.8,但作者對大量任意存在尺度、旋轉和亮度變化的兩幅圖片進行匹配,結果表明ratio取值在0. 4~0. 6 之間最佳,小於0. 4的很少有匹配點,大於0. 6的則存在大量錯誤匹配點,所以建議ratio的取值原則如下:
ratio=0. 4:對於準確度要求高的匹配;
ratio=0. 6:對於匹配點數目要求比較多的匹配;
ratio=0. 5:一般情況下。
Lowe's改進:可以反過來使用最近鄰比次近鄰,在匹配中可以作為置信度來使用,當滿足最近鄰比次近鄰大於某個值的時候,作為某個條件的判別 置信度;比如可以應用在雙目視覺立體匹配中的視差選擇與優化環節中(論文正在編寫中);
#include "highgui/highgui.hpp" #include "opencv2/nonfree/nonfree.hpp" #include "opencv2/legacy/legacy.hpp" #include <iostream> using namespace cv; using namespace std; int main() { Mat image01 = imread("g2.jpg", 1); Mat image02 = imread("g4.jpg", 1); imshow("p2", image01); imshow("p1", image02); //灰度圖轉換 Mat image1, image2; cvtColor(image01, image1, CV_RGB2GRAY); cvtColor(image02, image2, CV_RGB2GRAY); //提取特徵點 SurfFeatureDetector surfDetector(2000); //海塞矩陣閾值,在這裡調整精度,值越大點越少,越精準 vector<KeyPoint> keyPoint1, keyPoint2; surfDetector.detect(image1, keyPoint1); surfDetector.detect(image2, keyPoint2); //特徵點描述,為下邊的特徵點匹配做準備 SurfDescriptorExtractor SurfDescriptor; Mat imageDesc1, imageDesc2; SurfDescriptor.compute(image1, keyPoint1, imageDesc1); SurfDescriptor.compute(image2, keyPoint2, imageDesc2); FlannBasedMatcher matcher; vector<vector<DMatch> > matchePoints; vector<DMatch> GoodMatchePoints; vector<Mat> train_desc(1, imageDesc1); matcher.add(train_desc); matcher.train(); matcher.knnMatch(imageDesc2, matchePoints, 2); cout << "total match points: " << matchePoints.size() << endl; // Lowe's algorithm,獲取優秀匹配點 for (int i = 0; i < matchePoints.size(); i++) { if (matchePoints[i][0].distance < 0.6 * matchePoints[i][1].distance) { GoodMatchePoints.push_back(matchePoints[i][0]); } } Mat first_match; drawMatches(image02, keyPoint2, image01, keyPoint1, GoodMatchePoints, first_match); imshow("first_match ", first_match); waitKey(); return 0; }
參考部落格: