1. 程式人生 > >Harris角點檢測的實現(cv::Mat && c++)

Harris角點檢測的實現(cv::Mat && c++)

原文連結或Google “A COMBINED CORNER AND EDGE DETECTOR”可以找到Harris角點檢測的論文。

簡單的概括一下,Harris角點檢測的原理為,通過計算論文中的R來判斷某一個畫素點是否為角點,通常情況下,當R為正數且較大時,該點為角點。若R為負數且絕對值較大時,該點為邊緣點。若R的絕對值較小,則該點通常位於光滑區域。

計算R需要兩個基本量,一個為dx,另一個為dy,通常情況下,我們會計算畫素點所在的視窗內(我的程式碼中採用了2*2的區域)所有畫素點的梯度,然後進行第二步的計算。在程式碼中,x方向的梯度為dx[4],y方向的梯度為dy[4]。

得到梯度後,我們需要計算論文中的A,B,C

A=\sum \left ( dx^{2} \right )

B=\sum \left ( dy^{2} \right )

C=\sum \left ( dx*dy \right )

至此我們將得到論文中的M=$$\left[ \begin{matrix} A & C \\ C & B \end{matrix}\right] \tag{1} $$

下面我們將計算R,根據線性代數的基本公式,我們可以得到

R=A*B-C^{2}-k(A+B)^{2},其中,k的取值通常為0.04~0.06(k越小,Harris運算元越敏感)。得到R之後,我們便可以找到角點。然後通過非極大值抑制(Non-maximal Suppression)的方法,避免角點過於密集的出現。

程式碼為Harris角點響應值計算

double Harris(const cv::Mat& image, int x, int y) {
	int A, B, C;
	int dx[4];
	// 0 1
	// 2 3
	dx[0] = (int)image.at<uchar>(y, x + 1) - image.at<uchar>(y, x - 1);
	dx[1] = (int)image.at<uchar>(y, x + 2) - image.at<uchar>(y, x);
	dx[2] = (int)image.at<uchar>(y + 1, x + 1) - image.at<uchar>(y + 1, x - 1);
	dx[3] = (int)image.at<uchar>(y + 1, x + 2) - image.at<uchar>(y + 1, x);

	int dy[4];
	dy[0] = (int)image.at<uchar>(y + 1, x) - image.at<uchar>(y - 1, x);
	dy[1] = (int)image.at<uchar>(y + 1, x + 1) - image.at<uchar>(y - 1, x + 1);
	dy[2] = (int)image.at<uchar>(y + 2, x) - image.at<uchar>(y, x);
	dy[3] = (int)image.at<uchar>(y + 2, x + 1) - image.at<uchar>(y, x + 1);

	A = dx[0] * dx[0] + dx[1] * dx[1] + dx[2] * dx[2] + dx[3] * dx[3];
	B = dy[0] * dy[0] + dy[1] * dy[1] + dy[2] * dy[2] + dy[3] * dy[3];
	C = dx[0] * dy[0] + dx[1] * dy[1] + dx[2] * dy[2] + dx[3] * dy[3];

	return A * B - C * C -0.04 * (A + B) * (A + B);
}

非極大值抑制的可以採用只保留某一個視窗內Harris響應值最大的點進行處理,在此不貼程式碼了。

注:萬不可偷懶只求一個點的dx和dy,否則得到的值恆為負數,因為A*B-C^{2}=0