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

opencv筆記--ORB

ORB detector 使用 FAST detector 和 BRIEF descriptor 基本思路。在介紹 ORB 之前,首先對 FAST 與 BRIEF 進行說明。

1 FAST

FAST(Featrues from Accelerated Segment Test),其基本思想是比較當前點與周邊點差異,當週邊有連續不少於一半的點均比中間點亮或者暗,則認為該點為一個特徵點。其中,亮或暗的定義為:

1)當時,周邊點比中間點亮;

2)當時,周邊點比中間點暗;

3)當時,周邊點與中間點相似;

使用以上定義,可以迅速找到影象中候選特徵點。

由於需要滿足不少於一半的連續周邊點亮於或暗於中間點,可以首先檢測水平與垂直方向上四個點,當少於兩個連續點滿足條件,則該點一定不是候選特徵點。如此可以提升計算效率。

當完成候選特徵點掃描後,會發現存在許多臨近特徵點,可以使用如下評分進行非極大值抑制:

以上即為 FAST 的基本思想,opencv 實現在 cv::FastFeatureDetector 中,引數threshold 定義了亮或暗,nonmaxSuppression 確定是否排除臨近點。

2 BRIEF

BRIEF 對特徵點生成描述特徵向量。在 SIFT 與 SURF 中均使用了塊特徵描述方案,使用不同小塊的方向梯度直方圖構成特徵向量。BRIEF 使用點特徵描述特徵點,基本思想為:

1)在特徵點區域內隨機生成 N 個點對,這N個點對生成方式有很多種,但一旦生成,對於所有特徵點描述均使用相同的點對模式;

2)由於需要對孤立點進行比較,所以首先平滑影象以抑制噪聲;

3)構造 N 位向量,第 k 個點對生成第 k 位向量,當點對中前一個點大於後一個點,其值為 1,反之為 0;

opencv 實現在cv::BriefDescriptorExtractor 中,引數 bytes 確定特徵點描述向量長度為 bytes * 8。

結合 FAST 與 BRIEF,可以實現類似 SIFT 與 SURF 的功能,以下給出簡單使用程式碼:

 1 cv::FastFeatureDetector detector(20);
 2 std::vector<cv::KeyPoint> keypoints1, keypoints2;
3 detector.detect(img1, keypoints1); 4 detector.detect(img2, keypoints2); 5 6 cv::BriefDescriptorExtractor brief; 7 cv::Mat descriptors1, descriptors2; 8 brief.compute(img1, keypoints1, descriptors1); 9 brief.compute(img2, keypoints2, descriptors2); 10 11 // 不同於SIFT與SURF,這裡使用漢明距離 12 cv::BFMatcher matcher(cv::NORM_HAMMING); 13 std::vector<DMatch> matches; 14 matcher.match(descriptors1, descriptors2, matches);

其匹配結果如下:

3 ORB

ORB 主要思想如下:

1)使用 FAST 提取候選特徵點;

2)為了克服 FAST 可能產生的邊緣響應,使用 Harris corner measure 保留角點響應,剔除邊緣響應(邊緣響應不利於匹配);

3)按以上方法在不同層級影象金字塔上搜索候選特徵點;

4)使用歸一化影象描述特徵點方向;

5)使用特徵點方向生成 BRIEF 特徵點描述向量;

6)使用漢明距離計算特徵點之間相似度;

opencv 提供 cv::ORB 實現特徵點提取與描述,其建構函式引數如下:

nfeatures 表示需要提取的特徵點數量;

scaleFactor,nlevels 為影象金字塔引數;

firstLevel 表示從第幾層開始搜尋特徵點,一般為 0;

patchSize 確定特徵點尺寸,edgeThreshold 應不小於patchSize,該引數忽略邊界特徵點;

scoreType 確定使用 FAST 評分機制或者 Harris corner 評分機制;

WTA_K 控制比較點個數,當為 2 時,即為 FAST 對點對比較方式;

以下給出簡單使用程式碼:

 1 cv::Mat img1 = cv::imread("a.bmp", cv::IMREAD_GRAYSCALE);
 2 cv::Mat img2 = cv::imread("b.bmp", cv::IMREAD_GRAYSCALE);
 3 
 4 std::vector<cv::KeyPoint> keypoints1, keypoints2;
 5 cv::Mat descriptors1, descriptors2;
 6 
 7 cv::ORB orb(100, 1.5, 4);
 8 orb.operator()(img1, cv::noArray(), keypoints1, descriptors1);
 9     orb.operator()(img2, cv::noArray(), keypoints2, descriptors2);
10 
11 cv::BFMatcher matcher(cv::NORM_HAMMING);
12 std::vector<DMatch> matches;
13 matcher.match(descriptors1, descriptors2, matches);
14 
15 cv::Mat img_matches;
16 cv::drawMatches(img1, keypoints1, img2, keypoints2, matches, img_matches);
17 cv::imwrite("c.jpg", img_matches);
18 
19 double min_dist = 100;
20 
21 for (int i = 0; i < matches.size(); i++)
22 {
23     double dist = matches[i].distance;
24     if (dist < min_dist) min_dist = dist;
25         
26 }
27 
28 // Draw only "good" matches (i.e. whose distance is less than 2*min_dist,
29 // or a small arbitary value ( 0.02 ) 
30 std::vector< DMatch > good_matches;
31 
32 for (int i = 0; i < matches.size(); i++)
33 {
34     if (matches[i].distance <= max(2 * min_dist, 0.02))
35     {
36         good_matches.push_back(matches[i]);
37     }
38 }
39 
40 cv::drawMatches(img1, keypoints1, img2, keypoints2, good_matches, img_matches);
41 cv::imwrite("d.jpg", img_matches)

其匹配結果如下:

參考資料Learning OpenCV 3 Adrian Kaehler & Gary Bradski