概述
除了之前文章所说的利用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邻域内的局部极大值被保留。
(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个角点。