众所周知,自opencv3.0版本以来,各种改动层出不穷,与opencv2相比还是有很大差别的。从学习《OpenCV3编程入门》这本书你就能发现,前面可能还好,到后面比较复杂的图像处理,如特征提取,简直大改。3.0把特征提取相关的函数整合在了opencv_contrib中,需要你自己配置,然后就算你花了130分钟配置好了也会发现书中的示例程序照样用不了。因为好多函数包括头文件都有改动,关键作者懒死噜,一丝线索都没透露直接用的opencv2的版本,真素气cry!!!没办法,只能苦了我们这些用opencv3版本的了,最恶熏的是网上还不好找资料,所以花了我130分钟的时间才成功运行呕!接下来就给大家分享吧!
opencv_contrib的配置
首先最重要的一步就是opencv_contrib的配置,需要用到cmake,我用的是VS2015+OpenCV3.2.0,当时配置这个opencv_contrib也是花了不少时间,具体教程我就不介绍了,网上还是挺多的,当然能不能一次成功就看你的运气噜,毕竟不是谁都有神淋眷顾的嘻嘻。下面给出一个配置教程的链接,openCV3.2.0配置VS2013(自用)+opencv_contrib安装,建议大家多找几个教程对比一下,综合起来成功率会高一点。
头文件的变动
我选用的是书上的11.2.3 示例程序:SURF特征提取的代码,代码不长,但是要改的地方真的不少呕。首先是头文件,好多都整合到了opencv_contrib中,像原先放在nonfree.hpp的SURF和legacy.hpp中的BruteForce相关函数,现在都放在了xfeatures2d.hpp里面。所以你只需如下添加这个头文件,当然前提是你要配置好opencv_contrib。
#include<opencv2/xfeatures2d.hpp>
using namespace xfeatures2d;
这个命名空间也非常重要,不然那些相关函数你照样用不了,所以真的很无语呕,麻烦死噜!
定义特征检测类对象
书上的代码是
SurfFeatureDetector detector(minHessian);
detector.detect(srcImage1, keypoint1);
opencv3的版本则改成了如下的指针定义方式,因此需要用箭头调用detect()函数,方法有两种,一种和原来一样用SurfFeatureDetector定义类,另一种方法则是直接用SURF定义,这种似乎是通用法,,包括特征提取也是用这个
方法一:
Ptr< SurfFeatureDetector >detector = SurfFeatureDetector::create(minHessian);
detector->detect(srcImage1, keypoint1);
方法二:
Ptr< SURF> detector =SURF::create(minHessian);
detector->detect(srcImage1, keypoint1);
计算描述符(特征向量)
书上的代码是
SurfDescriptorExtractor extractor;
extractor.compute(srcImage1, keypoint1, descriptors1);
改动如下,由此可得,只要是关于定义类的代码,都可以按照如下的方式进行定义
//方法一
Ptr< SurfDescriptorExtractor> extractor = SurfDescriptorExtractor::create();
//方法二
//Ptr< SURF> extractor = SURF::create();
extractor->compute(srcImage1, keypoint1, descriptors1);
使用BruteForce进行匹配
书上的代码是
BruteForceMatcher< L2< float > > matcher;
matcher.match(descriptors1, descriptors2, matches);
这里与上面有些不同,它照样有两种改动方法,一种与方法一相同,另一种则是直接用头文件提供的BFMatcher定义类,这种与书上类似,不是指针类
//方法一
Ptr< DescriptorMatcher > matcher = DescriptorMatcher::create(“BruteForce”);
matcher->match(descriptors1, descriptors2, matches);
//方法二
//BFMatcher matcher(NORM_L2);
//matcher.match(descriptors1, descriptors2, matches);
完整代码
其它部分就基本一样了,依旧给出完整代码供大家使用,我就是这么大方,比较我很高贵,但是免费嘻嘻!
#include<opencv2/opencv.hpp>
#include<opencv2/xfeatures2d.hpp>
#include<iostream>
using namespace cv;
using namespace xfeatures2d;
using namespace std;
int main()
{
Mat srcImage1 = imread("linlin.jpg");
Mat srcImage2 = imread("linlin2.jpg");
//使用SURF算子检测关键点
int minHessian = 700; //SURF算法中的Hessian阈值
Ptr<SurfFeatureDetector>detector = SurfFeatureDetector::create(minHessian);// 定义一个特征检测类对象
vector<KeyPoint> keypoint1, keypoint2;//vector模板类,存放任意类型的动态数组
//调用detect函数检测出SURF特征关键点,保存在vector容器中
detector->detect(srcImage1, keypoint1);
detector->detect(srcImage2, keypoint2);
//计算描述符(特征向量)
//方法一
Ptr<SurfDescriptorExtractor> extractor = SurfDescriptorExtractor::create();
//方法二
//Ptr<SURF> extractor = SURF::create();
Mat descriptors1, descriptors2;
extractor->compute(srcImage1, keypoint1, descriptors1);
extractor->compute(srcImage2, keypoint2, descriptors2);
//使用BruteForce进行匹配
//实例化一个匹配器
//方法一
Ptr<DescriptorMatcher> matcher = DescriptorMatcher::create("BruteForce");
//方法二
//BFMatcher matcher(NORM_L2);
vector<DMatch> matches;
//匹配两幅图中的描述子
matcher->match(descriptors1, descriptors2, matches);
//绘制从两个图像中匹配出的关键点
Mat imgMatches;
drawMatches(srcImage1, keypoint1, srcImage2, keypoint2, matches, imgMatches); //进行绘制
imshow("匹配图", imgMatches);
waitKey(0);
return 0;
}
实验效果
依旧选用宇宙天后的婊情,但是天后婊情太过丰富,所以匹配效果嘛,我和某蔡姓女士婊示清者自清靴靴!(注意两张图片最好调成尺寸大小相同呦)