计算机视觉中,我们经常要匹配两幅图像。匹配的的方式就是通过比较两幅图像中的公共特征,比如边,角,以及图像块(blob)等,来对两幅图像进行匹配。
相对于边,角更适合描述图像特征,比如下面的图像中,大概有6种特征,我们用A、B、C、D、E、F来描述,其中A, B是平的区域,在图像中很难精确定位,C,D是边,比A,B好些,但是图像中的边也很多,定位到某个边也比较困难,相比来说E,F的角更适合描述当前的图像的特征,也更好检测,因为你不论怎么移动图像,这些角的特征都和图像其它部分不同。所以在计算机视觉中,我们通常用角来描述图像特征。
E,F中的角我们通常称作角点(corner points),他们具有以下特征:
–局部窗口沿各方向移动,均产生明显变化的点
–图像局部曲率突变的点
在这篇教程中,我们来学习如何在图像中检测harrs特征角,harris特征角最早在paper A Combined Corner and Edge Detector中被Chris Harris & Mike Stephens提出。
Harris角点检测的基本思想:从图像局部的小窗口观察图像特征,在各个方向移动都会导致图像灰度的明显变化,也就是说图像的梯度在各个方向有很大变化。
下面我们看看harris角的计算方法:
对于灰度图像 ,我们在窗口内,用x方向的偏移u和y方向的偏移v,扫过所有像素,得到一个图像灰度值的变化和。
- 表示在 位置的窗口。
- 是 位置的图像灰度值。
- 是位置 的图像灰度值。
由于我们要在一个窗口内查找harris特征角,所以我们必须找到变化最大的窗口,这个窗口内肯定存在特征角,所以我们定义下面的方程,并用泰勒级数展开式子:
-
表示成矩阵乘法形式:
-
假设
-
则有:
-
对每一个窗口计算得到一个分数R,根据R的大小来判定窗口内是否存在harris特征角。分数R根据下面公式计算得到:
这里:(是矩阵M的2个特征值,k是一个指定值,这是一个经验参数,需要实验确定它的合适大小,通常它的值在0.05和0.5之间)。
- det(M) =
- trace(M) =
- R取决于M的特征值,对于角点|R|很大,平坦的区域|R|很小,边缘的R为负值
在opencv中,我们可以通过函数cv::cornerHarris 计算特征角,
C++: void cornerHarris(InputArray src, OutputArray dst, int blockSize, int ksize, double k, intborderType=BORDER_DEFAULT )
Parameters:
- src – 单通道8位或者浮点图像。
- dst – 存储 Harris 角的结果图像,它的格式为:CV_32FC1,图像大小和源图像一致。
- blockSize – 就是扫描时候窗口的大小。
- ksize – Sobel() 算子使用的值。
- k – 上面介绍的计算R时候的k参数值。
- borderType –像素插值方法。
下面的代码显示一副图像的harris角检测结果:
// 读入输入图像
cv::Mat image= cv::imread("../church01.jpg",0);
if (!image.data)
return 0;
// 显示图像
cv::namedWindow("Original Image");
cv::imshow("Original Image",image);
// 检测 Harris Corners
cv::Mat cornerStrength;
cv::cornerHarris(image,cornerStrength,
3, // neighborhood size
3, // aperture size
0.01); // Harris parameter
//二值化harris角的检测结果
cv::Mat harrisCorners;
double threshold= 0.0001;
cv::threshold(cornerStrength,harrisCorners,
threshold,255,cv::THRESH_BINARY_INV);
// 显示结果
cv::namedWindow("Harris Corner Map");
cv::imshow("Harris Corner Map",harrisCorners);
下面是程序的运行结果:
程序代码:参考工程文件FirstOpenCV48