Opencv2系列學習筆記5(檢測Harris角點)

在計算機視覺中,興趣點(也叫關鍵點或者特徵點)的概念被大量用於解決物體識別、圖像匹配、視覺跟蹤、三維重建等問題。它依賴於這個想法,即不再觀察整副圖像,而是選擇某些特殊的點,然後對它們執行局部分析。如果能檢測到足夠多的這種點,同時它們的區分度很高,並且可以精確定位穩定的特徵,那麼這個方法就很有效。

Harris角點的理論部分見opencv1的這篇blog:http://blog.csdn.net/lu597203933/article/details/15088485。 下面闡述opencv2中如何進行harris角點檢測和極大值抑制。

一:harris角點檢測

Code:   

  1. int main()  
  2. {  
  3.     Mat image = imread("F:\\huangrong.jpg", 0);  
  4.     if(!image.data)  
  5.     {  
  6.         cout << "Fail to load image" << endl;  
  7.         return 0;  
  8.     }  
  9.     Mat cornerStrength;  
  10.     int blockSize = 2;       //   
  11.     int kSize = 3;    // the size of sobel kernel  
  12.     cornerHarris(image, cornerStrength, blockSize, kSize, 0.01);  // 計算的結果爲由公式得到的分數  
  13.     //  二值化  
  14.     Mat harrisCorner;  
  15.     double thresh = 0.00001;  
  16.     threshold(cornerStrength, harrisCorner, thresh, 255, THRESH_BINARY_INV);  
  17.     namedWindow("image");  
  18.     imshow("image", image);  
  19.     namedWindow("cornerStrength");  
  20.     imshow("cornerStrength", cornerStrength);  
  21.     namedWindow("harrisCorner");  
  22.     imshow("harrisCorner", harrisCorner);  
  23.     waitKey(0);  
  24.     return 0;  
  25. }  

Explaination:

<1>opencv2中使用cornerHarris(InputArray src, OutputArray dst, int blockSize,int ksize, double k, int borderType=BORDER_DEFAULT );

    第一個參數: 輸入源圖像

    第二個參數:輸出 用於保存計算得到的得分

    第三個參數:相鄰像素尺寸

    第四個:sobel運算核大小

    第五:公式中的參數

<2>二值化函數threshold( InputArray src, OutputArray dst,doublethresh,double maxval, inttype );

Result:

 

二:極大值抑制

以上獲取到的角點圖像包含許多角點羣,所以需要極大值抑制。我們使用膨脹函數dilate和比較compare運算來進行抑制

主要思想是通過dilate和compare這兩個函數得到極大值點所對應的標識,後將二值化的得分值與標識進行與運算即bitwise_and 函數。具體解釋見代碼註釋。

Code:

HarrisDetector.h

  1. class HarrisDetector{  
  2. private:  
  3.     // 表示角點強度的32位浮點圖像  
  4.     Mat cornerStrength;  
  5.     // 表示閥值后角度的32位浮點圖像  
  6.     Mat cornerTh;  
  7.     //  局部極大值圖像(內部)--標識  
  8.     Mat localMax;  
  9.     int neighbourhood;  
  10.     int aperture;   // the size of the sobel kernel  
  11.     double k;     
  12.     //閥值  
  13.     double thre;           //  閥值  
  14.   
  15. public:  
  16.     HarrisDetector():neighbourhood(2),aperture(3), k(0.01),   
  17.         thre(0.00001){  
  18.         //setLocalMaxWindowSize(nonMaxSize);  
  19.     }  
  20.     void detect(Mat &image);    // 得到局部範圍內的極大值點所對應的標識  
  21.     Mat getCornerMap();              //得到局部極大值  
  22.     void getCorners(vector<Point> &points);   //將局部極大值點push入vector中  
  23.     void drawOnImage(Mat &image, vector<Point> &points);  
  24. };  
  25.   
  26. void HarrisDetector::detect(Mat &image){   // 通過膨脹和比較得到局部極大值點所對應的標識。。  
  27.     cornerHarris(image, cornerStrength, neighbourhood, aperture, k);  
  28.     Mat dilated;  
  29.     //膨脹運算替換每個像素值爲相鄰範圍內的最大值,只有局部極大值的點纔會保留原樣  
  30.     dilate(cornerStrength, dilated, Mat());     // 膨脹操作  
  31.     compare(cornerStrength, dilated, localMax, CMP_EQ);    // 對應點是否相等進行比較 是則爲255,否則爲0  
  32. }  
  33.   
  34. Mat HarrisDetector::getCornerMap()         // 二值化後通過與操作得到抑制後得極大值 ===角點  
  35. {  
  36.     Mat cornerMap;  
  37.     // 對角點圖像進行閥值化  
  38.     threshold(cornerStrength, cornerTh, thre, 255, THRESH_BINARY);  
  39.     // 轉換爲8位圖像。。  
  40.     cornerTh.convertTo(cornerMap, CV_8U);  
  41.     // 非極大值抑制  
  42.     bitwise_and(cornerMap, localMax, cornerMap);  
  43.     return cornerMap;  
  44. }  
  45. void HarrisDetector::getCorners(vector<Point> &points)   // 將極大值點所對應的points放入  
  46. {  
  47.     Mat cornerMap = getCornerMap();  
  48.     for(int y = 0; y < cornerMap.rows; y++)  
  49.     {  
  50.         uchar *cornerPtr = cornerMap.ptr<uchar>(y);      // 遍歷所有的特徵點  
  51.         for(int x = 0; x < cornerMap.cols; x++)  
  52.         {  
  53.             if(cornerPtr[x]){  
  54.                 points.push_back(Point(x, y));  
  55.             }  
  56.         }  
  57.     }  
  58. }  
  59.   
  60. void HarrisDetector::drawOnImage(Mat &image, vector<Point> &points)  
  61. {  
  62.     int radius = 3, thickness = 2;  
  63.     vector<Point>::iterator it = points.begin();  
  64.     // 對於所有角點  
  65.     while(it!= points.end())  
  66.     {  
  67.         // 繪製一個圓  
  68.         circle(image, *it, radius, Scalar(255,255,255), thickness);  
  69.         it ++;  
  70.     }  
  71. }  

main.cpp:

  1. Mat image = imread("F:\\huangrong.jpg", 0);  
  2.     vector<Point> points;  
  3.     HarrisDetector hdetector;  
  4.     hdetector.detect(image);          //// 通過膨脹和比較得到局部極大值點所對應的標識。。  
  5.     hdetector.getCorners(points);        // 得到極大值並將極大值點所對應的points放入  
  6.     cout << points.size()<< endl;  
  7.     hdetector.drawOnImage(image, points);<span style="font-family: Arial, Helvetica, sans-serif; background-color: rgb(255, 255, 255);">    </span>  

Result:


三:適合跟蹤的優質特徵

Opencv2自帶了goodFeaturesToTrack這個函數,用於解決特徵點聚類問題,除了引入局部極大值的條件,特徵點傾向於在圖像中不均勻分佈,集中在在紋理豐富的部分。該函數的具體解釋見代碼註釋。

Code:

  1. /*1:將cornerHarris函數得到的得分進行降序排列,依次取爲角點,數量不超過100個,兩個角點之間的距離要大於10。。 
  2.     效果:解決了特徵點聚類問題,此外特徵點傾向於在圖像中均勻分佈。 
  3.     */  
  4.     goodFeaturesToTrack(image, points, 100, 0.01, 10);  // 0.01 爲質量等級  
  5.     cout << points.size() << endl;  

此外cv:: goodFeaturesToTrack函數擁有一個封裝類cv::GoodFeaturesToTrackDetector,他繼承自抽象類FeatureDetector類。下面代碼實現功能和上面一樣。

Code:

  1. /*2:與1的效果是一樣的,只是goodFeaturesToTrack函數擁有一個封裝類GoodsFeaturesToTrackDetector,*/  
  2.     Mat result;  
  3.     vector<KeyPoint> keypoints;   // 特徵點向量  
  4.     GoodFeaturesToTrackDetector gftt(100, 0.01, 10);  // 檢測器的構造函數  
  5.     gftt.detect(image, keypoints);          // 檢測  
  6.     drawKeypoints(image, keypoints, result);  
作者:小村長  出處:http://blog.csdn.net/lu597203933 歡迎轉載或分享,但請務必聲明文章出處。 (新浪微博:小村長zack, 歡迎交流!)
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章