一角点检测
兴趣点=关键点=特征点,检测足够多的点,同时他们的区分度很高,则可以精确定位稳定的特征
特征类型分为:
[1]边缘
[2]角点(感兴趣关键点)
[3]斑点(Blobs) (感兴趣区域)
角点是在任意方向的一个微小变动都会引起灰度很大的变化的点。
角点:
[1]一阶导数(灰度的梯度)的局部最大所对应的像素点
[2]两条及两条以上边缘的交点
[3]图像中梯度和梯度方向的变化速率都很高的点
[4]角点处的一阶导数最大,二阶导数为0,它指示了物体边缘变化不连续的方向
1,Harris角点检测
基于灰度图像的角点提取算法,稳定性高。采用高斯滤波,速度较慢,角点信息有丢失和位置偏移的现象,有聚簇现象。
针对每一个像素,在blockSize×blockSize的邻域内,计算
根据设定的阈值threshold,如果R>threshold,则判断为角点
void cornerHarris(InputArray src, OutputArray dst,
int blockSize, int ksize, double k,
int borderType=BORDER_DEFAULT )
//src,单通道8-bit或浮点型图像
//dst,与src同size,type为CV_32FC1,用来存储R值
//blockSize,针对每一个像素的邻域大小
//ksize,进行Sobel边缘检测的ksize
//k,计算公式中的参数k
//borderType,边界拓展类型
应用:
//转化成灰度图
cv::cvtColor(image,Image,CV_BGR2GRAY);
//进行角点检测
cv::Mat process;
int blockSize=2;
int ksize=3;
double k=0.04;
cv::cornerHarris(Image,process,blockSize,ksize,k);
//进行归一化,使值落在0~255
cv::normalize(process,process,0,255,cv::NORM_MINMAX,
CV_32FC1);
//对于大于设定阈值的点,判断为角点
int thresh=120;
for(int i=0;i<result.rows;i++)
for(int j=0;j<result.cols;j++)
if(process.at<float>(i,j)>thresh)
{
cv::circle(result,cv::Point(j,i),5,cv::Scalar(0,0,255),2);
}
效果图:
2,Shi-Tomasi角点检测
用于强角点的检测,是Harris算法的改进版,两个特征值中较小的一个大于最小阈值,会得到强角点
角点检测原理:
[1]首先利用cornerHarris()或者cornerMnEigenVal(),计算角点的质量
[2]执行非极大抑制,在3*3邻域内局部最大值被保留
[3]有最小特征值比还要小的点被抛弃
[4]剩下的角点,根据质量进行递减排序
[5]根据角点间距离minDistance,留下质量好的角点
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-bit或者32位浮点型
*corners,输出被检测到的角点向量,vector<Point2f>
*maxCorners,角点的最大数量
*qualityLevel,用于计算最小特征值的参数,最小特征值
*=qualityLevel×最大特征值,一般为0.01/0.1
*minDistance,角点间的最小距离
*mask,掩码
*blockSize,每个像素邻域
*useHarrisDetector,如果true使用cornerHarris(),否则
*cornerMnEigenVal()
*k,Harris的参数
*/
应用:
//转化成灰度图
cv::cvtColor(image,Image,CV_BGR2GRAY);
//查找角点
std::vector<cv::Point2f> corners;
cv::goodFeaturesToTrack(Image,corners,100,0.01,8);
cv::Size winSize(5,5);
cv::Size zeroZone(-1,-1);
cv::TermCriteria criteria=
cv::TermCriteria(CV_TERMCRIT_EPS+CV_TERMCRIT_ITER,40,0.01);
//进行亚像素精确化
cv::cornerSubPix(Image,corners,winSize,zeroZone,criteria);
//进行标记
for(int i=0;i<corners.size();i++)
{
cv::circle(result,corners[i],5,cv::Scalar(0,0,255),2);
}
效果图:
3,创建自己的角点检测
1>计算角点检测特征值和特征向量
对于每一个像素p,在blockSize×blockSize区域内,通过Sobel计算协变矩阵:
为M的非排序特征值。
x1,y1为的特征向量
x2,y2为的特征向量
存储在dst中
void cornerEigenValsAndVecs(InputArray src, OutputArray dst,
int blockSize, int ksize,
int borderType=BORDER_DEFAULT )
//src,单通道,8-bit或浮点型图像
//dst,与src同size,type为CV_32FC(6)
//blockSize,邻域大小
//ksize,Sobel边缘检测的ksize
//borderType,边界拓展类型
2>为角点检测,计算梯度矩阵的最小的特征值
用来寻找中的最小值
void cornerMinEigenVal(InputArray src, OutputArray dst,
int blockSize, int ksize=3,
int borderType=BORDER_DEFAULT )
//src,单通道,8-bit或浮点型图像
//dst,存储最小的特征值,与src同size,type为CV_32