1.概述
角点是图像很重要的特征,对图像图形的理解和分析有很重要的作用,在保留图像图形重要特征的同时,可以有效减少信息的数据量,使信息的含量很高,有效提高计算速度,有利于图像的可靠匹配,使得实时处理成为可能。在物体识别、图像匹配、视觉跟踪和三维重建等方面有很重要的应用。
角点可以认为是窗口向任意方向的移动都导致图像灰度的明显变化。从图像分析的角度来定义角点可以有一下两种:
1.角点可以是两个边缘的角点
2.角点是邻域内具有两个主方向的特征点
前者往往需要对图像边缘进行编码,这在很大程度上依赖于图像的分割与边缘提取,具有相当大的难度和计算量,且一旦待检测目标局部发生变化,很可能导致操作的失败。
角点检测算法可以归纳为三类:基于灰度图像的角点检测、基于二值图像的角点检测、基于轮廓曲线的角点检测。基于灰度图像的检测又可细分为基于梯度、基于模板、基于模板梯度组合三类方法,其中基于模板的方法主要考虑像素邻域点的灰度变化,即图像亮度的变化,将与邻点亮度对比足够大的点定义为角点。常见的基于模板的角点检测算法有Kitchen-Rosenfeld角点检测,Harris角点检测算法,KLT角点检测和SUSAN角点检测。本文主要介绍Harris角点检测。
2.Harris角点检测原理
Harris角点检测原理推导靠一篇博客讲清楚不太现实,这里介绍一个比较直观的概念而不是数学推导。
Harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高。
人眼对角点的识别通常是在一个局部的小区域或小窗口完成的。如下图所示:
在各个方向上移动这个特征的小窗口,窗口内区域的灰度发生了较大的变化,那么久认为在窗口内遇到了角点,如果这个特定的窗口在图像各个方向上移动时,窗口内图像的灰度发生了很大变化,而在另一些方向上没有发生变化,那么窗口内的图像可能就是一条直线的线段。
3.opencv API
opencv提供cornerHarris()提取Harris角点。cornerHarris函数对每一个像素在blockSize x blockSize邻域内,计算2 x 2梯度的协方差矩阵M(x,y),,接着它计算如下公式输出局部最大值,即为角点。
void cv::cornerHarris ( InputArray src,
OutputArray dst,
int blockSize,
int ksize,
double k,
int borderType = BORDER_DEFAULT
)
src:输入图像,Mat类型即可,必须为单通道8-bit或浮点型图像
dst:角点检测的输出结果,与原图像有相同的尺寸和类型
blockSize:邻域大小,可以查看cornerEigenValsAndVecs()得到更多关于blockSize的信息
ksize:表示Sobel()算子孔径大小
**k:**Harris参数,用于判断是否为角点
borderType:前面已多次介绍,为图像边界模式,有默认值BORDER_DEFAULT
4.示例代码
#include <iostream>
#include <stdlib.h>
#include <opencv2\core\core.hpp>
#include <opencv2\highgui\highgui.hpp>
#include <opencv2\imgproc\imgproc.hpp>
using namespace std;
using namespace cv;
//定义全局变量
Mat srcImage, grayImage;
int thresh = 100;
const int threshMaxValue = 255;
//声明回调函数
void cornerHarris_detect(int, void*);
int main()
{
srcImage = imread("harris.jpg");
//判断文件是否加载成功
if (srcImage.empty())
{
cout << "图像加载失败!";
return -1;
}
else
cout << "图像加载成功..." << endl << endl;
cvtColor(srcImage, grayImage, COLOR_BGR2GRAY);
namedWindow("grayImage", WINDOW_AUTOSIZE);
imshow("grayImage", grayImage);
createTrackbar("Threshold:", "grayImage", &thresh, threshMaxValue, cornerHarris_detect);
cornerHarris_detect(thresh, 0);
waitKey(0);
return 0;
}
void cornerHarris_detect(int, void*)
{
Mat dstImage, dst_norm_image, dst_norm_scaled;
dstImage = Mat::zeros(srcImage.size(), CV_32FC1);
//检测器参数设置
int blockSize = 2; //邻域尺寸
int apertureSize = 3; //Sobel算子孔径
double k = 0.04; //Harris参数
//角点检测
cornerHarris(grayImage, dstImage, blockSize, apertureSize, k, BORDER_DEFAULT);
normalize(dstImage, dst_norm_image, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
convertScaleAbs(dst_norm_image, dst_norm_scaled); //强归一化后的图像线性变换为8位无符号整型
//绘制角点
for (int j = 0; j < dst_norm_image.rows; j++)
{
for (int i = 0; i < dst_norm_image.cols; i++)
{
if ((int)dst_norm_image.at<float>(j,i)>thresh)
{
circle(dst_norm_scaled, Point(i, j), 5, Scalar(0), 2, 8, 0);
circle(grayImage, Point(i, j), 5, Scalar(0, 0, 255), 2, 8, 0);
}
}
}
namedWindow("cornerHarris", WINDOW_AUTOSIZE);
imshow("cornerHarris", dst_norm_scaled);
namedWindow("corner_grayImage", WINDOW_AUTOSIZE);
imshow("corner_grayImage", grayImage);
}
运行结果
5.参考文献
http://www.360doc.com/content/15/1212/23/20007814_519967668.shtml