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(y, x + 1) - image.at(y, x - 1);
	dx[1] = (int)image.at(y, x + 2) - image.at(y, x);
	dx[2] = (int)image.at(y + 1, x + 1) - image.at(y + 1, x - 1);
	dx[3] = (int)image.at(y + 1, x + 2) - image.at(y + 1, x);

	int dy[4];
	dy[0] = (int)image.at(y + 1, x) - image.at(y - 1, x);
	dy[1] = (int)image.at(y + 1, x + 1) - image.at(y - 1, x + 1);
	dy[2] = (int)image.at(y + 2, x) - image.at(y, x);
	dy[3] = (int)image.at(y + 2, x + 1) - image.at(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

你可能感兴趣的:(C/C++基础)