1. 程式人生 > >Opencv學習筆記(五)Harris角點檢測

Opencv學習筆記(五)Harris角點檢測

文章目錄:

一、Harris角點檢測基本理論

二、opencv程式碼實現

三、改進的Harris角點檢測

四、FAST角點檢測

五、參考文獻

六、附錄(資料和原始碼)

一、Harris角點檢測基本理論(要講清楚東西太多,附錄提供文件詳細說明)

1.1 簡略表達:

角點:最直觀的印象就是在水平、豎直兩個方向上變化均較大的點,即Ix、Iy都較大 
邊緣:僅在水平、或者僅在豎直方向有較大的變化量,即Ix和Iy只有其一較大 
平坦地區:在水平、豎直方向的變化量均較小,即Ix、Iy都較小


角點響應

R=det(M)-k*(trace(M)^2)   (附錄資料給出k=0.04~0.06,opencv指出是0.05-0.5,浮動較大)

det(M)=λ1*λ2      trace(M)=λ1+λ2

R取決於M的特徵值,對於角點|R|很大,平坦的區域|R|很小,邊緣的R為負值。

1.2 詳細描述:見附錄裡的ppt

1.3 演算法步驟


其中,區域性極大值可用先膨脹後與原圖比較的方法求得,具體見二中原始碼。

二、opencv程式碼實現

harris類

#ifndef HARRIS_H
#define HARRIS_H
#include "opencv2/opencv.hpp"

class harris
{
private:
    cv::Mat  cornerStrength;  //opencv harris函式檢測結果,也就是每個畫素的角點響應函式值
    cv::Mat cornerTh; //cornerStrength閾值化的結果
    cv::Mat localMax; //區域性最大值結果
    int neighbourhood; //鄰域視窗大小
    int aperture;//sobel邊緣檢測視窗大小(sobel獲取各畫素點x,y方向的灰度導數)
    double k;
    double maxStrength;//角點響應函式最大值
    double threshold;//閾值除去響應小的值
    int nonMaxSize;//這裡採用預設的3,就是最大值抑制的鄰域視窗大小
    cv::Mat kernel;//最大值抑制的核,這裡也就是膨脹用到的核
public:
    harris():neighbourhood(3),aperture(3),k(0.01),maxStrength(0.0),threshold(0.01),nonMaxSize(3){

    };

    void setLocalMaxWindowsize(int nonMaxSize){
        this->nonMaxSize = nonMaxSize;
    };

    //計算角點響應函式以及非最大值抑制
    void detect(const cv::Mat &image){
            //opencv自帶的角點響應函式計算函式
            cv::cornerHarris (image,cornerStrength,neighbourhood,aperture,k);
            double minStrength;
            //計算最大最小響應值
            cv::minMaxLoc (cornerStrength,&minStrength,&maxStrength);

            cv::Mat dilated;
            //預設3*3核膨脹,膨脹之後,除了區域性最大值點和原來相同,其它非區域性最大值點被
            //3*3鄰域內的最大值點取代
            cv::dilate (cornerStrength,dilated,cv::Mat());
            //與原圖相比,只剩下和原圖值相同的點,這些點都是區域性最大值點,儲存到localMax
            cv::compare(cornerStrength,dilated,localMax,cv::CMP_EQ);
    }

    //獲取角點圖
    cv::Mat getCornerMap(double qualityLevel) {
            cv::Mat cornerMap;
            // 根據角點響應最大值計算閾值
            threshold= qualityLevel*maxStrength;
            cv::threshold(cornerStrength,cornerTh,
            threshold,255,cv::THRESH_BINARY);
            // 轉為8-bit圖
            cornerTh.convertTo(cornerMap,CV_8U);
            // 和區域性最大值圖與,剩下角點區域性最大值圖,即:完成非最大值抑制
            cv::bitwise_and(cornerMap,localMax,cornerMap);
            return cornerMap;
    }

    void getCorners(std::vector<cv::Point> &points,
            double qualityLevel) {
            //獲取角點圖
            cv::Mat cornerMap= getCornerMap(qualityLevel);
            // 獲取角點
            getCorners(points, cornerMap);
    }

    // 遍歷全圖,獲得角點
    void getCorners(std::vector<cv::Point> &points,
    const cv::Mat& cornerMap) {

            for( int y = 0; y < cornerMap.rows; y++ ) {
                    const uchar* rowPtr = cornerMap.ptr<uchar>(y);
                    for( int x = 0; x < cornerMap.cols; x++ ) {
                    // 非零點就是角點
                          if (rowPtr[x]) {
                                points.push_back(cv::Point(x,y));
                          }
                     }
                }
          }

    //用圈圈標記角點
    void drawOnImage(cv::Mat &image,
    const std::vector<cv::Point> &points,
            cv::Scalar color= cv::Scalar(255,255,255),
            int radius=3, int thickness=2) {
                    std::vector<cv::Point>::const_iterator it=points.begin();
                    while (it!=points.end()) {
                    // 角點處畫圈
                    cv::circle(image,*it,radius,color,thickness);
                    ++it;
            }
    }

};

#endif // HARRIS_H
相關測試程式碼:
 cv::Mat  image, image1 = cv::imread ("test.jpg");
    //灰度變換
    cv::cvtColor (image1,image,CV_BGR2GRAY);


    // 經典的harris角點方法
    harris Harris;
    // 計算角點
    Harris.detect(image);
    //獲得角點
    std::vector<cv::Point> pts;
    Harris.getCorners(pts,0.01);
    // 標記角點
    Harris.drawOnImage(image,pts);

    cv::namedWindow ("harris");
    cv::imshow ("harris",image);
    cv::waitKey (0);
    return 0;
相關測試結果:


三、改進的Harris角點檢測

    從經典的Harris角點檢測方法不難看出,該演算法的穩定性和k有關,而k是個經驗值,不好把握,浮動也有可能較大。鑑於此,改進的Harris方法()直接計算出兩個特徵值,通過比較兩個特徵值直接分類,這樣就不用計算Harris響應函數了。

    另一方面,我們不再用非極大值抑制了,而選取容忍距離:容忍距離內只有一個特徵點。
    該演算法首先選取一個具有最大   最小特徵值的點(即:max(min(e1,e2)),e1,e2是harris矩陣的特徵值)作為角點,然後依次按照最大最小特徵值順序尋找餘下的角點,當然和前一角點距離在容忍距離內的新角點唄忽略。

    opencv測試該演算法程式碼如下:

    cv::Mat  image, image1 = cv::imread ("test.jpg");
    //灰度變換
    cv::cvtColor (image1,image,CV_BGR2GRAY);
    // 改進的harris角點檢測方法
    std::vector<cv::Point> corners;
    cv::goodFeaturesToTrack(image,corners,
    200,
    //角點最大數目
    0.01,
    // 質量等級,這裡是0.01*max(min(e1,e2)),e1,e2是harris矩陣的特徵值
    10);
    // 兩個角點之間的距離容忍度
    harris().drawOnImage(image,corners);//標記角點
    測試結果如下:

四、FAST角點檢測

    演算法原理比較簡單,但實時性很強。

    該演算法的角點定義為:若某畫素點圓形鄰域圓周上有3/4的點和該畫素點不同(程式設計時不超過某閾值th),則認為該點就是候選角點。opencv更極端,選用半徑為3的圓周上(上下左右)四個點,若超過三個點和該畫素點不同,則該點為候選角點。

    和Harris演算法類似,該演算法需要非極大值抑制。

opencv程式碼:

    cv::Mat  image, image1 = cv::imread ("test.jpg");
    cv::cvtColor (image1,image,CV_BGR2GRAY);
    //快速角點檢測
    std::vector<cv::KeyPoint> keypoints;
    cv::FastFeatureDetector fast(40,true);
    fast .detect (image,keypoints);
    cv::drawKeypoints (image,keypoints,image,cv::Scalar::all(255),cv::DrawMatchesFlags::DRAW_OVER_OUTIMG);


測試結果如下:


五、參考文獻

【1】The classical article describing the Harris operator: C. Harris and M.J. Stephens, A combined  corner and edge detector, by Alvey Vision Conference, pp. 147–152, 1988.

【2】The article by J. Shi and C. Tomasi, Good features to track, Int. Conference on Computer Vision  and Pattern Recognition, pp. 593-600, 1994 which introduced these features.

【3】The article by K. Mikolajczyk and C. Schmid, Scale and Affine invariant interest point  detectors, International Journal of Computer Vision, vol 60, no 1, pp. 63-86, 2004, which proposes a multi-scale and affine-invariant Harris operator.

【4】The article by E. Rosten and T. Drummond, Machine learning for high-speed corner detection, in In European Conference on Computer Vision, pp. 430-443, 2006 that describes the FAST feature algorithm in detail

六、附錄

我傳的資源連結,原始碼和相關文件。