图像像素区域的兴趣点区域对于目标检测、目标跟踪有很重要的意义。当兴趣点周围存在方形区域时,最易形成角点。对于兴趣点检测。角点反映的是图像中局部最大值或最小值的孤立点,可理解为区域邻域的小方块,存在于不同方形的主边缘处。窗口向任意方向的移动都会导致图像灰度的明显变化,形成的点集称为角点。
1.moravec角点
moravec角点常用于立体匹配,其原理是通过滑动窗口像素变化来实现角点检测,首先计算窗口像素的兴趣值,即以当前像素为中心像素点,取一个正方形
,计算其0°、45°、90°及135°四个方向灰度差的平方和,取其中的最小值作为该兴趣像素点的兴趣值。其公式如下:
moravec角点检测器对每一个兴趣中心点进行滑窗遍历,计算其相关8-邻域方向的特征关系,像素点值位置变化可取(u,v)={(-1.-1),(-1,0),(-1,1),(0,-1),(0,1),(1,-1),(1,0),(1,-1)}。moravec角点检测于其它同类型角点检测相比存在两个缺点:
(1)非均匀性响应:窗口特性决定了在进行角点检测时,很容易受到邻近特性的影响,一般在实验操作前,先进行平滑操作。moravec角点检测算子对斜边缘的响应很强,这是因为只考虑了每隔45°的方向变化,而没有在全部方向上进行考虑。
(2)噪声响应。由于窗口函数是一个二值函数,不管像素点离中心点的距离时多少,均赋于一样的权重,致使其对应的噪声也有很强的响应。moravec角点检测对噪声十分敏感,一般在进行角点检测前,先对图像兴趣区域采用较大的窗口或先进行平滑操作。
#include <opencv2\opencv.hpp> using namespace cv; cv::Mat MoravecCorners(cv::Mat srcImage,int ksize,int threshold) { cv::Mat resMorMat = srcImage.clone(); int r = ksize / 2; const int nRows = srcImage.rows; const int nCols = srcImage.cols; int nCount = 0; CvPoint *pPoint = new CvPoint [nRows * nCols]; for(int i =r;i < srcImage.rows-r;i++) { for(int j =r;j<srcImage.cols-r;j++) { int wV1,wV2,wV3,wV4; wV1 = wV2 = wV3 = wV4 = 0; //计算水平方向窗口内的兴趣值 for(int k = -r;k<r;k++) { wV1 += (srcImage.at<uchar>(i,j+k)- srcImage.at<uchar>(i,j+K+1))*(srcImage.at<uchar>(i,j+k)- srcImage.at<uchar>(i,j+k+1)) } //计算垂直方向窗口内的兴趣值 for(int k =-r;k<r;k++) { wV2 += (srcImage.at<uchar>(i+k,j)-srcImage.at<uchar>(i+k+1,j))* (srcImage.at<uchar>(i+k,j)-srcImage.at<uchar>(i+k+1,j+k+1)); } //计算45°方向窗口内的兴趣值 for(int k =-r;k<r;k++) { wV3 += (srcImage.at<uchar>(i+k,j+k)-srcImage.at<uchar>(i+k+1,j+k+1))* (srcImage.at<uchar>(i+k,j+k)-srcImage.at<uchar>(i+k+1,j+k+1)); } //计算135°方向窗口内的兴趣值 for(int k = -r;k<r;k++) { wV4 += (srcImage.at<uchar>(i+k,j+k)-srcImage.at<uchar>(i+k+1,j-k-1))* (srcImage.at<uchar>(i+k,j-k)-srcImage.at<uchar>(i+k+1,j-k-1)); } int value = min(min(wV1,wV2),min(mV3,mV4)); if(value > threshold) { pPoint[nConut] = cvPoint(j,i); nConut++; } } } for(int i = 0; i < nCount;i++) { circle(resMorMat,pPoint[i],5,Scalar(255,0,0)); } return resMorMat; }
2.harris角点
harris角点在maravec角点的基础上进行了改进,对比于moravec角点连续平方求和,它引入了局部变化因子,利用高斯权重函数特性进行角点检测。对于图像f(x,y),任取窗口块W,进行平移
、
,考虑到局部特性变化,计算图像平移后窗口变化值之差的平方和S如下:
考虑到响应特性,角点不会受到光圈参数的影响,对于
中的高斯响应部分,利用泰勒展开,对于平移后的图像,可变换成下式:
将上式中f(i,j)-f(i-
,j-
)的近似值代入到
中可得到:
最后进行矩阵变换,可得到:
其中,
,
,
,对于局部微小移动量[u,v],窗口移动导致的图像灰度变化,时矩阵变换中实对称矩阵M。
其中M为2x2矩阵,由图像导数可得参数对应于a、b、c及d。对于局部结构矩阵M代表的邻域,将实对称矩阵对角化处理后,对应项可以理解为旋转因子,经过对角化处理后,根据两个正交方向的变化分量计算其相应的特征值
,
。如果两个特征值均较大且数值相当,则图像窗口在所有方向上的移动都将产生明显的灰度变化,可判断其将形成角点。如果仅有一个特征值较高且远大于另一特征值,则可以得到相应边缘,其它情况下可以得到稳定区域。基于上述特征值特性。harris角点理论提出了相应的角点响应函数。如下式所示:
其中k为常量因子,通常情况取值为0.04~0.06,对图像窗口内数据进行求和加权,实际上可以更好地刻画窗口中心特性。Harris角点在时间复杂度上更高于moravec角点,其对噪声页十分敏感,也存在非均匀响应。harris角点检测器检测率高,且可以得到重复响应。其实现步骤如下:
(1)利用水平于垂直差分算子对图像进行卷积操作,计算得到相应地
,根据实对称矩阵M的组成,计算对应矩阵元素的值。
(2)利用高斯函数对矩阵M进行平滑操作,得到新的M矩阵,步骤1和步骤2可以改变顺序。
(3)对每一个像素和给定的邻域窗口,计算局部特征结果矩阵M的特征值和相应函数
(4)选取响应函数C的阈值,根据非极大值抑制原理,同时满足阈值及某邻域内的局部极大值为候选角点。
void CornerHarris(const Mat& srcImage,Mat& result,int blockSize,int ksize,double k) { Mat src; srcImage.copyTo(src); result.create(src.size(),CV_32F); int depth = src.depth(); //检测掩膜尺寸 double scale = (double)(1<<((ksize>0?ksize:3)-1))*blockSize; if(depth == CV_8U) { scale *= 255.; } scale = 1./scale; //sobel滤波 Mat dx,dy; Sobel(src,dx,CV_32F,1,0,kSize,scale,0); Sobel(src,dy,CV_32F,0,1,kSize,scale,0); cv::Mat cov(size,CV_32FC3); int i,j; for(i =0;i<size.height;i++) { float *covData = (float*)(cov.data+i*cov.step); const float *dxData = (const float*)(dx.data + i*dx.step); const float *dyData = (const float*)(dy.data + i*dy.step); for(j=0;j<size.width;j++) { float dx_ = dxData[j]; float dy_ = dyData[j]; covData[3*j] = dx_*dx_; covData[3*j + 1] = dx_*dy_; covData[3*j + 2] = dy_*dy_; } } boxFilter(cov,cov.cov.depth(),Size(blockSize,blockSize),Point(-1,-1),false); if(cov.isContinuous()&&result.isContinuous()) { size.width *= size.height; size.height = 1; } else { size = result.size(); } for(i=0;i<size.height;i++) { float *resultData = (float*)(result.data + i*result.step); const float *covData = (const float*)(cov.data+i*cov.step); for(j=0;j<size.width;j++) { float a = covData[3*j]; float b = covData[3*j+1]; float c = covData[3*j+2]; resultData[j] = a*c - b*b - k*(a+c)*(a+c); } } }
3.Shi-Tomasi角点
harris算法中角点响应函数的定义为:
,而Shi-Tomasi角点检测则选取了不同的角点响应函数:
.
Shi-Tomasi角点检测划分相关一对一匹配对,依据图像的角点特征、图像灰度和位置信息,采用最大互相关函数进行相似度计算,最终实现角点检测。
Opencv中利用函数goodFeaturesToTrack实现该算法,函数原型如下:
void goodFeaturesToTrack(InputArray image,OutputArray corners,int maxCorners,double qualityLevel,double minDistance,InputArray mask = noArray(),int blockSize = 3,bool useHarrisDetecector=false,double k =0.04)
参数image为输入单通道图像,corners为检测到的角点输出矩阵,maxCorners表示检测到的角点输出的最大数目,如果检测到的角点数目大于该值,则选取更强的角点输出;qualityLevel表示可允许接受的角点最差质量,该参数使用时将该数值乘以最佳角点的质量数值来删除角点;minDistance表示返回角点间的最小的欧式距离,用于限定近邻像素被检测出角点的可能性,mask为可选参数为兴趣区域,若输入图像非空,它将被限定到检测到角点区域;blocksize表示像素邻域中计算协方差矩阵窗口的尺寸;useHarrisDetector应用harris检测来确定;k为经验常数。