#图像处理_OpenCV# Harris角点检测原理及C++实现

1.Harris角点
1.1基本定义
首先,什么是角点,角点是指一个边缘轮廓的一角。角点可以在一个物体的边缘处,但是边缘不同于角点,简单来说角点就是同时是边缘和角的点。
1.2判断依据
计算机完成角点检测是通过一个小窗口逐步扫描过去来完成的,在移动过程中的灰度的变换则作为判断角点的依据:
①.当检测窗口移动时,灰度几乎没有发生变化 ->认为是“平整地带”;
②.当检测窗口移动时,灰度只在一个方向上发生突变 ->认为是“边缘地带”;
③.当检测窗口移动时,灰度在各个方向上均发生突变 ->认为是“角点地带”;
1.3数学推导
#图像处理_OpenCV# Harris角点检测原理及C++实现_第1张图片
E(u,v)具体含义我也不知道,可以理解为沿着某个方向的变化大小的期望,配合之前的解释,沿着多个方向若灰度变化都很大则定义为角点。
化成矩阵的形式后记 M2 = [A, C; C, B]
A 是 图像在x方向上的二次偏导数;
B 是 图像在y方向上的二次偏导数;
C 是 图像在xy方向上的梯度乘积;
为了求A , C ,B我们需要首先计算两个方向上的梯度;梯度的计算表可以用sobel算子等相关算子进行计算。
这里需要注意的一点是,为了将中心像素对周围像素的影像考虑进来,对于求得的M2矩阵进行高斯滤波可以改善,最终得到M矩阵。
#图像处理_OpenCV# Harris角点检测原理及C++实现_第2张图片
#图像处理_OpenCV# Harris角点检测原理及C++实现_第3张图片
对于M矩阵特征值的判断来得出结论如下,
图像中的直线:一个特征值大,另一个特征值小,λ1≫λ2或λ2≫λ1。自相关函数值在某一方向上大,在其他方向上小。
图像中的平面:两个特征值都小,且近似相等;自相关函数数值在各个方向上都小。
图像中的角点:两个特征值都大,且近似相等,自相关函数在所有方向都增大。

1.4计算方法
得到的矩阵M并不需要直接去判断他的特征值,harris算法找到了一个更为简单的判断方式,那就是R; R = detM - k(trace(M))^2
其中:
det M = λ1λ2=A * C−B^2;
trace M = λ2 + λ2 = A + C;
k 取0.04-0.06;

角点处R为大数值正数;边缘处R为大数值复数;平坦区处R绝对值是小数值。

1.5 算法实现步骤
1.利用Soble或其他方式计算出XY方向的梯度值
2.计算出二阶偏导与梯度乘积
3.利用高斯函数对M矩阵进行滤波
4.计算局部特征结果矩阵M的特征值和响应函数R = det(M)-k(trace(M))^2 (0.04<=k<=0.06)
5.将计算出响应函数的值C进行非极大值抑制,滤除一些不是角点的点,同时要满足大于设定的阈值

2程序清单

2.1内部库函数学习
①、滑块拖动函数

    createTrackbar("Threshold", output_title, &thresh, max_count, Harris_Demo);
    Harris_Demo(0,0);

参数1:滑块名称;
参数2:滑块所在的窗口名称;
参数3:滑块改变的变量名称,注意要加 ’&‘,同样表示初始值大小;
参数4:滑块终点数字大小;
参数5:滑块操作的子函数名称,且下一行需要调用这个函数;

②、harris角点检测函数

cornerHarris(img_gray, dst, blockSize, ksize, k, BORDER_DEFAULT);

参数1:原始图像,必须是灰度;
参数2:操作后返回的图像;
参数3:blockSize特征值计算矩阵的维数 一般是2;
参数4:ksize平移扫过图像的矩阵块;
参数5:表示对图像边缘的处理,这里直接BORDER_DEFAULT表示默认;

③、像素大小标准化函数

//此处只使用了最大值最小值的标准化模式
normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());

参数1:原始图像;
参数2:操作后返回的图像;
参数3:double 类参数1 表示标准化的最小值
参数4:double 类参数2 表示标准化的最大值
参数5:标准化方式,NORM_MINMAX表示最大最小值标准化;
参数6:32位float类型数据;
参数7:我也不知道 Mat();

④、转换图像像素类型

//使用线性变换转换输入数组元素成8位无符号整型
convertScaleAbs(norm_dst, normScaleDst);;

参数1:原始图像;
参数2:操作后返回的图像;

⑤、画出一个小圆圈,在给定位置

circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);

参数1:需要画圈的操作图像;
参数2:画圈的操作位置;
参数3:圆圈半径;
参数4:画出圆圈的颜色Scalar(B,G, R)颜色配比;
参数5:内部填充,越大涂的越多,不要大于参数3;
参数6:按照默认;
参数7:按照默认;

⑥、指针操作遍历整个图像

for (int row = 0; row < resultImg.rows; row++) {
		//定义每一行的指针
		uchar* currentRow = normScaleDst.ptr(row);//表示了行指针的开始
		for (int col = 0; col < resultImg.cols; col++) {
			int value = (int)*currentRow;	//第一次默认指针的第一列
			...
			...
			...
			currentRow++;					//+1之后向下一列进发
		}
	}

2.2整体程序

#include 
#include 
#include 

using namespace std;
using namespace cv;

int thresh = 130;
int max_count = 255;
Mat img, img_gray;
const char* output_title = "Harris Corner Dectction Result";
void Harris_Demo(int, void *);

int main(int argv, char** argc) {
	img = imread("E:/OpenCV/image/home.jpg");
	if (img.empty()) {
		printf("colud not load image...");
		return -1;
	}
	namedWindow("input image", CV_WINDOW_AUTOSIZE);
	imshow("input image", img);
	//以上是图像处理的标准开头
	namedWindow(output_title, CV_WINDOW_AUTOSIZE);
	cvtColor(img, img_gray, CV_BGR2GRAY);

	createTrackbar("Threshold", output_title, &thresh, max_count, Harris_Demo);
	Harris_Demo(0, 0);

	waitKey(0);
	return 0;
}

void Harris_Demo(int, void *) {

	Mat dst, norm_dst, normScaleDst;
	dst = Mat::zeros(img_gray.size(), CV_32FC1);
	//harris角点核心函数
	int blockSize = 2;
	int ksize = 3;
	int k = 0.04;

	cornerHarris(img_gray, dst, blockSize, ksize, k, BORDER_DEFAULT);
	//上述输出的取值范围并不是0-255 需要按照最大最小值进行归一化
	normalize(dst, norm_dst, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
	convertScaleAbs(norm_dst, normScaleDst);

	Mat resultImg = img.clone();
	//用彩色来显示
	for (int row = 0; row < resultImg.rows; row++) {
		//定义每一行的指针
		uchar* currentRow = normScaleDst.ptr(row);
		for (int col = 0; col < resultImg.cols; col++) {
			int value = (int)*currentRow;
			if (value > thresh) {
				circle(resultImg, Point(col, row), 2, Scalar(0, 0, 255), 2, 8, 0);
			}
			currentRow++;
		}
	}

	imshow(output_title, resultImg);
}

3结果
#图像处理_OpenCV# Harris角点检测原理及C++实现_第4张图片

纯属个人学习总结 ,有问题请指正,谢谢

你可能感兴趣的:(OpenCV)