【轉】ORB特徵提取算法

原文網址:http://blog.csdn.net/hujingshuang/article/details/46984411

簡介

        ORB的全稱是ORiented Brief,是文章ORB: an efficient alternative to SIFT or SURF中提出的一種新的角點檢測與特徵描述算法。實際上,ORB算法是將FAST角點檢測與BRIEF特徵描述結合並進行了改進。

ORB算法

        在上一篇文章《BRIEF特徵點描述算法》中,指出了BRIEF的優缺點,ORB算法就是針對BRIEF算法的缺點1、2提出來的。ORB算法分爲兩個部分:FAST特徵點檢測、BRIEF特徵描述。

FAST特徵檢測

        在文章《FAST特徵點檢測算法》中,詳細闡述了FAST算法。但該算法僅僅確定了特徵點的位置,沒有得到其他任何信息。在ORB算法中,依然採用FAST來檢測特徵點的位置,但算法進行了如下改動:(以FAST-9爲例)

1、假設在圖像中要提取N個特徵點,則降低FAST的閾值,使FAST算法檢測到的特徵點大於N;

2、在特徵點位置處,計算特徵點的Harris響應值R,取前N個響應值大的點作爲FAST特徵點(Harris角點響應計算:Harris角點檢測中的數學推導);

3、由於要解決BRIEF算法的旋轉不變性,則需要計算特徵點的主方向。

ORB中利用重心來計算,如下(其中(x,y)是特徵鄰域內的點):


atan2表示反正切,得到的θ值就是FAST特徵點的主方向。

BRIEF特徵描述

         在文章《BRIEF特徵點描述算法》種,闡述了BRIEF算法。該算法速度優勢相當明顯,但存在三個致命的缺點。針對尺度不變性,可以像SIFT算法一樣,子尺度空間構造圖像金字塔解決,此處不再說明。ORB算法主要解決前兩天缺點:噪聲敏感、旋轉不變性。

1、解決噪聲敏感問題

        BRIEF中,採用了9x9的高斯算子進行濾波,可以一定程度上解決噪聲敏感問題,但一個濾波顯然是不夠的。ORB中提出,利用積分圖像來解決:在31x31的窗口中,產生一對隨機點後,以隨機點爲中心,取5x5的子窗口,比較兩個子窗口內的像素和的大小進行二進制編碼,而非僅僅由兩個隨機點決定二進制編碼。(這一步可有積分圖像完成)

2、解決旋轉不變性

        利用FAST中求出的特徵點的主方向θ,對特徵點鄰域進行旋轉,Calonder建議先將每個塊旋轉後,再進行BRIEF描述子的提取,但這種方法代價較大。ORB算法採用的是:每一個特徵點處,對產生的256對隨機點(以256爲例),將其進行旋轉,後進行判別,再二進制編碼。如下:S表示隨機點位置(2xn的矩陣),Sθ表示旋轉後的隨機點的位置(2xn的矩陣),x1=(u1,v1)是一個座標向量,其餘雷同。n=256。


得到新的隨機點位置後,利用積分圖像進行二進制編碼,即可。

實驗

opencv代碼

  1. #include <iostream>  
  2. #include <opencv2/core/core.hpp>  
  3. #include <opencv2/highgui/highgui.hpp>  
  4. #include <opencv2/legacy/legacy.hpp>  
  5. #include <iostream>  
  6. #include <vector>  
  7.   
  8. using namespace cv;  
  9. using namespace std;  
  10. int main()  
  11. {  
  12.     Mat img_1 = imread("beaver1.png");  
  13.     Mat img_2 = imread("beaver2.png");  
  14.     if (!img_1.data || !img_2.data)  
  15.     {  
  16.         cout << "error reading images " << endl;  
  17.         return -1;  
  18.     }  
  19.   
  20.     ORB orb;  
  21.     vector<KeyPoint> keyPoints_1, keyPoints_2;  
  22.     Mat descriptors_1, descriptors_2;  
  23.   
  24.     orb(img_1, Mat(), keyPoints_1, descriptors_1);  
  25.     orb(img_2, Mat(), keyPoints_2, descriptors_2);  
  26.       
  27.     BruteForceMatcher<HammingLUT> matcher;  
  28.     vector<DMatch> matches;  
  29.     matcher.match(descriptors_1, descriptors_2, matches);  
  30.   
  31.     double max_dist = 0; double min_dist = 100;  
  32.     //-- Quick calculation of max and min distances between keypoints  
  33.     forint i = 0; i < descriptors_1.rows; i++ )  
  34.     {   
  35.         double dist = matches[i].distance;  
  36.         if( dist < min_dist ) min_dist = dist;  
  37.         if( dist > max_dist ) max_dist = dist;  
  38.     }  
  39.     printf("-- Max dist : %f \n", max_dist );  
  40.     printf("-- Min dist : %f \n", min_dist );  
  41.     //-- Draw only "good" matches (i.e. whose distance is less than 0.6*max_dist )  
  42.     //-- PS.- radiusMatch can also be used here.  
  43.     std::vector< DMatch > good_matches;  
  44.     forint i = 0; i < descriptors_1.rows; i++ )  
  45.     {   
  46.         if( matches[i].distance < 0.6*max_dist )  
  47.         {   
  48.             good_matches.push_back( matches[i]);   
  49.         }  
  50.     }  
  51.   
  52.     Mat img_matches;  
  53.     drawMatches(img_1, keyPoints_1, img_2, keyPoints_2,  
  54.         good_matches, img_matches, Scalar::all(-1), Scalar::all(-1),  
  55.         vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);  
  56.     imshow( "Match", img_matches);  
  57.     cvWaitKey();  
  58.     return 0;  
  59. }  

實驗結果

ORB源碼

在:..\opencv\sources\modules\features2d\src\orb.c中,請自行查看分析,這裏列出部分源碼:
  1. static void//計算Harris角點響應  
  2. HarrisResponses(const Mat& img, vector<KeyPoint>& pts, int blockSize, float harris_k)  
  3. {  
  4.     CV_Assert( img.type() == CV_8UC1 && blockSize*blockSize <= 2048 );  
  5.   
  6.     size_t ptidx, ptsize = pts.size();  
  7.   
  8.     const uchar* ptr00 = img.ptr<uchar>();  
  9.     int step = (int)(img.step/img.elemSize1());  
  10.     int r = blockSize/2;  
  11.   
  12.     float scale = (1 << 2) * blockSize * 255.0f;  
  13.     scale = 1.0f / scale;  
  14.     float scale_sq_sq = scale * scale * scale * scale;  
  15.   
  16.     AutoBuffer<int> ofsbuf(blockSize*blockSize);  
  17.     int* ofs = ofsbuf;  
  18.     forint i = 0; i < blockSize; i++ )  
  19.         forint j = 0; j < blockSize; j++ )  
  20.             ofs[i*blockSize + j] = (int)(i*step + j);  
  21.   
  22.     for( ptidx = 0; ptidx < ptsize; ptidx++ )  
  23.     {  
  24.         int x0 = cvRound(pts[ptidx].pt.x - r);  
  25.         int y0 = cvRound(pts[ptidx].pt.y - r);  
  26.   
  27.         const uchar* ptr0 = ptr00 + y0*step + x0;  
  28.         int a = 0, b = 0, c = 0;  
  29.   
  30.         forint k = 0; k < blockSize*blockSize; k++ )  
  31.         {  
  32.             const uchar* ptr = ptr0 + ofs[k];  
  33.             int Ix = (ptr[1] - ptr[-1])*2 + (ptr[-step+1] - ptr[-step-1]) + (ptr[step+1] - ptr[step-1]);  
  34.             int Iy = (ptr[step] - ptr[-step])*2 + (ptr[step-1] - ptr[-step-1]) + (ptr[step+1] - ptr[-step+1]);  
  35.             a += Ix*Ix;  
  36.             b += Iy*Iy;  
  37.             c += Ix*Iy;  
  38.         }  
  39.         pts[ptidx].response = ((float)a * b - (float)c * c -  
  40.                                harris_k * ((float)a + b) * ((float)a + b))*scale_sq_sq;  
  41.     }  
  42. }  
  1. //計算FAST角點的主方向  
  2. static float IC_Angle(const Mat& image, const int half_k, Point2f pt,  
  3.                       const vector<int> & u_max)  
  4. {  
  5.     int m_01 = 0, m_10 = 0;  
  6.   
  7.     const uchar* center = &image.at<uchar> (cvRound(pt.y), cvRound(pt.x));  
  8.   
  9.     // Treat the center line differently, v=0  
  10.     for (int u = -half_k; u <= half_k; ++u)  
  11.         m_10 += u * center[u];  
  12.   
  13.     // Go line by line in the circular patch  
  14.     int step = (int)image.step1();  
  15.     for (int v = 1; v <= half_k; ++v)  
  16.     {  
  17.         // Proceed over the two lines  
  18.         int v_sum = 0;  
  19.         int d = u_max[v];  
  20.         for (int u = -d; u <= d; ++u)  
  21.         {  
  22.             int val_plus = center[u + v*step], val_minus = center[u - v*step];  
  23.             v_sum += (val_plus - val_minus);  
  24.             m_10 += u * (val_plus + val_minus);  
  25.         }  
  26.         m_01 += v * v_sum;  
  27.     }  
  28.   
  29.     return fastAtan2((float)m_01, (float)m_10);  
  30. }  
  1. #define GET_VALUE(idx) \  
  2.        (x = pattern[idx].x*a - pattern[idx].y*b, \ //計算旋轉後的位置  
  3.         y = pattern[idx].x*b + pattern[idx].y*a, \  
  4.         ix = cvRound(x), \  
  5.         iy = cvRound(y), \  
  6.         *(center + iy*step + ix) )  
  1. //判決,並二進制編碼  
  2. for (int i = 0; i < dsize; ++i, pattern += 16)  
  3. {  
  4.     int t0, t1, val;  
  5.     t0 = GET_VALUE(0); t1 = GET_VALUE(1);  
  6.     val = t0 < t1;  
  7.     t0 = GET_VALUE(2); t1 = GET_VALUE(3);  
  8.     val |= (t0 < t1) << 1;  
  9.     t0 = GET_VALUE(4); t1 = GET_VALUE(5);  
  10.     val |= (t0 < t1) << 2;  
  11.     t0 = GET_VALUE(6); t1 = GET_VALUE(7);  
  12.     val |= (t0 < t1) << 3;  
  13.     t0 = GET_VALUE(8); t1 = GET_VALUE(9);  
  14.     val |= (t0 < t1) << 4;  
  15.     t0 = GET_VALUE(10); t1 = GET_VALUE(11);  
  16.     val |= (t0 < t1) << 5;  
  17.     t0 = GET_VALUE(12); t1 = GET_VALUE(13);  
  18.     val |= (t0 < t1) << 6;  
  19.     t0 = GET_VALUE(14); t1 = GET_VALUE(15);  
  20.     val |= (t0 < t1) << 7;  
  21.   
  22.     desc[i] = (uchar)val;  
  23. }  
  1. //產生512個隨機點的座標位置  
  2. static void makeRandomPattern(int patchSize, Point* pattern, int npoints)  
  3. {  
  4.     RNG rng(0x34985739); // we always start with a fixed seed,  
  5.                          // to make patterns the same on each run  
  6.     forint i = 0; i < npoints; i++ )  
  7.     {  
  8.         pattern[i].x = rng.uniform(-patchSize/2, patchSize/2+1);  
  9.         pattern[i].y = rng.uniform(-patchSize/2, patchSize/2+1);  
  10.     }  
  11. }  

總結

ORB算法利用了FAST檢測特徵點的快,BRIEF特徵描述子的簡單和快,二者結合並進行了改進,導致ORB算法的又好又快。

參考文獻

1、ORB: an efficient alternative to SIFT or SURF[J],IEEE International Conference on Computer Vision,2011.

2、基於ORB和改進RANSAC算法的圖像拼接技術[J],2015.

3、基於ORB特徵的目標檢測與跟蹤的研究[碩士論文],2013.

4、基於背景差分與ORB算法的運動目標檢測與跟蹤算法研究[碩士論文],2014.
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章