cornerHarris函数对于每一个像素(x,y)在blockSize x blockSize 邻域内,计算2x2梯度的协方差矩阵M(x,y)。就可以找出输出图中的局部最大值,即找出了角点。
void cornerHarris( InputArray src, OutputArray dst, int block Size, int ksize, double k, int borderType = BORDER_DEFAULT)
1.InputArray类型的src,输入图像,即原图像,填Mat类型即可,且需要为单通道8位或者浮点型图像;
2.OutputArray类型的dst,函数调用后的运算结果存在这里,即这个参数用于存放Harris角点检测的输出结果,和原图片有一样的尺寸和类型;
3.int类型的blockSize,表示邻域的大小,更多详细信息在cornerEigenValsAndVecs()中讲到;
4.int类型的ksize,表示Sobel()算子的孔径的大小;
5.double类型的k,Harris参数;
6.int类型的borderType,图像像素的边界模式。注意它有默认值BORDER_DEFAULT;
#include <opencv2/opencv.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> using namespace cv; #define WINDOW_NAME1 "窗口1" #define WINDOW_NAME2 "窗口2" Mat g_srcImage, g_srcImage1, g_grayImage; int g_nThresh = 30; //当前阀值 int g_nMaxThresh = 175; void on_fCornerHarris(int, void*) { Mat dstImage; //目标图 Mat normImage; //归一化后的图 Mat scaledImage; //线性变换后的八位无符号整形的图 // 置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值 dstImage = Mat::zeros(g_srcImage.size(), CV_32FC1); g_srcImage1 = g_srcImage.clone(); //角点检测 cornerHarris(g_grayImage, dstImage, 2, 3, 0.04, BORDER_DEFAULT); normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat()); //将归一化后的图线性变换成8位无符号整形 convertScaleAbs(normImage, scaledImage); //将检测到的,且符合阀值条件的角点绘制出来 for (int i = 0; i < normImage.rows; i++) { for (int j = 0; j < normImage.cols; j++) { if ((int)normImage.at<float>(i, j) > g_nThresh + 80) { circle(g_srcImage1, Point(j, i), 5, Scalar(10, 10, 255), 2, 8, 0); circle(scaledImage, Point(j, i), 5, Scalar(0, 10, 255), 2, 8, 0); } } } imshow(WINDOW_NAME1, g_srcImage1); imshow(WINDOW_NAME2, scaledImage); } int main() { g_srcImage = imread("fangzi.jpg"); g_srcImage.copyTo(g_srcImage1); cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY); namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE); createTrackbar("阀值:", WINDOW_NAME1, &g_nThresh, g_nMaxThresh, on_fCornerHarris); on_fCornerHarris(0, NULL); waitKey(0); return 0; }
在原图中:
在二值图中:
Shi-Tomasi角点检测是Harris角点检测算法的改进,见下文: