与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; }
运行结果:
参考:http://blog.csdn.net/masibuaa/article/details/8998601