1. Harris 角点检测
最近复习了Harris角点检测算法原理,这里做下学习笔记。
当滑动窗口沿任意方向进行微小移动,窗口内响应函数值都有剧烈变化,我们称这样的点为角点。另外,当滑动窗口沿某一方向进行微小移动, 窗口内响应函数值有剧烈变化(边缘点),沿其他方向则变化微小(平坦区域点)。
响应函数:
通过对M进行响应函数计算来判断是否为角点:
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;
}
参数设置:
运行结果:
本文没有对原理进行仔细介绍,网上有很多,大家可以自行搜索,或是查看参考博文。
本文代码截取自个人软件部分源码,无法直接运行,需要对代码中图像读取以及参数读取部分进行修改, 谢谢!
https://www.cnblogs.com/zyly/p/9508131.html#_label4