Opencv3笔记31——Harris角点检测
1. 兴趣点和角点
在图像处理和计算机视觉领域,兴趣点,也被称为关键点、特征点。被用于解决物体识别和图像识别,图像匹配、视觉跟踪、三维建模等一系列的问题。
图像特征类型被分为三种:
1. 边缘
2. 角点(感兴趣关键点)
3. 斑点(Blobs)感兴趣区域
角点是个很特殊的存在。如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,我们称之为角点。角点作为图像上的特征点,包含重要的信息,在图像融合和目标跟踪及三维重建中有重要的应用价值。因为角点位于两条边缘的交点处,代表了两个边缘变换的方向上的点,所以它们精确的定位二维特征。
关于角点的具体描述有以下几种。
- 一阶导数:灰度的梯度,局部最大所对应的像素点
- 两条及两条以上边缘的交点
- 图像中梯度值和梯度方向的变化速率都很高的点
- 角点处的一阶导数最大,二阶导数为0,指示了物体边缘变换不连续的方向
2 角点检测
现有的角点检测算法并不是都十分的健壮。很多的方法都要求有大量的训练集和冗余数据来防止和减少错误特征的出现。
角点检测方法的一个很重要的评价标准是其多幅图像中相同或相似特征的检测能力,并且能够应对光照变化、图像旋转等图像变化。
算法归类
- 基于灰度图像角点检测
- 基于二值图像的角点检测
- 基于轮廓曲线的角点检测
基于灰度图像的角点检测又可分为基于梯度、基于模板和基于模板梯度组合三类方法。
基于模板的方法主要考虑像素邻域点的灰度变化、即图像亮度的变化将与领点亮度对比最够大的店定义为角点。
基于模板的角点检测算法有kitchen-Rosenfeld角点检测算法,Harris角点检测算法、KLT检点检测算法及SUSAN角点检测算法。
3. harris角点检测
harris角点检测时一种直接基于灰度图像的角点提取算法,稳定性高,尤其对于L型角点检测精度高。但是由于采用了高斯滤波,运算速度相对比较的慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。
4. 实现harris角点检测:cornerHarris()函数
cornerHarris函数和cornerMinEigenVal()以及cornerEigenValsAndVecs()函数类似。cornerHarris函数对于每一个像素在邻域内,计算梯度的协方差矩阵,接着计算如下:
就可以找出输出图中的局部最大值,找出了角点。
函数原型:
void cornerHarris(InputArray src,OutputArray dst,int blockSize,int ksize,double k, intborderType = BORDER_DEFAULT)
- 第三个参数:int类型的blockSize,表示领域的大小
- 第四个参数:int类型的ksize,表示Sobel()算子的孔径大小
- 第五个参数:double 类型的k,Harris参数
- 第六个参数:int类型的borderType,图像像素的边界模式,默认值为BORDER_DEFAULT
5.cornerHarris程序实例
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
using namespace cv;
int main()
{
//灰度的方式读入图像
Mat srcImage = imread("1.jpg", 0);
imshow("原始图", srcImage);
//进行Harris角点检测找出角点
Mat cornerStrength;
cornerHarris(srcImage, cornerStrength, 2, 3, 0.01);
//对灰度图像进行阈值操作
Mat harrisCorner;
threshold(cornerStrength, harrisCorner, 0.00001, 255, THRESH_BINARY);
imshow("角点检测后的二值效果图", harrisCorner);
waitKey(0);
return 0;
}
6. Harris角点检测与绘制
#include <opencv2/opencv.hpp>
#include <opencv2/imgproc/imgproc.hpp>
#include <opencv2/highgui/highgui.hpp>
using namespace cv;
//定义宏
#define WINDOW_NAME1 "【程序窗口1】"
#define WINDOW_NAME2 "【程序窗口2】"
//全局变量声明
Mat g_srcImage, g_srcImage1, g_grayImage;
//当前阈值
int thresh = 30;
//最大阈值
int max_thresh = 175;
//全局函数声明
//回调函数
void on_CornerHarris(int, void *);
int main()
{
//载入原图
g_srcImage = imread("1.jpg", 1);
if (!g_srcImage.data)
{
printf("图片错误~!\n");
return false;
}
imshow("原始图", g_srcImage);
g_srcImage1 = g_srcImage.clone();
//转为灰度图
cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);
//创建窗口和滚动条
namedWindow(WINDOW_NAME1, WINDOW_AUTOSIZE);
createTrackbar("阈值:", WINDOW_NAME1, &thresh, max_thresh, on_CornerHarris);
on_CornerHarris(0, 0);
waitKey(0);
return 0;
}
//回调函数的定义
void on_CornerHarris(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);
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(0, 10, 255), 2, 8, 0);
}
}
}
imshow(WINDOW_NAME1, g_srcImage1);
imshow(WINDOW_NAME2, scaledImage);
}