Harris 角点检测c++源码实现

特征检测

1. Harris 角点检测


 

 

文章目录

  • 系列文章目录
  • 前言
  • 一、Harris角点检测原理
  • 二、C++源码实现
  • 三、程序执行结果
  • 总结
  • 参考文档

 


前言

最近复习了Harris角点检测算法原理,这里做下学习笔记。


 

一、Harris角点检测原理

当滑动窗口沿任意方向进行微小移动,窗口内响应函数值都有剧烈变化,我们称这样的点为角点。另外,当滑动窗口沿某一方向进行微小移动, 窗口内响应函数值有剧烈变化(边缘点),沿其他方向则变化微小(平坦区域点)。

响应函数:

E(\Delta x,\Delta y) = \sum_{(x,y)\euro W}^{}w(x,y) * (I(x+\Delta x, y+\Delta y) - I(x,y))^{2}

E(\Delta x,\Delta y)\cong \begin{pmatrix} \Delta x & \Delta y \end{pmatrix} M \begin{pmatrix} \Delta x\\ \Delta y \end{pmatrix} = A * \Delta x^{2} + C*\Delta x*\Delta y + B * \Delta y^{2}

M=\sum_{(x,y)\epsilon W}^{}w(x,y) * \begin{pmatrix} _{_{I_x^{2}}} & _{I_x{}I_y{}} \\ _{I_x{}I_y{}} & _{_{I_y^{2}}} \end{pmatrix}

通过对M进行响应函数计算来判断是否为角点:

R = det(M) - k(trace(M)^{2})

Harris 角点检测c++源码实现_第1张图片

二、C++源码实现

int Sample_MyHarrisBlock::Run()
{
	bool	bStatus = true;
	long	debug = 0;
	long	kernelSize = 3;
	long	windowSize = 3;
	double	k = 0.04;
	double	threshold = 0.01;
	long	nms = 0;
	long	bResize = 0;
	long	resize_h = 0;
	long	resize_w = 0;

	GetValue("Debug", debug);

	Mat* pSrcImg = NULL;
	GetValue("src image", pSrcImg);

	if (pSrcImg == NULL)
	{
		LOG_ERROR(BLOCK_SAMPLE_TEXTDETECTORSWT, "src image is null!");
		goto ERR_EXIT;
	}

	GetValue("kernel size", kernelSize);
	GetValue("window size", windowSize);
	GetValue("threshold", threshold);
	//GetValue("nms", (long&)nms);
	GetValue("k", k);
	GetValue("resize", (long&)bResize);
	GetValue("resize_h", resize_h);
	GetValue("resize_w", resize_w);

	{
		/*
		E = sum(w(x,y)*(I(x+u, y+v) - I(x,y))^2)), (x, y) in slide window

		E = [u, v] M [u, v]T

		M = sum(w(x,y)*[Ix^2 IxIy\n IxIy Iy^2])

		R = det(M) - k(trace(M))^2,

		if R(x, y) > threshold * max(R), then corner point
		*/
		Mat gray;
		if (pSrcImg->channels() == 3)
			cvtColor(*pSrcImg, gray, COLOR_BGR2GRAY);
		else
			gray = pSrcImg->clone();

		Mat src;
		if (bResize == 1)
		{
			resize(*pSrcImg, src, Size(resize_w, resize_h));
			resize(gray, gray, Size(resize_w, resize_h));
		}
		else
		{
			src = pSrcImg->clone();
		}

		//1. calculate Ix, Iy by soble x, y

		Mat I_x;
		Mat I_y;
		Sobel(gray, I_x, CV_32FC1, 1, 0, kernelSize);
		Sobel(gray, I_y, CV_32FC1, 0, 1, kernelSize);

		//2. calculate Ixx, Ixy, Iyy

		Mat I_xx, I_yy, I_xy;
		I_xx = Mat(I_x.size(), CV_32FC1);
		I_yy = Mat(I_y.size(), CV_32FC1);
		I_xy = Mat(I_x.size(), CV_32FC1);
		for (int row = 0; row < I_x.rows; row++)
		{
			for (int col = 0; col < I_x.cols; col++)
			{
				I_xx.at(row, col) = I_x.at(row, col) * I_x.at(row, col);
				I_xy.at(row, col) = I_x.at(row, col) * I_y.at(row, col);
				I_yy.at(row, col) = I_y.at(row, col) * I_y.at(row, col);
			}
		}

		//3. calculate weighted Ixx, Ixy, Iyy by Gaussian function, sigmaX=2
		Mat gauss_Ixx, gauss_Iyy, gauss_Ixy;
		GaussianBlur(I_xx, gauss_Ixx, Size(kernelSize, kernelSize), 2);
		GaussianBlur(I_xy, gauss_Ixy, Size(kernelSize, kernelSize), 2);
		GaussianBlur(I_yy, gauss_Iyy, Size(kernelSize, kernelSize), 2);
		
		//4. calculate R: R = det(M) - k * trace(M)^2
		std::vector> M;
		Mat R = Mat(I_xx.size(), CV_32FC1);
		for (int row = 0; row < gauss_Ixx.rows; row++)
		{
			for (int col = 0; col < gauss_Ixx.cols; col++)
			{
				Mat temp = Mat(2,2, CV_32FC1);
				temp.at(0, 0) = gauss_Ixx.at(row, col);
				temp.at(0, 1) = gauss_Ixy.at(row, col);
				temp.at(1, 0) = gauss_Ixy.at(row, col);
				temp.at(1, 1) = gauss_Iyy.at(row, col);

				double d = determinant(temp);
				Scalar t = trace(temp);

				R.at(row, col) = d - k * t[0] * t[0];
			}
		}

		//5. filter corner point by threshold: R(x,y) > threshold * maxR;
		double minR = DBL_MAX, maxR = DBL_MIN;
		minMaxLoc(R, &minR, &maxR);

		Mat result;
		if (src.channels() == 3)
		{
			result = src.clone();
		}
		else
		{
			std::vector srcs = { src, src, src };
			merge(srcs, result);
		}

		for (int row = 0; row < result.rows; row++)
		{
			for (int col = 0; col < result.cols; col++)
			{
				if (R.at(row, col) > threshold * maxR)
				{
					result.at(row, col) = Vec3b(0, 0, 255);
				}
			}
		}
			
		Mat* pDstImg = new Mat(result);
		if (!pDstImg->empty())
		{
			SetValue("Dst Image", pDstImg);
			goto EXIT;
		}

	}


ERR_EXIT:
	bStatus = false;

EXIT:

	SetValue("Status", (long)bStatus);

	return bStatus;
}

三、程序执行结果

参数设置:

Harris 角点检测c++源码实现_第2张图片

运行结果:

Harris 角点检测c++源码实现_第3张图片


总结

本文没有对原理进行仔细介绍,网上有很多,大家可以自行搜索,或是查看参考博文。

本文代码截取自个人软件部分源码,无法直接运行,需要对代码中图像读取以及参数读取部分进行修改, 谢谢!

 

参考文档

https://www.cnblogs.com/zyly/p/9508131.html#_label4

你可能感兴趣的:(opencv,计算机视觉,c++)