1. 程式人生 > 實用技巧 >SLAM14講 第七章 特徵點法

SLAM14講 第七章 特徵點法

視覺前端和優化後端

視覺里程計VO-根據相鄰影象的資訊估計處粗略的相機運動,給後端較好的估計值

【一】特徵提取與匹配:特徵點法

——執行穩定,對光照、動態物體不敏感

主要問題:根據影象來估計相機運動

特徵點-路標-有代表性的點-影象資訊的一種表達形式-在相機運動之後保持穩定-角點|邊緣|區塊

僅灰度值:受光照、形變、物體材質的影響嚴重【×】

SIFT\SURF\ORB——可重複性、可區別性、高效、區域性

特徵點=關鍵點(影象中的位置、朝向、大小)+描述子(向量,周圍畫素)

依據【外觀相似的特徵有相似的描述子原則】

SIFT尺度不變特徵變換 5228.7ms

FAST關鍵點——計算速度很快,沒有描述子,不具有方向性

ORB(旋轉、尺度不變性)——速度極快的二進位制描述子BRIEF 1000點/15.3ms

SURF 217.3ms

7.1 ORB特徵

Oriented FAST關鍵點(FAST+特徵點主方向)+BRIEF特徵子

1 FAST關鍵點

FAST角點:檢測區域性畫素畫素灰度變化明顯的地方(只比較畫素亮度大小)

FAST-9/11/12(半徑為3的圓上16個畫素點中有N個大於或小於中心點的閾值120%/80%)

FAST-12預測試:第1/5/9/13個點的情況

#非極大值抑制:一定區域內僅保留響應極大值的角點,避免集中

【缺點1】FAST特徵點量大且不確定,往往希望對影象提取固定數量的特徵

【改進】固定數量N,原始FAST角點計算Harries響應值

【缺點2】FAST不具有方向資訊

【改進】由構建影象金字塔並在每一層檢測角點實現尺度不變性,灰度質心(以影象塊灰度值作為權重的中心)法實現特徵旋轉

2 BRIEF描述子

關鍵點附近兩個畫素p和q的大小關係,1/0,128維,隨機選取

旋轉後的Steer BRIEF特徵

7.2 特徵匹配(資料關聯)

#場景大量重複紋理導致的誤匹配問題

計算特徵點之間的描述子距離,通常漢明距離,二進位制不同位數的個數

特徵點多時,用快速近似最近鄰FLANN演算法

#include 
<iostream> #include <opencv2/core/core.hpp> #include <opencv2/features2d/features2d.hpp> #include <opencv2/highgui/highgui.hpp> using namespace std; using namespace cv; int main ( int argc, char** argv ) { if ( argc != 3 ) //確認輸入為兩張圖片 { cout<<"usage: feature_extraction img1 img2"<<endl; return 1; } //-- 讀取影象 // imread C++ 模型 // include <opencv2/imgcodecs.hpp> // Mat cv::imread( const String & filename, int flags = IMREAD_COLOR) // 返回MAT型別,讀取失敗時返回空矩陣 Mat::data = NULL // 引數1:filename 讀取的圖片檔名 絕對/相對路徑 要加字尾 // 引數2:flags 讀取標記,讀取圖片的方式,預設為IMREAD_COLOR(好像沒影響) Mat img_1 = imread ( argv[1], IMREAD_COLOR ); Mat img_2 = imread ( argv[2], CV_LOAD_IMAGE_COLOR ); //-- 初始化 std::vector<KeyPoint> keypoints_1, keypoints_2;//關鍵點-放置keypoint物件的一個vector Mat descriptors_1, descriptors_2;//描述子,cv::Mat型別 //OpenCV提供FeatureDetector實現特徵檢測及匹配; //FeatureDetetor是虛類,通過定義FeatureDetector的物件可以使用多種特徵檢測方法。通過create()函式呼叫: //FAST\STAR\SIFT\SURF\ORB\MSER\GFTT\HARRIS\Dense\SimpleBlob Ptr<FeatureDetector> detector = ORB::create();//ORB特徵點檢測 Ptr<DescriptorExtractor> descriptor = ORB::create();//BRIEF描述子提取 //計算特徵點之間的描述子距離,通常漢明距離 //DescriptorMatcher是匹配特徵向量的抽象類,在OpenCV2中的特徵匹配方法都繼承自該類 //(例如:BFmatcher,FlannBasedMatcher)。該類主要包含了兩組匹配方法:影象對之間的匹配以及影象和一個影象集之間的匹配 //DescriptorMatcher::create 對於給定引數,建立特徵描述子匹配(使用預設的建構函式). //BruteForce(L2)、BruteForce-L1\BruteForce-Hamming\BruteForce-HammingLUT\FlannBased Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create ( "BruteForce-Hamming" ); //-- 第一步:檢測 Oriented FAST 角點位置 detector->detect ( img_1,keypoints_1 ); detector->detect ( img_2,keypoints_2 ); //-- 第二步:根據角點位置計算 BRIEF 描述子 descriptor->compute ( img_1, keypoints_1, descriptors_1 ); descriptor->compute ( img_2, keypoints_2, descriptors_2 ); Mat outimg1; drawKeypoints( img_1, keypoints_1, outimg1, Scalar::all(-1), DrawMatchesFlags::DEFAULT ); imshow("圖1 ORB特徵點",outimg1); Mat outimg2; drawKeypoints( img_2, keypoints_2, outimg2, Scalar::all(-1), DrawMatchesFlags::DEFAULT ); imshow("圖2 ORB特徵點",outimg2); //-- 第三步:對兩幅影象中的BRIEF描述子進行匹配,使用 Hamming 距離 //DMatch是用於匹配特徵關鍵點的特徵描述子的類:查詢特徵描述子索引, 特徵描述子索引, 訓練影象索引, 以及不同特徵描述子之間的距離. vector<DMatch> matches; //BFMatcher matcher ( NORM_HAMMING ); matcher->match ( descriptors_1, descriptors_2, matches ); //-- 第四步:匹配點對篩選 double min_dist=10000, max_dist=0; //找出所有匹配之間的最小距離和最大距離, 即是最相似的和最不相似的兩組點之間的距離 for ( int i = 0; i < descriptors_1.rows; i++ ) { double dist = matches[i].distance; if ( dist < min_dist ) min_dist = dist; if ( dist > max_dist ) max_dist = dist; } // 僅供娛樂的寫法 min_dist = min_element( matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance; max_dist = max_element( matches.begin(), matches.end(), [](const DMatch& m1, const DMatch& m2) {return m1.distance<m2.distance;} )->distance; printf ( "-- Max dist : %f \n", max_dist ); printf ( "-- Min dist : %f \n", min_dist ); //當描述子之間的距離大於兩倍的最小距離時,即認為匹配有誤.但有時候最小距離會非常小,設定一個經驗值30作為下限. std::vector< DMatch > good_matches; for ( int i = 0; i < descriptors_1.rows; i++ ) { if ( matches[i].distance <= max ( 2*min_dist, 30.0 )) { good_matches.push_back ( matches[i] ); } } //-- 第五步:繪製匹配結果 Mat img_match; Mat img_goodmatch; drawMatches ( img_1, keypoints_1, img_2, keypoints_2, matches, img_match ); drawMatches ( img_1, keypoints_1, img_2, keypoints_2, good_matches, img_goodmatch ); imshow ( "圖3 所有匹配點對", img_match ); imshow ( "圖4 優化後匹配點對-篩選小於兩倍最小漢明距離或工程經驗值30的點", img_goodmatch ); imwrite ( "圖3 所有匹配點對.png", img_match ); imwrite ( "圖4 優化後匹配點對篩選小於兩倍最小漢明距離或工程經驗值30的點.png", img_goodmatch ); waitKey(0);

max-dist:95

min-dist:4

所有匹配點對:

優化後匹配點對(小於兩倍最小漢明距離的點):

優化後匹配點對(小於兩倍最小漢明距離或工程經驗值30的點):

優化後匹配點對(小於最小和最大漢明距離中間值的點):