Opencv学习之角点检测
在图像处理和计算机视觉领域,兴趣点(interest points),也被称作关键点(key points)、特征点(feture points)。它被大量用于解决物体识别、图像识别、图像匹配、视觉跟踪、三维重建等一系列的问题,如果能检测到足够多特殊的点,同时它们的区分度很高,并且可以精确定位稳定的特征,那么这个方法就具有使用价值。
图像特征类型被分为以下三种:
(1)边缘
(2)角点(感兴趣关键点):如果某一点在任意方向的一个微小变动都会引起灰度很大的变化。
(3)斑点(Blobs)(感兴趣区域)
关于角点的具体描述:
*一阶导数(灰度的梯度)的局部最大所对应的像素点。
*两条及两条以上边缘的交点。
*图像中梯度值和梯度方向的变化速率都很高的点。
*角点处的一阶导数最大,二阶导数为零,它指示了物体边缘变化不连续的方向。
目前图像处理领域角点检测算法归纳:
*基于灰度图像的角点检测(又分为,基于梯度、基于模板(图像亮度的变化,将邻点亮度对比足够大的点定义为角点)、基于模板梯度组合三类方法)
*基于二值图像的角点检测
*基于轮廓曲线的角点检测
Harris角点检测是一种直接基于灰度图像的角点提取算法,稳定性高,尤其对L型角点检测精度高。但由于采用了高斯滤波,运算速度相对较慢,角点信息有丢失和位置偏移的现象,而且角点提取有聚簇现象。
void cornerHarris(inputArray src,outputArray dst,int blockSize,int ksize,double k, int borderType=BORDER_DEFAULT)
*第一个参数,输入图像,须为单通道8位或者浮点型图像。
*第二个参数,用于存放Harris角点检测的输出结果,和源图像有一样的尺寸和类型。
*第三个参数,表示邻域的大小。
*第四个参数,表示Sobel()算子的孔径大小。
*第五个参数,Harris焦点响应函数中的参数。
*第六个参数,图像像素的边界模式,默认值BORDER_DEFAULT。
#include
#include
#include
using namespace cv;
//宏定义部分
#define WINDOW_NAME1 "image[procedure window1]"
#define WINDOW_NAME2 "image[procedure window2]"
//全局变量声明
Mat g_srcImage,g_srcImage1,g_grayImage;
int g_nThresh=30;//当前阈值
int g_nThresh_max=175;//最大阈值
//全局函数声明
void on_CornerHarris(int ,void *);//回调函数
//主函数
int main()
{
//载入源图像显示并进行克隆保存
g_srcImage=imread("/Users/new/Desktop/2.jpg");
if(!g_srcImage.data){printf("读取源图像srcImage错误~!\n");return false;}
imshow(WINDOW_NAME1, g_srcImage);
g_srcImage1=g_srcImage.clone();
//转换为灰度图像
cvtColor(g_srcImage1, g_grayImage, COLOR_BGR2GRAY);
//创建窗口和阈值滑动条
namedWindow(WINDOW_NAME1);
createTrackbar("threshold: ", WINDOW_NAME1, &g_nThresh, g_nThresh_max,on_CornerHarris);
on_CornerHarris(0, 0);
waitKey(0);
return 0;
}
//回调函数定义
void on_CornerHarris(int ,void *)
{
//定义一些局部变量
Mat dstImage;//目标图
Mat normImage;//归一化后图
Mat scaledImage;//线性变换后的八位无符号整型的图
//初始化
//置零当前需要显示的两幅图,即清除上一次调用此函数时他们的值
dstImage=Mat::zeros(g_srcImage.size(), CV_32FC1);
g_srcImage1=g_srcImage.clone();
//正式检测
//进行角点检测
cornerHarris(g_grayImage, dstImage, 2, 3, 0.04);
//归一化
normalize(dstImage, normImage,0,255,NORM_MINMAX,CV_32FC1,Mat());
//将归一化后的图线性变换成8位无符号整型
convertScaleAbs(normImage, scaledImage);
//进行绘制
for(int j=0;jfor(int i=0;iif((int)normImage.at<float>(j,i)>g_nThresh+80)
{
circle(g_srcImage1, Point(i,j), 3, Scalar(10,10,255),2,8,0);
circle(scaledImage, Point(i,j), 3, Scalar(10,10,255),2,8,0);
}
}
//显示最终结果
imshow(WINDOW_NAME1,g_srcImage1);
imshow(WINDOW_NAME2,scaledImage);
}
Shi-Tomasi算法是Harris算法的改进,此算法最原始的定义是将矩阵M的行列式与M的迹相减,再将差值同预先给定的阈值进行比较,后来Shi和Tomasi提出了改进方法,若两个特征值中较小的一个大于最小的阈值的话,则会得到强角点。
goodFeaturesToTrack函数就是确定图像强角点的函数。
void goodFeaturesToTrack(inputArray image,outputArray corners,int maxCorners,double qualityLevel,double minDistance,inputArray mask=noArray(),int blockSize=3,bool useHarrisDetector=false,double k=0.4)
*第一个参数,输入图像,须为8位或浮点型32位单通道图像。
*第二个参数,检测到的角点的输出向量。
*第三个参数,角点的最大数量。
*第四个参数,角点检测可接受的最小特征值。其实实际用于过滤角点的最小特征值时qualityLevel与图像中最大特征值的乘积。所以qualityLevel通常不会超过1(常用的值为0.10或者0.01),而检测完所有的角点后,还要进一步剔除掉一些距离较近的角点。
*第五个参数,角点之间的最小距离,此参数用于保证返回的角点之间的距离不小于此参数个像素。
*第六个参数,可选参数,表示感兴趣区域,默认值noArray(),若此参数非空(需为CV_8UC1类型,且和第一个参数image有相同的尺寸),便用于指定角点检测区域。
*第七个参数,默认值3,是计算导数自相关矩阵时指定的邻域范围。
*第八个参数,默认值false,只是是否使用Harris角点检测。
*第九个参数,默认值0.04,为用于设置Hessian自相关矩阵行列式的相对权重的权重系数。
另外值得一提,goodFeaturesToTrack函数可以用来初始化一个基于点的对象跟踪操作。
#include
#include
#include
#include
using namespace cv;
using namespace std;
//宏定义部分
#define WINDOW_NAME1 "image[Shi-Tomasi corner dtector]"
//全局变量声明
Mat g_srcImage,g_grayImage;
int g_maxCornerNumber=33;
int g_maxTrackbarNumber=500;
RNG g_rng(12345);
//全局函数声明
void on_GoodFeaturesToTrack(int ,void *);//回调函数
//主函数
int main()
{
//载入源图像并将其转换为灰度图
g_srcImage=imread("/Users/new/Desktop/2.jpg");
if(!g_srcImage.data){printf("读取源图像srcImage错误~!\n");return false;}
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
//创建窗口和滑动条
namedWindow(WINDOW_NAME1);
createTrackbar("max corners_num: ", WINDOW_NAME1, &g_maxCornerNumber, g_maxTrackbarNumber,on_GoodFeaturesToTrack);
imshow(WINDOW_NAME1,g_srcImage);
on_GoodFeaturesToTrack(0, 0);
waitKey(0);
return 0;
}
//回调函数定义
void on_GoodFeaturesToTrack(int ,void *)
{
//对变量小于等于1时的处理
if(g_maxCornerNumber<=1){g_maxCornerNumber=1;}
//Shi-Tomasi算法的参数准备
vector corners;
double qualityLevel=0.01;//角点检测可接受的最小特征
double minDistance=10;//角点之间的最小距离
int blockSize=3;//计算导数自相关矩阵时指定的邻域范围
double k=0.04;//权重系数
Mat copy=g_srcImage.clone();//复制源图像到一个临时变量中,作为感兴趣区域
//进行Shi-Tomasi角点检测
goodFeaturesToTrack(g_grayImage, corners, g_maxCornerNumber, qualityLevel, minDistance,Mat(),blockSize,false,k);
//输出文字信息
cout<<">此次检测到的角点数量为:"<//绘制检测到的角点
int r=4;
for(unsigned int i=0;i//以随机颜色绘制角点
circle(copy, corners[i], r, Scalar(g_rng.uniform(0, 255),g_rng.uniform(0, 255),g_rng.uniform(0, 255)),-1,8,0);
}
imshow(WINDOW_NAME1, copy);
}
若进行图像处理的目的不是提取用于识别的特征点而是进行几何测量,这通常需要更高的精度,而函数goodFeaturesToTrack函数只能提供简单的像素的坐标值,也就是说,有时候会需要实数坐标值而不是整数坐标值。
亚像素级角点检测的位置在摄像机标定、跟踪并重建摄像机的轨迹,或者重建被跟踪目标的三维结构时,是一个基本的测量值。
cornerSubPix函数用于寻找亚像素角点位置(不是整数类型的位置,而是更精确的浮点类型的位置)。
void cornerSubPix(inputArray image,inputoutputArray corners,Size winSize,Size zeroZone,TermCriteria criteria)
*第一个参数,输入图像。
*第二个参数,提供输入角点的初始坐标和精确的输出坐标。
第三个参数,搜索窗口的一半尺寸,若winSize=Size(5,5),那么就表示使用(5*2+1)(5*2+1)=11x11大小的搜索窗口。
*第四个参数,表示死区的一半尺寸,而死区为不对搜索区的中央位置做求和运算的区域,用来避免自相关矩阵出现的某些可能的奇异性。值(-1,-1)表示没有死区。
*第五个参数,求角点的迭代过程的终止条件,即角点位置的确定,要么迭代数大于某个设定值,或者是精确度达到某个设定值,criteria可以是最大迭代数目,或者是设定的精确度,也可以是它们的组合。
#include
#include
#include
#include
using namespace cv;
using namespace std;
//宏定义部分
#define WINDOW_NAME1 "image[Shi-Tomasi corner dtector]"
//全局变量声明
Mat g_srcImage,g_grayImage;
int g_maxCornerNumber=33;
int g_maxTrackbarNumber=500;
RNG g_rng(12345);
//全局函数声明
void on_GoodFeaturesToTrack(int ,void *);//回调函数
//主函数
int main()
{
//载入源图像并将其转换为灰度图
g_srcImage=imread("/Users/new/Desktop/2.jpg");
if(!g_srcImage.data){printf("读取源图像srcImage错误~!\n");return false;}
cvtColor(g_srcImage, g_grayImage, COLOR_BGR2GRAY);
//创建窗口和滑动条
namedWindow(WINDOW_NAME1);
createTrackbar("max corners_num: ", WINDOW_NAME1, &g_maxCornerNumber, g_maxTrackbarNumber,on_GoodFeaturesToTrack);
imshow(WINDOW_NAME1,g_srcImage);
on_GoodFeaturesToTrack(0, 0);
waitKey(0);
return 0;
}
//回调函数定义
void on_GoodFeaturesToTrack(int ,void *)
{
//对变量小于等于1时的处理
if(g_maxCornerNumber<=1){g_maxCornerNumber=1;}
//Shi-Tomasi算法的参数准备
vector corners;
double qualityLevel=0.01;//角点检测可接受的最小特征
double minDistance=10;//角点之间的最小距离
int blockSize=3;//计算导数自相关矩阵时指定的邻域范围
double k=0.04;//权重系数
Mat copy=g_srcImage.clone();//复制源图像到一个临时变量中,作为感兴趣区域
//进行Shi-Tomasi角点检测
goodFeaturesToTrack(g_grayImage, corners, g_maxCornerNumber, qualityLevel, minDistance,Mat(),blockSize,false,k);
//输出文字信息
cout<<">此次检测到的角点数量为:"<//亚像素角点检测的参数设置
Size winSize=Size(5,5);
Size zeroZone=Size(-1,-1);
TermCriteria criteria=TermCriteria(TermCriteria::EPS+TermCriteria::MAX_ITER,400, 0.001);
//计算出亚像素点角点位置
cornerSubPix(g_grayImage, corners, winSize, zeroZone, criteria);
//输出角点信息
for(int i=0;icout<<"\t精确角点坐标["<"]("<","<")"<//绘制检测到的角点
int r=4;
for(unsigned int i=0;i//以随机颜色绘制角点
circle(copy, corners[i], r, Scalar(g_rng.uniform(0, 255),g_rng.uniform(0, 255),g_rng.uniform(0, 255)),-1,8,0);
}
imshow(WINDOW_NAME1, copy);
}
(1) //将归一化后的图线性变换成8位无符号整型
convertScaleAbs(normImage, scaledImage);
(2)定义角点的迭代过程的终止条件:
TermCriteria criteria=TermCriteria(TermCriteria::EPS+TermCriteria::MAX_ITER,400, 0.001);