除了之前文章所说的利用Harris进行角点检测,还可以利用Shi-Tomasi方法(相关论文)进行角点检测,该方法也可以用于初始化基于特征点的目标跟踪。
该方法在opencv中的具体实现是在函数goodFeaturesToTrack()中,其原型为:
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 ) C: void cvGoodFeaturesToTrack(const CvArr* image, CvArr* eig_image, CvArr* temp_image, CvPoint2D32f* corners, int* corner_count, double quality_level, double min_distance, const CvArr* mask=NULL, int block_size=3, int use_harris=0, double k=0.04 )
函数参数说明如下:
image:输入8-bit或浮点型32-bit图像,要求单通道;
eig_image和temp_image被忽略;
corners:检测到角点的输出矩阵;
maxCorners:角点个数的最大值,如果检测到的角点数目超过这个值,则取其中最显著的角点输出;
qualityLeve:用来表征可接受角点的最差质量。该参数值乘以最佳角点的质量数值得到的乘积(即最小的特征值,参考cornerMinEigenVal()函数,或者是Harris函数的响应值,参考cornerHarris()函数)是一个阈值,所有质量数值小于这个阈值的角点将被忽略。举例来说,如果最佳角点的质量数值为1500,qualityLevel设为0.01,那么所有质量数值小于15的角点都会被忽略。
minDistance:返回角点间最小的欧氏距离。
mask:可选的感兴趣区域。如果输入图像非空(此时mask必须为CV_8UC1并且大小和输入图像一致),它制定了角点被检测到的那个区域。
blockSize:在每个像素的邻域中计算导数协方差矩阵时的平均块大小(参考cornerEigenValsAndVecs()函数)。
useHarrisDetector:是否使用Harris检测算法(参考cornerHarris()函数)或者Shi-Tomasi检测算法(参考cornerMinEigenVal()函数)。
k:Harri角点检测自由参数。
该函数在图像或选定的区域中检测最显著的角点,的功能介绍如下:
(1)该函数在输入图像的每个像素点上使用cornerHarris()函数和cornerMinEigenVal()函数计算角点质量数值。
(2)该函数使用非极大值抑制算法(non-maximumsuppression),3*3邻域内的局部极大值被保留。
,则被忽略。
(4)步骤(3)筛选后剩下的角点按照质量数值从高到低排序。
(5)在每个检测到的角点周围minDistance的范围内,如果有更显著的角点被检测到,则这个角点被忽略。这样也是为了保证最显著的角点被保留下来。
代码示例如下:
/** * @使用Shi-Tomasi方法进行角点检测 * @author holybin */ #include "opencv2/highgui/highgui.hpp" #include "opencv2/imgproc/imgproc.hpp" #include <iostream> #include <stdio.h> #include <stdlib.h> using namespace cv; using namespace std; /// 全局变量 Mat src, srcGray; int maxCorners = 23; //角点个数的最大值 int maxCornersThresh = 1000; //角点个数最大值的上限(滑动条范围0-1000) RNG rng(12345); char* sourceWindow = "src"; /// 角点检测函数声明 void doGoodFeaturesToTrack( int, void* ); int main( int argc, char** argv ) { /// 载入图像并灰度化 src = imread( "D:\\opencv_pic\\house_small.jpg", 1 ); cvtColor( src, srcGray, CV_BGR2GRAY ); /// 创建显示窗口以及滑动条 namedWindow( sourceWindow, CV_WINDOW_AUTOSIZE ); createTrackbar( "max num:", sourceWindow, &maxCorners, maxCornersThresh, doGoodFeaturesToTrack ); imshow( sourceWindow, src ); doGoodFeaturesToTrack( 0, 0 ); waitKey(0); return(0); } /// 角点检测函数实现:标示出每个角点位置 void doGoodFeaturesToTrack( int, void* ) { if( maxCorners < 1 ) maxCorners = 1; /// Shi-Tomasi的参数设置 vector<Point2f> corners; double qualityLevel = 0.01; double minDistance = 10; int blockSize = 3; bool useHarrisDetector = false; //不使用Harris检测算法 double k = 0.04; /// 深度拷贝原图像用于绘制角点 Mat srcCopy = src.clone(); /// 应用角点检测算法 goodFeaturesToTrack( srcGray, corners, maxCorners, qualityLevel, minDistance, Mat(), //未选择感兴趣区域 blockSize, useHarrisDetector, k ); /// 当maxCorners的值较小时,以下两个值基本是一样的; /// 当maxCorners的值较大时,实际检测到的角点数目有可能小于maxCorners,以下两个值不一样。 cout<<"* detected corners : "<<corners.size()<<endl; cout<<"** max corners: "<<maxCorners<<endl; /// 绘制出角点 int r = 4; for( int i = 0; i < corners.size(); i++ ) circle( srcCopy, corners[i], r, Scalar(0,255,0), -1, 8, 0 ); /// 显示结果 namedWindow( sourceWindow, CV_WINDOW_AUTOSIZE ); imshow( sourceWindow, srcCopy ); }
运行结果:
从结果可以看出当角点个数阈值太大时,检测到的角点个数固定在434,也就是最多能检测出434个角点。