OpenCV3入門(十二)角點檢測

1、角點介紹

角點檢測(Corner Detection)是電腦視覺系統中用來獲得影像特徵的一種方法,廣泛應用於運動檢測、影像匹配、影片跟蹤、三維建模和目標識別等領域中,也稱為特徵點檢測。在影像中角點是一個重要的局部特徵,它決定了影像中關鍵區域的形狀,體現了影像中重要的特徵資訊。目前,角點檢測方法主要有2大類:

    1)基於影像邊緣輪廓特徵的方法。

    2)基於影像灰度資訊的方法。此方法主要通過計算曲率及梯度進行角點檢測,通過計算邊緣的曲率來判斷角點的存在性。典型代表有Harris演算法、Susan演算法、Moravec演算法等。

角點通常被定義為兩條邊的交點,更嚴格的說,角點的局部鄰域應該具有兩個不同區域的不同方向的邊界。而實際應用中,大多數所謂的角點檢測方法檢測的是擁有特定特徵的影像點,而不僅僅是“角點”。這些特徵點在影像中有具體的坐標,並具有某些數學特徵,如局部最大或最小灰度、某些梯度特徵等。現有的角點檢測演算法並不是都十分的健壯。很多方法都要求有大量的訓練集和冗餘數據來防止或減少錯誤特徵的出現。另外,角點檢測方法的一個很重要的評價標準是其對多幅影像中相同或相似特徵的檢測能力,並且能夠應對光照變化、影像旋轉等影像變化。

 2、Harris演算法介紹

Harris 是 Harris 和 Stephens 在 1988 年提出,專門針對 Moravec 運算元的改進版。Harris 運算元,又稱 Plessey運算元,它基於與 Moravec 相同的角點定義,即定義在各個方向上灰度值變化的點。

角點可以如下圖形象的定義,如果在各個方向上移動這個小窗口,窗口內的灰度發生了較大的變化,那麼說明窗口記憶體在角點;如果在各個方向移動,灰度幾乎不變,說明是平坦區域;如果只沿著某一個方向移動,灰度幾乎不變,說明是直線(邊緣)。

設影像窗口平移[u,v] ,產生的灰度變化為E[u,v] ,則:

 

上式中,窗口函數是一個矩形窗口或高斯窗口,它給在其中的像素加權。

我們必須使邊角檢測的函數最大化,這意味著,我們必須最大限度地利用第二個參數。

根據角點的定義,平坦區域,像素變化小,那麼上式後半部分基本接近為0;在邊緣區域,會在沿著邊緣方向上差值為一個穩定值;只有在角點處,無論向那個方向移動,都會發生變化。

根據泰勒級數展開:

那麼f(x+u, y+v)可以簡化為:

f(x+u, y+v) ≈ f(x,y) + ufx(x,y) + vfy(x,y)

Harris算式的可以寫成矩陣模式。

Harris算式可以近似得到下面的表達:

其中M為:

其中,表示 Ix 方向的梯度,表示Iy 方向的梯度,為高斯函數。矩陣的特徵值是自相關函數的一階曲率。特徵值的大小與特徵點的性質息息相關。即當兩個特徵值都比較小時,則此點可能位於平坦區,不為角點或邊界點; 當兩個特徵值一個較大、而另一個卻相對較小時,則此點位於邊界上,屬於邊界點; 當兩個特徵值均相對較大時,則此點沿任意方向的曲率都較大,為需要提取的角點。

M為梯度的協方差矩陣,在實際應用中為了能夠應用更好的編程,定義了角點響應函數R,通過判定R大小來判斷像素是否為角點。R取決於M的特徵值,對於角點|R|很大,平坦的區域|R|很小,邊緣的R為負值。Harris角點檢測演算法就是對角點響應函數R進行閾值處理:R > threshold,即提取R的局部極大值。

其中,det(M) = λ1* λ1, trace(M) =λ1+ λ1 。k是經驗參數,一般取值為0.04~0.06。

 當R為大數值正數的時候,表示為角點。如下圖所示:

3、Harris實驗

OpenCV函數原型:

C++:void cornerHarris( InputArray src, //輸入8bit單通道灰度Mat矩陣                    OutputArray dst, //保存角點檢測結果,32位單通道,大小與src相同                    int blockSize,   //滑塊窗口的尺寸、鄰域的大小                    int ksize,        //Sobel邊緣檢測濾波器大小                    double k,        //Harris中間參數,經驗值0.04~0.06                    int borderType=BORDER_DEFAULT  //插值類型                    );

測試實例:

int threshod_val = 30;  int max_threshod_val = 150;  Mat src_img;    void call_back(int, void*)  {      Mat normImage, scaledImage;      Mat Img_scr1 = src_img.clone();      Mat Img_dst = Mat::zeros(src_img.size(), CV_32FC1);        cornerHarris(src_img, Img_dst, 2, 3, 0.04, BORDER_DEFAULT); //進行角點檢測        normalize(Img_dst, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat()); // 歸一化      convertScaleAbs(normImage, scaledImage);//將歸一化後的圖線性變換成8位無符號整型        for (int i = 0; i < normImage.rows; i++)      {          for (int j = 0; j < normImage.cols; j++)          {              if ((int)normImage.at<float>(i, j) > threshod_val + 100)              {                  circle(Img_scr1, Point(j, i), 3, Scalar(0, 0, 255), 2, 8, 0);                  circle(scaledImage, Point(j, i), 3, Scalar(0, 0, 255), 2, 8, 0);              }          }        }        imshow("corner", Img_scr1);      imshow("scaledImage", scaledImage);  }    int main() {      src_img = imread("D:\WORK\5.OpenCV\LeanOpenCV\pic_src\checkerboard.png");      imshow("原圖", src_img);        cvtColor(src_img, src_img, COLOR_BGR2GRAY);      namedWindow("corner");      createTrackbar("thresh", "corner", &threshod_val, max_threshod_val, call_back);      call_back(threshod_val, 0);        waitKey(0);  }

輸出結果如下圖:

測試2:

4、參考文獻

1、A COMBINED CORNER AND EDGE DETECTOR,Chris Harris,Mike Stephens,1988

http://www.bmva.org/bmvc/1988/avc-88-023.pdf

2、Harris Corner Detection

https://opencv-python-tutroals.readthedocs.io/en/latest/py_tutorials/py_feature2d/py_features_harris/py_features_harris.html

3、Harris 角點檢測子

http://www.opencv.org.cn/opencvdoc/2.3.2/html/doc/tutorials/features2d/trackingmotion/harris_detector/harris_detector.html

4、【OpenCV入門教程之十六】OpenCV角點檢測之Harris角點檢測

https://blog.csdn.net/poem_qianmo/article/details/29356187

5、(四)OpenCV中的特徵檢測之Harris Corner檢測

https://blog.csdn.net/u014403318/article/details/80562785

6、OpenCV學習筆記(八)——Harris角度特徵從原理到實現詳解

https://blog.csdn.net/weixin_41695564/article/details/79962401

7、《OpenCV3 編程入門》,電子工業出版社,毛星雨著

8、《學習OpenCV》,清華大學出版社,Gary Bradski, Adrian kaehler著