角点检测(Corner Detection)是计算机视觉中用来获得图像特征的一种方法,广泛应用于运动检测、视频追踪、目标识别等领域中,也称特征点检测。
对于角点,到目前为止还没有明确的数学定义。但是你可以认为角点就是极值点,即在某方面属性特别突出的点。一般的角点检测都是对有具体定义的、或者是能够具体检测出来的兴趣点的检测。这意味着兴趣点可以是角点,是在某些属性上强度最大或者最小的孤立点、线段的终点,或者是曲线上局部曲率最大的点。
通俗的来说,在一副图像中,我们可以认为角点是物体轮廓线的连接点(见图1),当拍摄视角变化的时候,这些特征点仍能很好地保持稳定的属性。
角点通常被定义为两条边的交点,角点的局部领域应该具有两个不同区域的不同方向的边界。实际应用中,大多数角点检测方法检测的是拥有特定特征的图像点,不仅仅是“角点”。这些特征点在图像中具有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征。角点在保留图像图形重要特征的同时,可以有效地减少信息的数据量,使其信息的含量很高,有效地提高了计算的速度,有利于图像的可靠匹配,使得实时处理成为可能。
图像特征类型可以被分为如下三种:
其中,角点是个很特殊的存在。如果某一点在任意方向的一个微小变动都会引起灰度很大变化,那么就称为角点。角点位于两条边缘的交点处,代表了两个边缘变化的方向上的点,所以它们是可以精确定位的二维特征,甚至可以达到亚精度的精度。
关于角点的具体描述可以有如下几种:
在当前的图像处理领域,角点检测算法可以归纳为以下三类
Harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度很高。但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象。
角点检测最原始的想法就是取某个像素的一个邻域窗口,当这个窗口在各个方向上进行小范围移动时,观察窗口内平均的像素灰度值的变化(即,E(u,v),Window-averaged change of intensity)。从上图可知,我们可以将一幅图像大致分为三个区域(‘flat’,‘edge’,‘corner’),这三个区域变化是不一样的。
A. 窗口图像平坦 ---------------E的变化不大
B.窗口图像是一条边 ------------1.沿边滑动E的变化不大 2.垂直于边滑动,E的变化会很大
C.窗口图像为一个角点 ------------窗口图像沿任何方向移动,E的值变化都会很大
具体原理可参考下面两篇
https://blog.csdn.net/linqianbi/article/details/78930239
https://blog.csdn.net/pbymw8iwm/article/details/82624898
OpenCV中cornerHarris
函数可用于检测图像的Harris角点。 cornerHarris
函数名参数的说明:
void cornerHarris( InputArray src, //输入8bit 单通道灰度Mat矩阵
OutputArray dst, //用于保存Harris角点检测结果,32位单通道,大小与src相同
int blockSize, //滑块窗口的尺寸
int ksize, //Sobel边缘检测滤波器大小
double k, //Harries中间参数,经验值0.04~0.06
int borderType=BORDER_DEFAULT //插值类型
);
完整代码:
#include
#include
#include
#include
using namespace cv;
using namespace std;
Mat image;
Mat imageGray;
int thresh = 200;
int MaxThresh = 255;
void Trackbar(int, void*); //阈值控制
int main()
{
image = imread("1.jpg");
cvtColor(image, imageGray, CV_RGB2GRAY);
GaussianBlur(imageGray, imageGray, Size(5, 5), 1); // 滤波
namedWindow("Corner");
createTrackbar("threshold:", "Corner", &thresh, MaxThresh, Trackbar);
imshow("Corner", image);
Trackbar(0, 0);
waitKey();
return 0;
}
void Trackbar(int, void*)
{
Mat dst, dst8u, dstshow, imageSource;
dst = Mat::zeros(image.size(), CV_32FC1);
imageSource = image.clone();
cornerHarris(imageGray, dst, 3, 3, 0.04, BORDER_DEFAULT);
normalize(dst, dst8u, 0, 255, CV_MINMAX); //归一化
convertScaleAbs(dst8u, dstshow);
imshow("dst", dstshow); //dst显示
for (int i = 0;i(i, j)>thresh) //阈值判断
{
circle(imageSource, Point(j, i), 2, Scalar(0, 0, 255), 2); //标注角点
}
}
}
imshow("Corner", imageSource);
}
注:
1.convertScaleAbs函数是OpenCV中的函数,使用线性变换转换输入数组元素成8位无符号整型。
2.cvCircle(CvArr* img, CvPoint center, int radius, CvScalar color, int thickness=1, int lineType=8, int shift=0)
img为源图像指针
center为画圆的圆心坐标
radius为圆的半径
color为设定圆的颜色,规则根据B(蓝)G(绿)R(红)
thickness 如果是正数,表示组成圆的线条的粗细程度。否则,表示圆是否被填充
line_type 线条的类型。默认是8
shift 圆心坐标点和半径值的小数点位数
效果图:
OpenCV 提供了函数: cv2.goodFeaturesToTrack()
。这个函数可以帮我们使用 Shi-Tomasi 方法获取图像中 N 个最好的角点(也可以通过改变参数来使用 Harris 角点检测算法)。通常情况下,输入的应该是灰度图像。然后确定你想要检测到的角点数目。再设置角点的质量水平, 0到 1 之间。它代表了角点的最低质量,低于这个数的所有角点都会被忽略。最后在设置两个角点之间的最短欧式距离。根据这些信息,函数就能在图像上找到角点。所有低于质量水平的角点都会被忽略,然后再把合格角点按角点质量进行降序排列。函数会采用角点质量最高的那个角点(排序后的第一个),然后将它附近(最小距离之内)的角点删掉。按着这样的方式最后返回 N 个最佳角点。
//goodFeaturesToTrack有比cornerHarries更多的控制参数,函数原型:
void goodFeaturesToTrack( InputArray image, OutputArray corners,
int maxCorners, double qualityLevel, double minDistance,
InputArray mask=noArray(), int blockSize=3,
bool useHarrisDetector=false, double k=0.04);
/*第一个参数image:8位或32位单通道灰度图像;
第二个参数corners: 位置点向量,保存的是检测到角点的坐标;
第三个参数maxCorners: 定义可以检测到的角点的数量的最大值;
第四个参数qualityLevel: 检测到的角点的质量等级,角点特征值小于qualityLevel*最大特征
值的点将被舍弃;
第五个参数minDistance: 两个角点间最小间距,以像素为单位;
第六个参数mask: 指定检测区域,若检测整幅图像,mask置为空Mat();
第七个参数blockSize: 计算协方差矩阵时窗口大小;
第八个参数useHarrisDector: 是否使用Harris角点检测,为false,则使用Shi-Tomasi算子;
第九个参数K: 留给Harris角点检测算子用的中间参数,一般取经验值0.04~0.06.第8个参数为false时,改参数不起作用;
#include "core/core.hpp"
#include "highgui/highgui.hpp"
#include "imgproc/imgproc.hpp"
using namespace cv;
Mat image;
Mat imageGray;
int thresh=5; //角点个数控制
int MaxThresh=255;
void Trackbar(int,void*);
int main(int argc,char*argv[])
{
image=imread(argv[1]);
cvtColor(image,imageGray,CV_RGB2GRAY);
GaussianBlur(imageGray,imageGray,Size(5,5),1); // 滤波
namedWindow("Corner Detected");
createTrackbar("threshold:","Corner Detected",&thresh,MaxThresh,Trackbar);
imshow("Corner Detected",image);
Trackbar(0,0);
waitKey();
return 0;
}
void Trackbar(int,void*)
{
Mat dst,imageSource;
dst=Mat::zeros(image.size(),CV_32FC1);
imageSource=image.clone();
vector corners;
goodFeaturesToTrack(imageGray,corners,thresh,0.01,10,Mat());
for(int i=0;i
goodFeaturesToTrack相比cornerHarris,增加了检测的复杂度,同时也可以更好的控制检测到的角点的特性,比如角点个数,角点间最小间距等。设置检测点数为56时,只有特征值最大的前56个角点被检测出来,继续增大检测点数的值,所有角点都被检测出来