opencv2.4 sift算法的使用

与opencv2.3.1版本的sift算法的编程方法有所不同,貌似opencv2.4版本之后将sift、surf算法移到了nonfree区。

所以,需要包换的头文件:

#include <nonfree/features2d.hpp>

#include <nonfree/nonfree.hpp>

增加静态链接库:

opencv_nonfree249d.lib和opencv_features2d249d.lib

注:在使用 initModule_nonfree()函数时,需要用到 opencv_nonfree249d.lib 这个链接库,才能不出现“无法解析的外部符号”。


具体SIFT算法的运算过程是这样的:

1、用FeatureDetector创建相应的特征检测器,并调用FeatureDetector::detect()函数,来求取特征点,并保存在KeyPoint的vector容器中。

特征检测器如下:

Ptr<FeatureDetector> detector = FeatureDetector::create( "SIFT" );//创建SIFT特征检测器 

其中FeatureDetector::create()函数的参数可选:

• "FAST" – FastFeatureDetector

• "STAR" – StarFeatureDetector
• "SIFT" – SIFT (nonfree module)
• "SURF" – SURF (nonfree module)
• "ORB" – ORB
• "BRISK" – BRISK
• "MSER" – MSER
• "GFTT" – GoodFeaturesToTrackDetector
• "HARRIS" – GoodFeaturesToTrackDetector with Harris detector enabled
• "Dense" – DenseFeatureDetector
• "SimpleBlob" – SimpleBlobDetector


Keypoints特征点类定义如下:

       class KeyPoint
       {
              Point2f  pt;  //坐标
              float  size; //特征点邻域直径
              float  angle; //特征点的方向,值为[0,360),负值表示不使用
              float  response; //
              int  octave; //特征点所在的图像金字塔的组
              int  class_id; //用于聚类的id
       }


2、用DescriptorExtractor创建相应的特征向量生成器,并调用DescriptorExtractor::compute()函数,来求取特征矩阵,保存在Mat型变量中。

特征向量生成器定义如下:

Ptr<DescriptorExtractor> descriptor_extractor = DescriptorExtractor::create( "SIFT" );//创建特征向量生成器  

其中DescriptorExtractor::create()函数的参数如下:

• "SIFT" – SIFT
• "SURF" – SURF
• "BRIEF" – BriefDescriptorExtractor
• "BRISK" – BRISK
• "ORB" – ORB
• "FREAK" – FREAK


3、用DescriptorMatcher创建特征匹配器,并调用DescriptorMatcher::match()函数,求取两幅图像之间的匹配点,并保存在DMatch的vector容器中。

特征匹配器定义如下:

Ptr<DescriptorMatcher> descriptor_matcher = DescriptorMatcher::create( "BruteForce" );//创建特征匹配器
其中DescriptorMatcher::create()函数的参数如下,对应不同的匹配算法:

– BruteForce (it uses L2 ) 
– BruteForce-L1
– BruteForce-Hamming
– BruteForce-Hamming(2)
– FlannBased


DMatch结构体定义如下:

       struct DMatch
       {
              //三个构造函数
           DMatch(): queryIdx(-1), trainIdx(-1),imgIdx(-1),distance(std::numeric_limits<float>::max()) {}
           DMatch(int  _queryIdx, int  _trainIdx, float  _distance ) :
                            queryIdx( _queryIdx),trainIdx( _trainIdx), imgIdx(-1),distance( _distance) {}
           DMatch(int  _queryIdx, int  _trainIdx, int  _imgIdx, float  _distance ) :
                   queryIdx(_queryIdx), trainIdx( _trainIdx), imgIdx( _imgIdx),distance( _distance) {}
 
           intqueryIdx;  //此匹配对应的查询图像的特征描述子索引
           inttrainIdx;   //此匹配对应的训练(模板)图像的特征描述子索引
           intimgIdx;    //训练图像的索引(若有多个)
           float distance;  //两个特征向量之间的欧氏距离,越小表明匹配度越高。
           booloperator < (const DMatch &m) const;
       };


4、调用drawMatches()函数绘制匹配结果。


例程如下:

#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <features2d/features2d.hpp>
#include <nonfree/features2d.hpp>
#include <nonfree/nonfree.hpp>
#include <iostream>


using namespace cv;
using namespace std;



int main()
{
	/*SIFT算法*/
	Mat image1=imread("E:\\test\\lena.bmp",0);
	Mat image2=imread("E:\\test\\lena_Match.bmp",0);
	initModule_nonfree();   //初始化模块,使用SIFT或SURF时用到  
	Ptr<FeatureDetector> detector = FeatureDetector::create( "SIFT" );//创建SIFT特征检测器  
	Ptr<DescriptorExtractor> descriptor_extractor = DescriptorExtractor::create( "SIFT" );//创建特征向量生成器  
	Ptr<DescriptorMatcher> descriptor_matcher = DescriptorMatcher::create( "BruteForce" );//创建特征匹配器  
	if( detector.empty() || descriptor_extractor.empty() )  
		cout<<"fail to create detector!"; 


	//检测特征点
	vector<KeyPoint> vkKeypoints1,vkKeypoints2;
	detector->detect(image1,vkKeypoints1);
	detector->detect(image2,vkKeypoints2);
	cout<<"图像1特征点个数:"<<vkKeypoints1.size()<<endl;
	cout<<"图像2特征点个数:"<<vkKeypoints2.size()<<endl;


	//根据特征点计算特征描述子矩阵,即特征向量矩阵 
	Mat mDescriptors1,mDescriptors2;
	descriptor_extractor->compute( image1, vkKeypoints1, mDescriptors1);
	descriptor_extractor->compute(image2, vkKeypoints2, mDescriptors2);
	cout<<"图像1特征描述矩阵大小:"<<mDescriptors1.size() <<",特征向量个数:"<<mDescriptors1.rows<<",维数:"<<mDescriptors1.cols<<endl;
	cout<<"图像2特征描述矩阵大小:"<<mDescriptors2.size() <<",特征向量个数:"<<mDescriptors2.rows<<",维数:"<<mDescriptors2.cols<<endl;


	//特征匹配
	vector<DMatch> vdMatches;
	descriptor_matcher->match(mDescriptors1,mDescriptors2,vdMatches);


	//筛选匹配结果
	//距离是指两个特征向量间的欧式距离,表明两个特征的差异,值越小表明两个特征点越接近
	int nMinDis=100,nMaxDis=0;
	for (int i=0;i<vdMatches.size();i++)
	{
		if (nMinDis>vdMatches[i].distance)
			nMinDis=vdMatches[i].distance;
		if (nMaxDis<vdMatches[i].distance)
			nMaxDis=vdMatches[i].distance;
	}
	cout<<"最大距离:"<<nMaxDis<<endl;  
	cout<<"最小距离:"<<nMinDis<<endl; 
	vector<DMatch> vdGoodMatches;
	for (int i=0;i<vdMatches.size();i++)
	{
		if (vdMatches[i].distance < nMaxDis * 0.3)	//0.3为参考值,距离是指两个特征向量间的欧式距离,表明两个特征的差异,
													//值越小表明两个特征点越接近 。越小结果越精,但剩下的点少;越大结果
													//越粗,剩下的点多
			vdGoodMatches.push_back(vdMatches[i]);
	}


	//画出匹配结果
	Mat mMatchResult;
	drawMatches(image1,vkKeypoints1,image2,vkKeypoints2,vdGoodMatches,
		mMatchResult,
		Scalar::all(-1),							//Scalar::all(-1)表示将各匹配点颜色随机生成
		CV_RGB(0,255,0),							//未匹配点的颜色
		Mat(),										
		DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);	//NOT_DRAW_SINGLE_POINTS 不画出未匹配点


	namedWindow("Match");
	imshow("Match",mMatchResult);
	waitKey();


	return 0;
}



注:如果仅仅想画出特征点,可调用 drawKeypoints()函数实现,如:drawKeypoints(img1,keypoints1,img_keypoints1,Scalar::all(-1),0); 

运行结果:

opencv2.4 sift算法的使用_第1张图片

opencv2.4 sift算法的使用_第2张图片


参考:http://blog.csdn.net/masibuaa/article/details/8998601


你可能感兴趣的:(opencv2.4 sift算法的使用)