开启掘金成长之旅!这是我参与「掘金日新计划 · 2 月更文挑战」的第 4 天
1 概述
角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中,也称为特征点检测。
角点通常被定义为两条边的交点,更严格地说法是,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等。
2 兴趣点与角点
在图像处理和与计算机视觉领域,兴趣点(interest points),也被称作关键点(key points)、特征点(feature points)。它被大量用于解决物体识别、图像识别、 图像匹配、视觉跟踪、三维重建等一系列的问题。我们不再观察整幅图,而是选择某些特殊的点,然后对它们进行局部有的放矢地分析。如果能检测到足够多的这种点,同时它们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就具有实用价值。
图像特征类型可以被分为如下三种:
- 边缘
- 角点(感兴趣关键点)
- 斑点(Blobs)(感兴趣区域)
其中,角点是个很特殊的存在。如果某一点在任意方向的一个微小变动都会引起灰度很大的变化,那么我们就把它称之为角点。
角点作为图像上的特征点,包含有重要的信息,在图像融合和目标跟踪及三维重建中有重要的应用价值。它们在图像中可以轻易地定位,同时,在人造物体场景,比如门、窗、桌等处也随处可见。
因为角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,所以它们是可以精确定位的二维特征,甚至可以达到亚像素的精度。又由于其图像梯度有很高的变化,这种变化是可以用来帮助检测角点的。需要注意的是,角点与位于相同强度区域上的点不同,与物体轮廓上的点也不同,因为轮廓点难以在相同的其他物体上精确定位。
另外,关于角点的具体描述可以有如下几种:
- 一阶导数(即灰度的梯度)的局部最大所对应的像素点;
- 两条及两条以上边缘的交点;
- 图像中梯度值和梯度方向的变化速率都很高的点;
- 角点处的一阶导数最大,二阶导数为零,它指示了物体边缘变化不连续的方向。
3 角点检测
现有的角点检测算法并不是都十分的健壮。很多方法都要求有大量的训练集和冗余数据来防止或减少错误特征的出现。另外,角点检测方法的一个很重要的评价标准是其对多幅图像中相同或相似特征的检测能力,并且能够应对光照变化、图像旋转等图像变化。
在当前的图像处理领域,角点检测算法可归纳为以下三类。
- 基于灰度图像的角点检测
- 基于二值图像的角点检测
- 基于轮廓曲线的角点检测
而基于灰度图像的角点检测又可分为基于梯度、基于模板和基于模板梯度组合三类方法。其中基于模板的方法主要考虑像素领域点的灰度变化,即图像亮度的变化,将与邻点亮度对比足够大的点定义为角点。常见的基于模板的角点检测算法有Kitchen-Rosenfeld 角点检测算法,Harris角点检测算法、KLT 角点检测算 法及SUSAN角点检测算法。
接下来,让我们一起来了解harris角点检测。
4 harris角点检测
harris 角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高。但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。
5 实现Harris 角点检测:cornerHarris()函数
cornerHarris 函数用于在OpenCV中运行 Harris 角点检测算子来进行角点检测。和cornerMinEigenVal()以及 cornerEigenValsAndVecs()函数类似,cornerHarris 函数对于每一个像素(x,y)在blockSizexblockSize 邻域内,计算2x2梯度的协 方差矩阵M(x,y),接着它计算如下式子:
就可以找出输出图中的局部最大值,即找出了角点。
其函数原型和参数解析如下。
C++:
void cornerHarris(InputArray src,OutputArray dst, int blockSize, int ksize, double k, intborderType=BORDER_DEFAULT)
- 第一个参数,InputArray类型的src,输入图像,即源图像,填Mat类的对象即可,且须为单通道8位或者浮点型图像。
- 第二个参数,OutputArray 类型的 dst,函数调用后的运算结果存在这里,即这个参数用于存放Harris角点检测的输出结果,和源图片有一样的尺寸和类型。
- 第三个参数,int 类型的 blockSize,表示邻域的大小,更多详细信息在cornerEigenValsAndVecs()中有讲到。
- 第四个参数,int类型的ksize,表示Sobel()算子的孔径大小。
- 第五个参数,double类型的k,Harris参数。
- 第六个参数,int类型的borderType,图像像素的边界模式。注意它有默认值 BORDER_DEFAULT。更详细的解释,参考borderInterpolate()函数。
讲解完这个函数,我们看一个Harris角点检测示例程序,其中还用到了之前讲到的threshold 函数。
6 示例
源码:
//---------------------------------【头文件、命名空间包含部分】----------------------------
// 描述:包含程序所使用的头文件和命名空间
//---------------------------------------------------------------------------------------
#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;
}
原始图
效果图