原文链接或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
至此我们将得到论文中的
下面我们将计算R,根据线性代数的基本公式,我们可以得到
,其中,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,否则得到的值恒为负数,因为=0