角点检测详细总结及代码示例

 

角点检测(Corner Detection)是计算机视觉系统中用来获得图像特征的一种方法,广泛应用于运动检测、图像匹配、视频跟踪、三维建模和目标识别等领域中。也称为特征点检测。

一、角点(corner)

       角点通常被定义为两条边的交点,或者说,角点的局部邻域应该具有两个不同区域的不同方向的边界。更严格的说,角点的局部邻域应该具有两个不同区域的不同方向的边界。而实际应用中,大多数所谓的角点检测方法检测的是拥有特定特征的图像点,而不仅仅是“角点”。这些特征点在图像中有具体的坐标,并具有某些数学特征,如局部最大或最小灰度、某些梯度特征等。

关于角点的具体描述可以有几种:

(1)、一阶导数(即灰度的梯度)的局部最大所对应的像素点; (2)、两条及两条以上边缘的交点; (3)、图像中梯度值和梯度方向的变化速率都很高的点; (4)、角点处的一阶导数最大,二阶导数为零,指示物体边缘变化不连续的方向。

角点一般位于两条以上的交点上,五种类型如上图所示:分别为L型、Y型、T型、X型和箭头型。现有的角点检测算法并不是都十分的鲁棒。很多方法都要求有大量的训练集和冗余数据来防止或减少错误特征的出现。角点检测方法的一个很重要的评价标准是其对多幅图像中相同或相似特征的检测能力,并且能够应对光照变化、图像旋转等图像变化。不同的检测方法对角点有不同的意义。一个优秀的角点检测方法需要满足如下标准:

1)所有真实的角点都被发现到;

2)没有虚假的角点被当作角点检测出来;

3)角点在图像中的定位精确;

4)角点检测器必须对噪声有鲁棒性;

5)角点检测算子的效率应该是高效的。

二、目前的角点检测算法可归纳为3类:

基于灰度图的角点检测;基于二值图像的角点检测;基于轮廓曲线的角点检测.

2.1.基于灰度图的角点检测

基于灰度图的角点检测又分为:

(1)基于梯度。基于梯度的方法是通过计算边缘的曲率来判断角点的存在性,角点计算数值的大小不仅与边缘强度有关,而且与边缘方向的变化率有关,该方法对噪声比基于模板的角点检测方法对噪声更为敏感。

基于梯度更多参考:http://blog.csdn.net/tostq/article/details/49455449

(2)基于模板。基于模板的方法主要考虑像素邻域点的灰度变化,即图像亮度的变化,将与邻点亮度对比足够大的点定义为角点。

(3)基于模板梯度组合。除了直接对灰度图像的像素操作以外,罗斌等人采用了变换的方法,用电磁场理论中矢势的鞍点检测来代替角点的检测,是一种综合了模板角点检测和灰度曲率角点检测的方法。通过高斯模板和图像的卷积获得Canny边缘映射图,再计算梯度和边缘矢量就得到了矢势。对于矢势计算高斯曲率和平均曲率来判定是否是鞍点,对应的应该是图像的角点。因为涉及到了曲率的计算,也有人将该方法归到边缘曲线的角点检测。

常见的基于模板的角点检测算法分为:

(1)Kitchen-Rosenfeld角点检测算法

(2)Harris角点检测算法

更多参考http://blog.csdn.net/crzy_sparrow/article/details/7391511 http://blog.csdn.net/xw20084898/article/details/21180729

              https://blog.csdn.net/rqc112233/article/details/50112463(挺详细)

  ( 3)KLT角点检测算法  更多参考http://blog.csdn.net/tostq/article/details/49157811

 (4)SUSAN角点检测算法  更多参考http://blog.csdn.net/tostq/article/details/49305615

Moravec角点检测算法

Moravec角点检测算法是最早的角点检测算法之一。该算法将角点定义为具有低“自相关性”的点。算法会检测图像的每一个像素,将像素周边的一个邻域作为一个patch,并检测这个patch和周围其他patch的相关性。这种相关性通过两个patch间的平方差之和(SSD)来衡量,SSD值越小则相似性越高。

如果像素位于平滑图像区域内,周围的patch都会非常相似。如果像素在边缘上,则周围的patch在与边缘正交的方向上会有很大差异,在与边缘平行的方向上则较为相似。而如果像素是各个方向上都有变化的特征点,则周围所有的patch都不会很相似。

Moravec会计算每个像素patch和周围patch的SSD最小值作为强度值,取局部强度最大的点作为特征点。

Harris角点检测算法

 

Moravec角点检测算法有几个很明显的缺陷:

1,强度值的计算并不是各向同性的,只有离散的8个45度角方向被考虑。因为patch的评议比较最多只有8个方向;

2,由于窗口是方形并且二元的,因此相应函数会有噪声;

3,对边缘的相应太简单,因为强度值尽取SSD的最小值;

Harris角点检测其他参考资料:https://blog.csdn.net/Ben_Ben_Niao/article/details/47446627,里面含有Harris角点检测的详细步骤。

 

 

Harrid角点检测原理详解:https://blog.csdn.net/lwzkiller/article/details/54633670

                                         https://blog.csdn.net/rqc112233/article/details/50112463(挺详细)

常见角点检测算法原理截图自角点检测理论及算法研究(华中科技大学-梁艳的硕士论文)

参考:OpenCV——角点检测原理分析(Harris,Shi-Tomasi、亚像素级角点检测)

Harris OpenCV里面的API:


C++:void cornerHarris( InputArray src, //输入8bit单通道灰度Mat矩阵
				  OutputArray dst, //用于保存Harris角点检测结果,32位单通道,大小与src相同
				  int blockSize,   //滑块窗口的尺寸
				  int ksize,       //Sobel边缘检测滤波器大小
				  double k,        //Harris中间参数,经验值0.04~0.06
				  int borderType=BORDER_DEFAULT  //插值类型

 Shi-Tomasi 角点检测

Shi-Tomasi 算法是Harris 算法的改进。Harris 算法最原始的定义是将矩阵 M 的行列式值与 M 的迹相减,再将差值同预先给定的阈值进行比较。后来Shi 和Tomasi 提出改进的方法,若两个特征值中较小的一个大于最小阈值,则会得到强角点。
Shi 和Tomasi 的方法比较充分,并且在很多情况下可以得到比使用Harris 算法更好的结果。

OpenCV里面的API:

C++: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:计算协方差矩阵时窗口大小;

第八个参数useHarrisDetector:是否使用Harris角点检测,为false,则使用Shi-Tomasi算子;

第九个参数k:留给Harris角点检测算子用的中间参数,一般取经验值0.04~0.06。第八个参数为false时,该参数不起作用;

Shi-Tomasi 更多资料请参考http://blog.csdn.net/xiaowei_cqu/article/details/7805206

亚像素级角点检测

  当我们想要进行几何测量或者标定的时候势必要比目标识别需要更高的精度的特征点。而上面的goodFeaturesToTrack()只能得到整数的坐标值,这时候我们就需要亚像素级的角点检测来得到实数坐标值来满足精度需求。

   亚像素级角点检测的位置摄像机标定,跟踪并重建摄像机的轨迹或者重建被跟踪目标的三维结构时,是一个基本的测量值。下面是将角点位置精确到亚像素精度的过程:

参考:https://blog.csdn.net/zhu_hongji/article/details/81235643 
 

   一个向量与其正交的向量的点积为0,角点满足上图所示情况。其中(a)点p附近的图像是均匀的,其梯度为0;(b)边缘的梯度与沿边缘方向的q-p向量正交。在图中两种情况下,p点梯度与q-p向量的点积均为0。

      上图中,我们假设起始角点q在实际亚像素角点的附近。检测所有的q-p向量。若点p位于一个均匀区域,则点p的梯度为0。若q-p向量的方向与边缘的方向一致,则此边缘上p点处的梯度与q-p向量正交,在这两种情况下,p点处的梯度与q-p向量的点积为0.我们可以在p点周围找到很多组梯度以及相关的向量q-p,令其点集为0,然后可以通过求解方程组,方程组的解即为角点q的亚像素级精度的位置,即精确的角点位置。

OpenCV的API介绍:
 

C++:void cornerSubPix( 
InputArray image, //输入图像
InputOutputArray corners,//输入角点的初始坐标和为输出的精确坐标
Size winSize, //搜索窗口边长的一半
Size zeroZone,//搜索区域中间的死区大小的一半,(-1,-1)表示没有这样的大小。
TermCriteria criteria //终止角点优化迭代的条件
);

FAST角点检测算法

Smith 和 Brady在1997年提出了一种完全不同的角点提取方法,即“SUSAN (Smallest UnivalueSegment AssimilatingNucleus)”提取算子。SUSAN 提取算子的基本原理是,与每一图像点相关的局部区域具有相同的亮度。如果某一窗口区域内的每一像元亮度值与该窗口中心的像元亮度值相同或相似,这一窗口区域将被称之为“USAN”。计算图像每一像元的“USAN”,为我们提供了是否有边缘的方法。位于边缘上的像元的“USAN”较小,位于角点上的像元的“USAN”更小。因此,我们仅需寻找最小的“USAN”,就可确定角点。该方法由于不需要计算图像灰度差,因此,具有很强的抗噪声的能力。

Edward Rosten and TomDrummond 在2006年提出了一种简单快速的角点探测算法,该算法检测的角点定义为在像素点的周围邻域内有足够多的像素点与该点处于不同的区域。应用到灰度图像中,即有足够多的像素点的灰度值大于该点的灰度值或者小于该点的灰度值。

考虑下图中p点附近半径为3的圆环上的16个点,一个思路是若其中有连续的12个点的灰度值与p点的灰度值差别超过某一阈值,则可以认为p点为角点。

这一思路可以使用机器学习的方法进行加速。对同一类图像,例如同一场景的图像,可以在16个方向上进行训练,得到一棵决策树,从而在判定某一像素点是否为角点时,不再需要对所有方向进行检测,而只需要按照决策树指定的方向进行2-3次判定即可确定该点是否为角点。

 更多Fast角点检测资料请参考:http://blog.csdn.net/crzy_sparrow/article/details/7391511

部分算法示例程序:

//代码里面有三种程序
 
#include "stdafx.h"
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"
#include "opencv2/imgproc/imgproc.hpp"
 
using namespace std;
using namespace cv;
 
 
int main(int argv, char** argc)
{
	Mat srcImage = imread("C:/Users/zhj/Desktop/image/template.bmp");
 
	if (srcImage.empty())
	{
		printf("could not load image..\n");
		return false;
	}
	Mat srcgray, dstImage, normImage,scaledImage;
 
	cvtColor(srcImage, srcgray, CV_BGR2GRAY);
 
	Mat srcbinary;
	threshold(srcgray, srcbinary,0,255, THRESH_OTSU | THRESH_BINARY);
 
	Mat kernel = getStructuringElement(MORPH_RECT, Size(15, 15), Point(-1, -1));
	morphologyEx(srcbinary, srcbinary, MORPH_OPEN, kernel, Point(-1, -1));
 
/*
	//1、Harris角点检测
	cornerHarris(srcgray, dstImage, 3, 3, 0.01, BORDER_DEFAULT);
	//归一化与转换
	normalize(dstImage, normImage, 0, 255, NORM_MINMAX, CV_32FC1, Mat());
	convertScaleAbs(normImage, scaledImage);
	Mat binaryImage;
	threshold(scaledImage, binaryImage, 0, 255, THRESH_OTSU | THRESH_BINARY);
*/
 
 
	//2、Shi-Tomasi算法:确定图像强角点
	vector<Point2f> corners;//提供初始角点的坐标位置和精确的坐标的位置
	int maxcorners = 200;
	double qualityLevel = 0.01;  //角点检测可接受的最小特征值
	double minDistance = 10;	//角点之间最小距离
	int blockSize = 3;//计算导数自相关矩阵时指定的领域范围
	double  k = 0.04; //权重系数
 
	goodFeaturesToTrack(srcgray, corners, maxcorners, qualityLevel, minDistance, Mat(), blockSize, false, k);
	//Mat():表示感兴趣区域;false:表示不用Harris角点检测
 
	//输出角点信息
	cout << "角点信息为:" << corners.size() << endl;
 
	//绘制角点
	RNG rng(12345);
	for (unsigned i = 0; i < corners.size(); i++)
	{
		circle(srcImage, corners[i], 2, Scalar(rng.uniform(0, 255), rng.uniform(0, 255), rng.uniform(0, 255)), -1, 8, 0);
		cout << "角点坐标:" << corners[i] << endl;
	}
 
 
	//3、寻找亚像素角点
	Size winSize = Size(5, 5);  //搜素窗口的一半尺寸
	Size zeroZone = Size(-1, -1);//表示死区的一半尺寸
	//求角点的迭代过程的终止条件,即角点位置的确定
	TermCriteria criteria = TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER, 40,0.001);
	//TermCriteria criteria = TermCriteria(TermCriteria::EPS + TermCriteria::MAX_ITER, 40, 0.001);
 
	cornerSubPix(srcgray, corners, winSize, zeroZone, criteria);
 
 
	//输出角点信息
	cout << "角点信息为:" << corners.size() << endl;
 
	//绘制角点
	for (unsigned i = 0; i < corners.size(); i++)
	{
		circle(srcImage, corners[i], 2, Scalar(255,0,0), -1, 8, 0);
		cout << "角点坐标:" << corners[i] << endl;
	}
 
 
	waitKey(0);
	return(0);
 
}

2.2.基于二值图像的角点检测

2.3.基于轮廓曲线的角点检测。

http://blog.csdn.net/tostq/article/details/49452971

 

 

 

 

 

 

 

 



 

 

 

发布了11 篇原创文章 · 获赞 22 · 访问量 4万+
展开阅读全文

没有更多推荐了,返回首页

©️2019 CSDN 皮肤主题: 大白 设计师: CSDN官方博客

分享到微信朋友圈

×

扫一扫,手机浏览