opencv角点检测(二)
改进的Harris角点检测算法
<span style="font-size:18px;">harris角点检测算法的结果一定程度上取决于系数k,有人对Harris的角点检测算法进行了改进,直接利用像素点协方差矩阵的特征值提取角点。而且不在进行非极大值抑制,而是采用一种容忍距离的形式,在角点的一定范围内只有一个角点。</span>
<span style="font-size:18px;">具体原理:首先计算图像每个像素点的协方差矩阵,并求取对应的特征值,将最小的特征值最大的那个像素点作为第一个角点(具体来说,就是求出每个像素点的协方差矩阵对应的特征值,找出最小的那个,所有最小的特征值中哪个最大,就将哪个所对应的像素点作为角点max(min(e1,e2)),e1、e2为像素协方差矩阵的特征值)。然后依次按照最大最小特征值的顺序寻找角点,并保证在容忍距离内只有一个角点。</span>
<span style="font-size:18px;">opencv测试代码:</span>
<span style="font-size:18px;"></span><pre name="code" class="cpp">#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp><img src="http://img.blog.csdn.net/20150322224206153?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI2MDg5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /><img src="http://img.blog.csdn.net/20150322224206153?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI2MDg5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace std; using namespace cv; Mat src,src_gray; int cornernum = 20; int maxnum = 200; char* windowname = "Imagecorners"; void goodFeaturesdemo(int,void*); int main(int argc,char* argv[]) { src = imread("road.jpg"); cvtColor(src,src_gray,CV_BGR2GRAY);//将图像转化为灰度图; namedWindow(windowname,CV_WINDOW_AUTOSIZE); createTrackbar("CornersNum:",windowname,&cornernum,maxnum,goodFeaturesdemo);//创建控制条,与cornernum变量相 //关联 imshow(windowname,src); goodFeaturesdemo(0,0); waitKey(0); return 0; } void goodFeaturesdemo(int,void*) { if(cornernum < 1){ cornernum = 1;} vector<Point2f> points; double qualityLevel = 0.02; double minDistance = 10; int blockSize = 3; bool useHarrisDetector = false; double k = 0.04; Mat copy; copy = src.clone(); //进行角点检测 goodFeaturesToTrack(src_gray, //要进行检测的图像 points, //存储检测到的角点坐标,Point2f类型 cornernum, //检测到的角点的最大数目 qualityLevel, //角点的阈值条件,即角点的质量等级:qualityLevel*max(min(e1,e2)) minDistance, //容忍距离,单位像素 Mat(), blockSize, useHarrisDetector, k); cout<<"Number of corners detected: "<<points.size()<<endl; int r = 4; for(int i = 0; i < points.size(); i++) { circle(copy,points[i],r,Scalar(0,0,255),1,8); } //namedWindow(windowname,CV_WINDOW_AUTOSIZE); imshow(windowname,copy); }
<img src="http://img.blog.csdn.net/20150322224206153?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI2MDg5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
<span style="font-size:18px;">可以看出检测到的角点比较均匀,不会在一个小区域产生角点聚集的情况。</span>
<span style="font-size:18px;"> </span>
<span style="font-size:18px;"></span><pre name="code" class="cpp">定制自己的角点检测算法:
opencv提供了求取特征值和特征向量的函数,可以实现自己设计的角点提取算法,主要包括下面两个函数:
cornerEigenCalsAndVecs:计算像素对应的特征值和特征向量;
cornerMinEigenVal:求取像素点最小的特征值;
下面程序实现了一个定制化的Harris角点检测算法,和类似的Shi-Tomsi算法:
#include <opencv2/core/core.hpp> #include <opencv2/highgui/highgui.hpp> #include <opencv2/imgproc/imgproc.hpp> #include <iostream> using namespace std; using namespace cv; Mat src,src_gray; Mat myHarris_dst,myHarris_copy,Mc; Mat myShiTomsi_dst,myShiTomsi_copy; int myST_qualityLevel = 50; int myH_qualityLevel = 50; int max_qualityLevel =100; double myHarris_minVal,myHarris_maxVal; double myST_minVal,myST_maxVal; RNG rng(2444); char* myHarris = "myHarris Corner:"; char* myST = "myST Corner:"; void myHarris_function(int,void*); void myST_function(int,void*); int main(int argc,char* argv[]) { src = imread("road.jpg"); cvtColor(src,src_gray,CV_BGR2GRAY); int blocksize = 3; int aperture = 3; myHarris_dst = Mat::zeros(src_gray.size(),CV_32FC(6)); Mc = Mat::zeros(src_gray.size(),CV_32FC1); cornerEigenValsAndVecs(src_gray,myHarris_dst,blocksize,aperture,BORDER_DEFAULT);//求取像素点特征值和特征向 //量,具体参数意义见用户手册;论坛上应该有。 for( int i = 0; i < src_gray.rows; i++) { for(int j = 0; j < src_gray.cols; j++) { float lambda_1 = myHarris_dst.at<Vec6f>(i,j)[0];//取出两个特征值,后几位是特征向量; float lambda_2 = myHarris_dst.at<Vec6f>(i,j)[1]; Mc.at<float>(i,j) = lambda_1*lambda_2 - 0.04*pow((lambda_1+lambda_2),2);//harris角点检测法 } } minMaxLoc(Mc,&myHarris_minVal,&myHarris_maxVal);//求出最大值和最小值,用来筛选角点; namedWindow(myHarris,CV_WINDOW_AUTOSIZE); createTrackbar("Quality Level",myHarris,&myH_qualityLevel,max_qualityLevel,myHarris_function); myHarris_function(0,0); myShiTomsi_dst = Mat::zeros(src_gray.size(),CV_32FC1); cornerMinEigenVal(src_gray,myShiTomsi_dst,blocksize,aperture,4); minMaxLoc(myShiTomsi_dst,&myST_minVal,&myST_maxVal); namedWindow(myST,CV_WINDOW_AUTOSIZE); createTrackbar("Quality Level",myST,&myST_qualityLevel,max_qualityLevel,myST_function); myST_function(0,0); waitKey(); return 0; } void myHarris_function(int,void*) { myHarris_copy = src.clone(); if(myST_qualityLevel < 1) { myST_qualityLevel = 1;} for(int j = 0; j < src_gray.rows ; j++) { for(int i = 0; i < src_gray.cols ; i++) { if( Mc.at<float>(j,i) > myHarris_minVal + (float)(myHarris_maxVal - myHarris_minVal)* myH_qualityLevel/max_qualityLevel) circle(myHarris_copy,Point(i,j),3,Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255)),-1,8,0);//在检测到的焦点位 //置画圆 } } imshow(myHarris,myHarris_copy); } void myST_function(int,void*) { myShiTomsi_copy = src.clone(); for(int i = 0; i < src.rows; i++) { for(int j = 0; j < src.cols ; j++) { if(myShiTomsi_dst.at<float>(i,j) > myST_minVal + (myST_maxVal - myST_minVal)* myH_qualityLevel/max_qualityLevel) circle(myShiTomsi_copy,Point(j,i),3,Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255)),-1,8,0); } } imshow(myST,myShiTomsi_copy); }
<span style="font-size:18px;"><img src="http://img.blog.csdn.net/20150322224743120?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI2MDg5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /> </span>
<span style="font-size:18px;">定制化的Shi-Tomsi算法检测结果:</span>
<span style="font-size:18px;"><img src="http://img.blog.csdn.net/20150322224845286?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI2MDg5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" /> </span>
<span style="font-size:18px;"> </span>
<span style="font-size:18px;">亚像素角点检测:</span>
<span style="font-size:18px;"></span><pre name="code" class="cpp">opencv提供函数cornerSubPixel函数进行亚像素精度的角点检测。具体代码如下:
<pre name="code" class="cpp">#include <iostream> using namespace std; using namespace cv; Mat src,src_gray; int cornersnum = 20; int maxnum = 50; RNG rng(342); char* imgwindow = "Image"; void subPixelCorner(int,void*); int main(int argc,char* argv[]) { src = imread("cat.jpg"); cvtColor(src,src_gray,CV_BGR2GRAY); namedWindow(imgwindow,CV_WINDOW_AUTOSIZE); createTrackbar("Corners NUM:",imgwindow,&cornersnum,maxnum,subPixelCorner); subPixelCorner(0,0); //imshow(imgwindow,src); waitKey(0); return 0; } void subPixelCorner(int,void*) { if(cornersnum < 1) { cornersnum = 1;} Mat copy = src.clone(); vector<Point2f> points; double qualityLevel = 0.03; double minDistance = 10; int blocksize = 3; bool useHarrisDetector = false; double k = 0.045; goodFeaturesToTrack(src_gray, points, cornersnum, qualityLevel, minDistance, Mat(), blocksize, useHarrisDetector, k); cout<<"Number of detected corners:"<<points.size()<<endl; int r = 4; for( int i = 0; i < points.size(); i++) { circle(copy,points[i],r,Scalar(rng.uniform(0,255),rng.uniform(0,255),rng.uniform(0,255)),-1,8,0); } imshow(imgwindow,copy); Size size = Size(5,5); Size zerosize = Size(-1,-1); TermCriteria criteria = TermCriteria(CV_TERMCRIT_EPS + CV_TERMCRIT_ITER,30,0.01);//设置迭代结束的条件 cornerSubPix(src_gray,points,size,zerosize,criteria);//亚像素精度角点检测 for(int j = 0; j < points.size(); j++) { cout<<"Refined Corner ["<<j<<"] : ("<<points[j].x<<","<<points[j].y<<")"<<endl;} }
cornernum阈值为36时的运行结果:
重新定位的亚像素精度的角点:
<img src="http://img.blog.csdn.net/20150322225130178?watermark/2/text/aHR0cDovL2Jsb2cuY3Nkbi5uZXQvdTAxNDI2MDg5Mg==/font/5a6L5L2T/fontsize/400/fill/I0JBQkFCMA==/dissolve/70/gravity/Center" alt="" />
至此,利用opencv检测角点的算法总结完毕,本文的程序是在VC2010+opencv2.4.9+win7下可直接运行;下篇总结不同的特征检测算子。敬请期待!
<span style="font-size:18px;"> </span>