opencv筆記--SURF
SURF(Speeded-Up Robust Features) 是對 SIFT 得改進,相對於 SIFT,SURF 利用積分影象與盒函式模擬 DoG,提升了計算速度;同時,使用了一種不用於 SIFT 的特徵描述方案。
在 SIFT 中,檢測尺度空間極值使用了 DoG 響應,SURF 做了如下改進:
1)首先求原影象的積分影象,使用積分影象可以求任意尺度盒函式(Box Filter)響應;
2)使用 Box Fitler 代替 DoG,下圖給出了垂直方向與xy方向的 Box Filter,使用積分影象求任意尺寸響應時間都是固定的;
3)在 空間尋找極值作為候選特徵點,定義 Hessian 矩陣,其中,G 為高斯函式,I 為影象函式;
剔除 Det(H) 小於某固定值的候選特徵點,得到較好的極值點;
4)使用小波函式計算特徵點附近響應,該響應仍然可在積分影象上計算;然後以 60 度為步長在圓形上滑動,求每個視窗響應和並將響應和最大方向作為主方向;
5)將特徵點區域分為 4 * 4 小區域,在小區域內再次應用小波函式,並分別求出響應和,可構成向量,最終構成 4 * 4 * 4 = 64 維特徵向量;
一種擴充套件方式是區分 dx,dy 方向,分別統計 dy > 0 時對應的 dx 求和,dy < 0時對應的 dx 求和...,這樣將 v 擴充套件為 8 維向量,最終形成 4 * 4 * 8 = 128維特徵向量;
opencv 提供了 SURF 實現,其建構函式如下:
SURF(double hessianThreshold, int nOctaves=4, int nOctaveLayers=2, bool extended=true, bool upright=false);
hessianThreshold:當候選特徵點的 Hessian 矩陣行列式值小於該值時,忽略該候選特徵點;
nOctaves:表示高斯金字塔層數,當層數越多時,可檢測到更粗的特徵點;
nOctaveLayers:檢測尺度空間上極值使用層數為nOctaveLayers + 3;
extended:是否使用擴充套件特徵描述,預設特徵點描述向量為64維,擴充套件特徵點描述向量為128維;
upright:當特徵點方向不改變時,在描述特徵點時可不計算特徵點主方向;
SURF 特徵匹配程式碼與 SIFT 基本一致,如下:
1 cv::Mat img1 = cv::imread("a.jpg", cv::IMREAD_GRAYSCALE); 2 cv::Mat img2 = cv::imread("b.jpg", cv::IMREAD_GRAYSCALE); 3 4 cv::SurfFeatureDetector detector(2000); 5 std::vector<cv::KeyPoint> keypoints1, keypoints2; 6 cv::Mat descriptors1, descriptors2; 7 detector.operator()(img1, cv::noArray(), keypoints1, descriptors1); 8 detector.operator()(img2, cv::noArray(), keypoints2, descriptors2); 9 10 cv::BFMatcher matcher(cv::NORM_L2); 11 std::vector<DMatch> matches; 12 matcher.match(descriptors1, descriptors2, matches); 13 14 cv::Mat img_matches; 15 cv::drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches); 16 cv::imwrite("c.jpg", img_matches); 17 18 double min_dist = 100; 19 20 for (int i = 0; i < matches.size(); i++) 21 { 22 double dist = matches[i].distance; 23 if (dist < min_dist) min_dist = dist; 24 } 25 26 27 // Draw only "good" matches (i.e. whose distance is less than 2*min_dist, 28 // or a small arbitary value ( 0.02 ) 29 std::vector< DMatch > good_matches; 30 for (int i = 0; i < matches.size(); i++) 31 { 32 if (matches[i].distance <= max(2 * min_dist, 0.02)) 33 { 34 good_matches.push_back(matches[i]); 35 } 36 } 37 38 cv::drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches); 39 cv::imwrite("d.jpg", img_matches);
參考資料SURF: Speeded Up Robust Features Herbert Bay
Learning OpenCV 3 Adrian Kaehler & Gary Bradski