图像匹配算法总结
最近在開發視覺分揀機項目時,遇到了不規則物體的坐標和角度識別問題,因此做了不少基礎測試研究工作,重點是解決圖像匹配問題,定位工件的中心點坐標。中間走了不少彎路,做一下資料記錄在這里,可能會對后來人有所幫助,如果需要視覺識別,AI模型相關的需求也可以找我們深圳原數科技。
圖像匹配是指通過一定的匹配算法在兩幅或多幅圖像之間識別同名點,如二維圖像匹配中通過比較目標區和搜索區中相同大小的窗口的相關系數,取搜索區中相關系數最大所對應的窗口中心點作為同名點。其實質是在基元相似性的條件下,運用匹配準則的最佳搜索問題。
圖像匹配的方法很多,一般分為兩大類,一類是基于灰度匹配的方法,另一類是基于特征匹配的方法。
基于模板匹配的方法
也稱作相關匹配算法,用空間二維滑動模板進行圖像匹配,不同算法的區別主要體現在模板及相關準則的選擇方面。.
算法主要為模板圖像在基準圖上進行由左往右、由上到下進行相關運算,最后得到一個進行相關運算后的系數矩陣:系數矩陣中的參數值用來度量模板圖像在基準圖中的子區域相似程度。采用相關系數來進行評判,模板匹配算法主要有基于灰度值的模板匹配、梯度值的模板匹配、相位相關匹配等方法。
?
?
基于特征匹配的方法
首先在原始圖像中提取特征,然后再建立兩幅圖像之間特征的匹配對應關系。常用的特征匹配基元包括點、線、區域等顯著特征。圖像特征相比像素點數量殺過少很多,特征間的匹配度量隨位置變化尖銳,容易找出準確的匹配位置,特征提取能大大減少噪聲影響,對灰度變化、形變和遮擋有較強的適應力。
特征匹配有三個基本步驟:特征提取、特征描述和特征匹配。特征提取就是從圖像中提取出關鍵點(或特征點、角點)等。特征描述就是用一組數學向量對特征點進行描述,其主要保證不同的向量和不同的特征點之間是一種對應的關系,同時相似的關鍵點之間的差異盡可能小。特征匹配其實就是特征向量之間的距離計算,常用的距離有歐氏距離、漢明距離、余弦距離等。
為了能夠更好的進行圖像匹配,需要在圖像中選擇具有代表性的區域,例如:圖像中的角點、邊緣和一些區塊。圖像識別出角點是最容易,也就是說角點的辨識度是最高的。所以,在很多的計算機視覺處理中,都是提取交掉作為特征,對圖像進行匹配,例如SFM,視覺SLAM等。
但是,單純的角點并不能很好的滿足我們的需求,例如:相機從遠處得到的是角點,但是在近處就可能不是角點;或者,當相機旋轉后,角點就發生了變化。
?
?
為此,計算機視覺的研究者們設計了許多更為穩定的的特征點,這些特征點不會隨著相機的移動,旋轉或者光照的變化而變化。例如:SIFT,SURF,ORB等。一個圖像的特征點由兩部分構成:關鍵點(Keypoint)和描述子(Descriptor)關鍵點指的是該特征點在圖像中的位置,有些還具有方向、尺度信息。
描述子通常是一個向量,按照人為的設計的方式,描述關鍵點周圍像素的信息。通常描述子是按照外觀相似的特征應該有相似的描述子設計的。
其中描述子的可區分性和其不變性是矛盾的,一個具有眾多不變性的特征描述子,其 區分局部圖像內容的能力就比較稍弱;而如果一個很容易區分不同局部圖像內容的特征描述 子,其魯棒性往往比較低。所以,在設計特征描述子的時候,就需要綜合考慮這三個特性, 找到三者之間的平衡。
我們首先進行常規的特征提取和特征點匹配,看看效果如何。
#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("2.jpg",?1);????//右圖
????Mat?image02?=?imread("1.jpg",?1);????//左圖
????namedWindow("p2",?0);
?namedWindow("p1",?0);
????imshow("p2",?image01);
????imshow("p1",?image02);
????//灰度圖轉換??
????Mat?image1,?image2;
????cvtColor(image01,?image1,?CV_RGB2GRAY);
????cvtColor(image02,?image2,?CV_RGB2GRAY);
????//提取特征點????
????SurfFeatureDetector?surfDetector(800);??//?海塞矩陣閾值,在這里調整精度,值越大點越少,越精準?
????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<DMatch>?matchePoints;
????matcher.match(imageDesc1,?imageDesc2,?matchePoints,?Mat());
????cout?<<?"total?match?points:?"?<<?matchePoints.size()?<<?endl;
????Mat?img_match;
????drawMatches(image01,?keyPoint1,?image02,?keyPoint2,?matchePoints,?img_match);
????namedWindow("match",?0);
????imshow("match",img_match);
????imwrite("match.jpg",?img_match);
????waitKey();
????return?0;
}
?
?
由上面的特征點匹配的效果來看,匹配的效果還是相當糟糕的,如果我們拿著這樣子的匹配結果去實現圖像拼接或者物體追蹤,效果肯定是極差的。所以我們需要進一步篩選匹配點,來獲取優秀的匹配點,這就是所謂的“去粗取精”。這里我們采用了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:一般情況下。
#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;
}
?
?為了體現所謂的尺度不變形,我特意加入了額外一組圖片來測試
?
由特征點匹配的效果來看,現在的特征點匹配應該是非常精準了,因為我們已經把不合格的匹配點統統移除出去了。
2.SIFT
SURF算法是SIFT算法的加速版,?而SIFT(尺度不變特征轉換,?ScaleInvariant?Feature?Transform)?是另一種著名的尺度不變特征檢測法。我們知道,SURF相對于SIFT而言,特征點檢測的速度有著極大的提升,所以在一些實時視頻流物體匹配上有著很強的應用。而SIFT因為其巨大的特征計算量而使得特征點提取的過程異常花費時間,所以在一些注重速度的場合難有應用場景。但是SIFT相對于SURF的優點就是,由于SIFT基于浮點內核計算特征點,因此通常認為,?SIFT算法檢測的特征在空間和尺度上定位更加精確,所以在要求匹配極度精準且不考慮匹配速度的場合可以考慮使用SIFT算法。
SIFT特征檢測的代碼我們僅需要對上面的SURF代碼作出一丁點修改即可。
#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("1.jpg",?1);????//右圖
????Mat?image02?=?imread("2.jpg",?1);????//左圖
????namedWindow("p2",?0);
????namedWindow("p1",?0);
????imshow("p2",?image01);
????imshow("p1",?image02);
????//灰度圖轉換??
????Mat?image1,?image2;
????cvtColor(image01,?image1,?CV_RGB2GRAY);
????cvtColor(image02,?image2,?CV_RGB2GRAY);
????//提取特征點????
????SiftFeatureDetector?siftDetector(2000);??//?海塞矩陣閾值,在這里調整精度,值越大點越少,越精準?
????vector<KeyPoint>?keyPoint1,?keyPoint2;
????siftDetector.detect(image1,?keyPoint1);
????siftDetector.detect(image2,?keyPoint2);
????//特征點描述,為下邊的特征點匹配做準備????
????SiftDescriptorExtractor?SiftDescriptor;
????Mat?imageDesc1,?imageDesc2;
????SiftDescriptor.compute(image1,?keyPoint1,?imageDesc1);
????SiftDescriptor.compute(image2,?keyPoint2,?imageDesc2);
????//獲得匹配特征點,并提取最優配對?????
????FlannBasedMatcher?matcher;
????vector<DMatch>?matchePoints;
????matcher.match(imageDesc1,?imageDesc2,?matchePoints,?Mat());
????cout?<<?"total?match?points:?"?<<?matchePoints.size()?<<?endl;
????Mat?img_match;
????drawMatches(image01,?keyPoint1,?image02,?keyPoint2,?matchePoints,?img_match);
????imshow("match",img_match);
????imwrite("match.jpg",?img_match);
????waitKey();
????return?0;
}
?
?
沒有經過點篩選的匹配效果同樣糟糕。下面繼續采用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("1.jpg",?1);
????Mat?image02?=?imread("2.jpg",?1);
????imshow("p2",?image01);
????imshow("p1",?image02);
????//灰度圖轉換??
????Mat?image1,?image2;
????cvtColor(image01,?image1,?CV_RGB2GRAY);
????cvtColor(image02,?image2,?CV_RGB2GRAY);
????//提取特征點????
????SiftFeatureDetector?siftDetector(800);??//?海塞矩陣閾值,在這里調整精度,值越大點越少,越精準?
????vector<KeyPoint>?keyPoint1,?keyPoint2;
????siftDetector.detect(image1,?keyPoint1);
????siftDetector.detect(image2,?keyPoint2);
????//特征點描述,為下邊的特征點匹配做準備????
????SiftDescriptorExtractor?SiftDescriptor;
????Mat?imageDesc1,?imageDesc2;
????SiftDescriptor.compute(image1,?keyPoint1,?imageDesc1);
????SiftDescriptor.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);
????imwrite("first_match.jpg",?first_match);
????waitKey();
????return?0;
}
?
3.ORB
ORB是ORiented?Brief的簡稱,是brief算法的改進版。ORB算法比SIFT算法快100倍,比SURF算法快10倍。在計算機視覺領域有種說法,ORB算法的綜合性能在各種測評里較其他特征提取算法是最好的。
ORB算法是brief算法的改進,那么我們先說一下brief算法有什么去缺點。
 BRIEF的優點在于其速度,其缺點是:
不具備旋轉不變性
對噪聲敏感
不具備尺度不變性
而ORB算法就是試圖解決上述缺點中1和2提出的一種新概念。值得注意的是,ORB沒有解決尺度不變性。
#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);
????//提取特征點????
????OrbFeatureDetector?OrbDetector(1000);??//?在這里調整精度,值越小點越少,越精準?
????vector<KeyPoint>?keyPoint1,?keyPoint2;
????OrbDetector.detect(image1,?keyPoint1);
????OrbDetector.detect(image2,?keyPoint2);
????//特征點描述,為下邊的特征點匹配做準備????
????OrbDescriptorExtractor?OrbDescriptor;
????Mat?imageDesc1,?imageDesc2;
????OrbDescriptor.compute(image1,?keyPoint1,?imageDesc1);
????OrbDescriptor.compute(image2,?keyPoint2,?imageDesc2);
????flann::Index?flannIndex(imageDesc1,?flann::LshIndexParams(12,?20,?2),?cvflann::FLANN_DIST_HAMMING);
????vector<DMatch>?GoodMatchePoints;
????Mat?macthIndex(imageDesc2.rows,?2,?CV_32SC1),?matchDistance(imageDesc2.rows,?2,?CV_32FC1);
????flannIndex.knnSearch(imageDesc2,?macthIndex,?matchDistance,?2,?flann::SearchParams());
????//?Lowe's?algorithm,獲取優秀匹配點
????for?(int?i?=?0;?i?<?matchDistance.rows;?i++)
????{
????????if?(matchDistance.at<float>(i,0)?<?0.6?*?matchDistance.at<float>(i,?1))
????????{
????????????DMatch?dmatches(i,?macthIndex.at<int>(i,?0),?matchDistance.at<float>(i,?0));
????????????GoodMatchePoints.push_back(dmatches);
????????}
????}
????Mat?first_match;
????drawMatches(image02,?keyPoint2,?image01,?keyPoint1,?GoodMatchePoints,?first_match);
????imshow("first_match?",?first_match);
????imwrite("first_match.jpg",?first_match);
????waitKey();
????return?0;
}
?
?
4.FAST
FAST(加速分割測試獲得特征,?Features?from?Accelerated?Segment?Test)?。?這種算子專門用來快速檢測興趣點,?只需要對比幾個像素,就可以判斷是否為關鍵點。
跟Harris檢測器的情況一樣,?FAST算法源于對構成角點的定義。FAST對角點的定義基于候選特征點周圍的圖像強度值。?以某個點為中心作一個圓,?根據圓上的像素值判斷該點是否為關鍵點。?如果存在這樣一段圓弧,?它的連續長度超過周長的3/4,?并且它上面所有像素的強度值都與圓心的強度值明顯不同(全部更黑或更亮)?,?那么就認定這是一個關鍵點。
用這個算法檢測興趣點的速度非常快,?因此十分適合需要優先考慮速度的應用。?這些應用包括實時視覺跟蹤、?目標識別等,?它們需要在實時視頻流中跟蹤或匹配多個點。
我們使用FastFeatureDetector?進行特征點提取,因為opencv沒有提供fast專用的描述子提取器,所以我們借用SiftDescriptorExtractor?來實現描述子的提取。
#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("1.jpg",?1);
????Mat?image02?=?imread("2.jpg",?1);
????imshow("p2",?image01);
????imshow("p1",?image02);
????//灰度圖轉換??
????Mat?image1,?image2;
????cvtColor(image01,?image1,?CV_RGB2GRAY);
????cvtColor(image02,?image2,?CV_RGB2GRAY);
????//提取特征點????
????FastFeatureDetector?Detector(50);??//閾值?
????vector<KeyPoint>?keyPoint1,?keyPoint2;
????Detector.detect(image1,?keyPoint1);
????Detector.detect(image2,?keyPoint2);
????//特征點描述,為下邊的特征點匹配做準備????
????SiftDescriptorExtractor???Descriptor;
????Mat?imageDesc1,?imageDesc2;
????Descriptor.compute(image1,?keyPoint1,?imageDesc1);
????Descriptor.compute(image2,?keyPoint2,?imageDesc2);
????BruteForceMatcher<?L2<float>?>?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);
????imwrite("first_match.jpg",?first_match);
????waitKey();
????return?0;
}
如果我們把描述子換成SurfDescriptorExtractor,即FastFeatureDetector?+?SurfDescriptorExtractor的組合,看看效果
?
?
可以看出,這種組合下的特征點匹配并不精確。
如果我們把描述子換成SurfDescriptorExtractor,即FastFeatureDetector?+?BriefDescriptorExtractor?的組合,看看效果
?
?
速度雖快,但是精度卻差強人意。
看到這里可能很多人會有疑惑:為什么FAST特征點可以用所以我們借用SiftDescriptorExtractor或者其他描述子提取器進行提取?
在這里我說一下自己的理解。要完成特征點的匹配第一個步驟就是找出每幅圖像的特征點,這叫做特征檢測,比如我們使用FastFeatureDetector、SiftFeatureDetector都是特征檢測的模塊。我們得到這些圖像的特征點后,我們就對這些特征點進行進一步的分析,用一些數學上的特征對其進行描述,如梯度直方圖,局部隨機二值特征等。所以在這一步我們可以選擇其他描述子提取器對這些點進行特征描述,進而完成特征點的精確匹配。
在opencv中,SURF,ORB,SIFT既包含FeatureDetector,又包含?DescriptorExtractor,所以我們使用上述三種算法做特征匹配時,都用其自帶的方法配套使用。
除此之外,如果我們相用FAST角點檢測并作特征點匹配該怎么辦?此時可以使用上述的FastFeatureDetector?+?BriefDescriptorExtractor?的方式,這種組合方式其實就是著名的ORB算法。所以特征點檢測和特征點匹配是兩種不同的步驟,我們只需根據自己項目的需求對這兩個步驟的方法隨意組合就好。
5.Harris角點
在圖像中搜索有價值的特征點時,使用角點是一種不錯的方法。?角點是很容易在圖像中定位的局部特征,?并且大量存在于人造物體中(例如墻壁、?門、?窗戶、?桌子等產生的角點)。?角點的價值在于它是兩條邊緣線的接合點,?是一種二維特征,可以被精確地定位(即使是子像素級精度)。?與此相反的是位于均勻區域或物體輪廓上的點以及在同一物體的不同圖像上很難重復精確定位的點。?Harris特征檢測是檢測角點的經典方法。
這里僅展示GoodFeaturesToTrackDetector?+ SiftDescriptorExtractor的組合方式的代碼,其他組合不再演示。
#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("1.jpg",?1);
????Mat?image02?=?imread("2.jpg",?1);
????imshow("p2",?image01);
????imshow("p1",?image02);
????//灰度圖轉換??
????Mat?image1,?image2;
????cvtColor(image01,?image1,?CV_RGB2GRAY);
????cvtColor(image02,?image2,?CV_RGB2GRAY);
????//提取特征點????
????GoodFeaturesToTrackDetector?Detector(500);??//最大點數,值越大,點越多
????vector<KeyPoint>?keyPoint1,?keyPoint2;
????Detector.detect(image1,?keyPoint1);
????Detector.detect(image2,?keyPoint2);
????//特征點描述,為下邊的特征點匹配做準備????
????SiftDescriptorExtractor??Descriptor;
????Mat?imageDesc1,?imageDesc2;
????Descriptor.compute(image1,?keyPoint1,?imageDesc1);
????Descriptor.compute(image2,?keyPoint2,?imageDesc2);
????BruteForceMatcher<?L2<float>?>?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);
????imwrite("first_match.jpg",?first_match);
????waitKey();
????return?0;
}
匹配相當精準
?
計算機視覺領域其實還有了很多特征檢測的方法,比如HOG、Harr、LBP等,這里就不再敘述了,因為方法都是類似,我們根據自己的需求挑選相應的方法就好了。
?
?
?
?
總結
 
                            
                        - 上一篇: 十天学会单片机(3)发光管闪烁,蜂鸣器发
- 下一篇: VS2010中常用的快捷键
