参考博文:
https://blog.csdn.net/lwzkiller/article/details/54633670
https://blog.csdn.net/ihadl/article/details/18272627
角点的定义
角点检测又叫做特征点检测,是计算机视觉中用来获得图像特征的一种方法,可以应用在图像匹配,目标识别和三维重建等领域中。如果一个点在任意方向进行微小的变动都会引起很大的灰度变化,那就叫做角点。
关于角点的具体描述可以有几种:
一阶导数(即灰度的梯度)的局部最大所对应的像素点;
两条及两条以上边缘的交点;
图像中梯度值和梯度方向的变化速率都很高的点;
角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。
如下图所示,(a)中窗口在任意方向变动都没有灰度变化,则为平坦区域;(b)中窗口在水平方向的变动会引起较大的灰度变化,而沿着竖直方向边缘的变动不会有灰度变化,则为边缘区域;©中窗口在任意方向变动都会有较大灰度变化,则为角点。Haaris角点检测就是通过窗口在各个方向的变化程度来判别是否为角点的。
Haaris角点检测原理步骤
通过一个窗口发生滑动,其滑动距离为(u,v)时,计算其窗口内每一个像素点的灰度变化之和得到以下自相关函数:
通过泰勒展开可以做以下变换:
最后变成矩阵形式:
其中矩阵M为:
根据矩阵M的两个特征值,我们可以判断点是否为角点。
a. 在图像中的边缘区域。一个特征值大,另一个特征值小,λ1>λ2或λ2>λ1。自相关函数值在某一方向上大,在其他方向上小。
b. 在图像中的平面区域。两个特征值都小,且近似相等;自相关函数数值在各个方向上都小。
c. 在图像中的角点处。两个特征值都大,且近似相等,自相关函数在所有方向都增大。
为了度量角点响应,定义以下角点响应函数:
其中k为常数,值一般为0.04~0.06.
其中:
R 只与M的特征值有关,在不同区域R会有不同的值,可根据R的值来判断区域种类。
角点处:R 为大数值正数
边缘区域:R 为大数值负数
平坦区域:R 为小数值
在判断角点的时候,只需对角点响应函数R进行阈值处理:R > threshold,即可检测出符合条件的角点。
Opencv函数cornerHarris()
代码示例:
#include <opencv2/opencv.hpp>
#include<iostream>
using namespace cv;
using namespace std;
#define WIN_NAME1 "【程序窗口1】"
#define WIN_NAME2 "【程序窗口2】"
Mat g_srcImage, g_srcImage1, g_grayImage;
int thresh = 30;
int max_thresh = 175;
void on_CornerHarris(int, void*)
{
Mat dstImage, normImage, 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());
convertScaleAbs(normImage, scaledImage);
for (int j = 0; j < normImage.rows; j++)
{
for (int i = 0; i < normImage.cols; i++)
{
if ((int)normImage.at<float>(j, i) > thresh + 80)
{
circle(g_srcImage1, Point(i, j), 5, Scalar(10, 10, 255), 2, 8, 0);
circle(scaledImage, Point(i, j), 5, Scalar(10, 10, 255), 2, 8, 0);
}
}
}
imshow(WIN_NAME1, g_srcImage1);
imshow(WIN_NAME2, scaledImage);
}
int main()
{
g_srcImage = imread("C:/Users/msi-/Desktop/picture/witcher_logo.jpg",1);
imshow("【原图】", g_srcImage);
g_srcImage1 = g_srcImage.clone();
cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);
namedWindow(WIN_NAME1);
createTrackbar("阈值", WIN_NAME1, &thresh, max_thresh, on_CornerHarris);
on_CornerHarris(0, 0);
waitKey();
return 0;
}
检测图片结果:
原图:
二值图:
原图角点位置图: