1. 程式人生 > 實用技巧 >opencv筆記--SURF

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