SUSAN角点检测与匹配算法代码(OpenCV)

SUSAN角点检测与匹配算法

    • 测试环境Ubuntu+OpenCV2.4.3
    • SUSAN角点检测代码

SUSAN(Small univalue segment assimilating nucleus)是一种基于灰度图像以及窗口模板的 特征点获取方法,适用于图像中边缘和角点的检测,对噪声鲁棒,而且具有简单、有效、计算速度快等特点。本文结合SUSAN算法原理, 实现SUSAN角点检测,并结合 Brief描述子,实现 角点匹配算法。话不多说,直接上代码,代码有详细的注释!后面还有相应的论文,感兴趣的可以深入研究一下。

测试环境Ubuntu+OpenCV2.4.3

ubuntu下安装OpenCV的过程可以参考这篇博客。其他的版本可能会有一些问题,但是应该可以按照代码的思路简单解决。

SUSAN角点检测代码

#include 
#include "opencv2/opencv.hpp"
#include "opencv2/highgui/highgui.hpp"    
#include "opencv2/nonfree/nonfree.hpp"  
#include "opencv2/features2d/features2d.hpp"
#include "opencv2/legacy/legacy.hpp" 
#include  
using namespace std;
using namespace cv;
void  MySusan(Mat imageGray, vector<Point2f>& corners);

int main(int argc, char **argv)
{
    Mat image1 = imread("../image/1.jpg", 1);//读取图像
    Mat image2 = imread("../image/2.jpg", 1);//读取图像
    Mat imageGray1,imageGray2;
    cvtColor(image1,imageGray1,CV_RGB2GRAY);//将彩色图转化为灰度图
    cvtColor(image2,imageGray2,CV_RGB2GRAY);//将彩色图转化为灰度图
    IplImage  pBinary1 = image1,pBinary2 = image2;  
    IplImage *input1 = cvCloneImage(&pBinary1);//转化为iplpmage类型指针
    IplImage *input2 = cvCloneImage(&pBinary2);//转化为iplpmage类型指针
    vector<Point2f> corners1,corners2;		//角点
    vector<KeyPoint> keypoints1,keypoints2;        //关键点
    MySusan(imageGray1, corners1);
    MySusan(imageGray2, corners2);
    
    CvScalar color1 =CV_RGB(255,0,0);
    CvScalar color2 =CV_RGB(0,255,0);
    for(int i=0;i<corners1.size();i++)
    {
      cvCircle(input1, cvPoint((int)(corners1[i].x), (int)(corners1[i].y)), 2, color1, 1, CV_AA, 0);//圈出角点
    }
    
    for(int i=0;i<corners2.size();i++)
    {
      cvCircle(input2, cvPoint((int)(corners2[i].x), (int)(corners2[i].y)), 2, color2, 1, CV_AA, 0);//圈出角点
    }
    KeyPoint::convert(corners1,keypoints1);
    KeyPoint::convert(corners2,keypoints2);
    
    
    //特征点描述,为下边的特征点匹配做准备    
//    SiftDescriptorExtractor SiftDescriptor;
    BriefDescriptorExtractor  Descriptor;
    Mat imageDesc1, imageDesc2;
    Descriptor.compute(imageGray1,keypoints1 , imageDesc1);
    Descriptor.compute(imageGray2, keypoints2, imageDesc2);

    BruteForceMatcher< L2<float> > matcher;  
//  FlannBasedMatcher< L2 > matcher;
    vector<vector<DMatch> > matchePoints;
    vector<DMatch> GoodMatchePoints;
    matcher.knnMatch(imageDesc2, imageDesc1, matchePoints,2);//获取两个最优匹配点,在imageDesc2中找imageDesc1的2个最佳匹配点
    cout << "total match points: " << matchePoints.size() << endl;

    // Lowe's algorithm,获取优秀匹配点
    for (int i = 0; i < matchePoints.size(); i++)
    {
        if (matchePoints[i][0].distance < 0.4 * matchePoints[i][1].distance)
        {
            GoodMatchePoints.push_back(matchePoints[i][0]);
        }
    }
    cout << "GoodMatchePoints: " << GoodMatchePoints.size() << endl;
    Mat first_match;
    drawMatches(image2, keypoints2, image1, keypoints1, GoodMatchePoints, first_match);
    imshow("first_match ", first_match);
    imwrite("first_match.jpg", first_match);
    
    
    
    
//     cout<<"corners1.size="<
//     cout<<"corners2.size="<
//     imshow("imageBefore1",image1);
//     cvShowImage("imageAfter1",input1);
//     cvSaveImage( "ImageAfter1.jpg", input1);
//     imshow("imageBefore2",image2);
//     cvShowImage("imageAfter2",input2);
//     cvSaveImage( "ImageAfter2.jpg", input2);
    
     waitKey();
    return 0;
}


//susan角点检测
//输入灰度图,输出角点
void  MySusan(Mat imageGray, vector<Point2f>& corners)
{ 
    long int Imagewidth=imageGray.cols;
    long int Imageheight=imageGray.rows;//得到图像高宽
    cout<<"Imagewidth="<<Imagewidth<<" 	 Imageheight=" <<Imageheight<<endl;
    int threshold = 50;		//判断灰度相近的阈值(可调)
    long int i,j,c=0,u=0,g=0,max=0;
    int usan[(Imagewidth-6)*(Imageheight-6)];	// 当前像素和窗体内像素差别在t以下的个数,即相似的个数(一维)
    int imgn[Imageheight-6][Imagewidth-6];	// 当前像素和窗体内像素差别在t以下的个数,即相似的个数(二维)
    uchar *p1,*p2,*p3;
    
//  计算以像素为中心的窗体内包含的
//  包含37个像素的圆窗口,面积为12*pi=37,因此是以sqrt(12)为半径的原
//  没有在外围扩展图像,最终图像会缩小
    for(i=3;i<Imageheight-3;i++)  
    {
	p1=imageGray.ptr<uchar>(i);
        for(j=3;j<Imagewidth-3;j++)  
        {  
		//从原图中截取7*7的区域再在其中挑选圆窗
		Rect rect(j-3, i-3, 7,7);
		Mat image_tmp = imageGray(rect);
		//c表示灰度值相近的程度,越大越相近
		c=0;
		for(int p=0;p<7;p++)
		{
			p2=image_tmp.ptr<uchar>(p);
			for(int q=0;q<7;q++)
			{
				//在7*7的区域中选取圆窗包含的像素
				if((pow(p-3,2)+pow(q-3,2))<=12)
				{
				// 判断灰度是否相近,t是自己设置的
					if(abs(p1[j]-p2[q])<=threshold)
					{
						c++;	
					}
				}
			}		
		}
	    usan[u++]=c;
	}
    }
    cout<<"usansize="<<(Imagewidth-6)*(Imageheight-6)<<endl;
    for(i=0;i<(Imagewidth-6)*(Imageheight-6);i++)
    {
	if(usan[i]>g)   g=usan[i];     //找最大值
    }
//     相当于进一步调整阈值,在threshold的基础上进一步减少角点个数
    g=0.5*g;	//g通常取max/2
     for(i=0;i<(Imagewidth-6)*(Imageheight-6);i++)
    {
      if(usan[i]<g)   
	usan[i]=g-usan[i];
      else
	usan[i]=0;
    }
    for(i=0;i<Imageheight-6;i++)
    {
      for(j=0;j<Imagewidth-6;j++)
      {
	imgn[i][j]=usan[i*(Imagewidth-6)+j];
      }
    }
//    非极大抑制
   //3*3 
     for(i=1;i<Imageheight-7;i++)
    {
      for(j=1;j<Imagewidth-7;j++)
      {
	    if(imgn[i][j]>imgn[i-1][j-1]&&imgn[i][j]>imgn[i-1][j]&&imgn[i][j]>imgn[i-1][j+1]&&imgn[i][j]>imgn[i][j-1]
	      &&imgn[i][j]>imgn[i][j+1]&&imgn[i][j]>imgn[i+1][j-1]&&imgn[i][j]>imgn[i+1][j]&&imgn[i][j]>imgn[i+1][j+1])
	    {
		corners.push_back(cvPoint(j+3,i+3));//之前是从第3行3列开始检测的,这里加上3
	    }
      }
    }   
}

Paper: SUSAN — A New Approach to Low Level Image Processing

你可能感兴趣的:(特征匹配,算法,SUSAN,特征检测,特征匹配,OpenCV,角点)