OpenCV——SURF特征检测与匹配
Posted long5683
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了OpenCV——SURF特征检测与匹配相关的知识,希望对你有一定的参考价值。
SURF原理详解:https://wenku.baidu.com/view/2f1e4d8ef705cc1754270945.html
SURF算法工作原理
-
选择图像中的POI(Points of interest) Hessian Matrix
-
在不同的尺度空间发现关键点,非最大信号压制
-
发现特征点方法、旋转不变性要求
-
生成特征向量
SURF构造函数介绍
C++: SURF::SURF(
double hessianThreshold, --阈值检测器使用Hessian的关键点,默认值在
300-500之间
int nOctaves=4, -- 4表示在四个尺度空间
int nOctaveLayers=2, -- 表示每个尺度的层数
bool extended=false,
bool upright=false --表示计算旋转不变性,不计算的速度更快
)
特征点绘制
特征点绘制是为了把检测出来的Surf特征点在原图上绘制出来,这一步是为了把特征点直观的显示出来给我们看,跟整个Surf算子的特征提取和匹配流程没关系。
绘制使用drawKeypoints方法:
void drawKeypoints( const Mat& image,
const vector<KeyPoint>& keypoints,
CV_OUT Mat& outImage,
const Scalar& color=Scalar::all(-1),
int flags=DrawMatchesFlags::DEFAULT
);
第一个参数image:原始图像,可以使三通道或单通道图像;
第二个参数keypoints:特征点向量,向量内每一个元素是一个KeyPoint对象,包含了特征点的各种属性信息;
第三个参数outImage:特征点绘制的画布图像,可以是原图像;
第四个参数color:绘制的特征点的颜色信息,默认绘制的是随机彩色;
第五个参数flags:特征点的绘制模式,其实就是设置特征点的那些信息需要绘制,那些不需要绘制,有以下几种模式可选:
DEFAULT:只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标。
DRAW_OVER_OUTIMG:函数不创建输出的图像,而是直接在输出图像变量空间绘制,要求本身输出图像变量就是一个初始化好了的,size与type都是已经初始化好的变量
NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制
DRAW_RICH_KEYPOINTS:绘制特征点的时候绘制的是一个个带有方向的圆,这种方法同时显示图像的坐标,size,和方向,是最能显示特征信息的一种绘制方式。
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/xfeatures2d.hpp> 3 #include <iostream> 4 5 using namespace cv; 6 using namespace cv::xfeatures2d; 7 using namespace std; 8 9 int main(int argc, char** argv) { 10 Mat src = imread("test.jpg", IMREAD_GRAYSCALE); 11 if (src.empty()) { 12 printf("could not load image... "); 13 return -1; 14 } 15 namedWindow("input image", CV_WINDOW_AUTOSIZE); 16 imshow("input image", src); 17 18 // SURF特征点检测 19 int minHessian = 100; 20 Ptr<SURF> detector = SURF::create(minHessian);//创建一个surf类对象并初始化 21 vector<KeyPoint> keypoints; 22 detector->detect(src, keypoints, Mat());//找出关键点 23 24 // 绘制关键点 25 Mat keypoint_img; 26 drawKeypoints(src, keypoints, keypoint_img, Scalar::all(-1), DrawMatchesFlags::DEFAULT); 27 imshow("KeyPoints Image", keypoint_img); 28 29 waitKey(0); 30 return 0; 31 }
绘制匹配点
drawMatches( const Mat& img1, const vector<KeyPoint>& keypoints1, const Mat& img2, const vector<KeyPoint>& keypoints2, const vector<DMatch>& matches1to2, Mat& outImg, const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1), const vector<char>& matchesMask=vector<char>(), int flags=DrawMatchesFlags::DEFAULT );
其中参数如下:
* img1 – 源图像1
* keypoints1 –源图像1的特征点.
* img2 – 源图像2.
* keypoints2 – 源图像2的特征点
* matches1to2 – 源图像1的特征点匹配源图像2的特征点[matches[i]] .
* outImg – 输出图像具体由flags决定.
* matchColor – 匹配的颜色(特征点和连线),若matchColor==Scalar::all(-1),颜色随机.
* singlePointColor – 单个点的颜色,即未配对的特征点,若matchColor==Scalar::all(-1),颜色随机.
*matchesMask – Mask决定哪些点将被画出,若为空,则画出所有匹配点.
*flags—它跟drawKeypoints方法中flags的含义是一样的。
当仅使用筛选出的最优匹配点进行匹配的时候,意味着会有很多非最优的特征点不会被匹配,这时候可以设置flags=DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS
1 #include <opencv2/opencv.hpp> 2 #include <opencv2/xfeatures2d.hpp> 3 #include <iostream> 4 5 using namespace cv; 6 using namespace cv::xfeatures2d; 7 using namespace std; 8 9 int main(int argc, char** argv) { 10 Mat src = imread("数字.jpg", IMREAD_GRAYSCALE); 11 Mat temp = imread("2.png", IMREAD_GRAYSCALE); 12 if (src.empty()|| temp.empty()) { 13 printf("could not load image... "); 14 return -1; 15 } 16 namedWindow("input image", CV_WINDOW_AUTOSIZE); 17 imshow("input image", src); 18 19 // SURF特征点检测 20 int minHessian = 400; 21 Ptr<SURF> detector = SURF::create(minHessian,4,3,true,true);//创建一个surf类检测器对象并初始化 22 vector<KeyPoint> keypoints1, keypoints2; 23 detector->detect(src, keypoints1, Mat());//找出关键点 24 detector->detect(temp, keypoints2, Mat());//找出关键点 25 26 BFMatcher matcher; //实例化一个暴力匹配器 27 Mat src_vector, temp_vector;//用来存放特征点的描述向量 28 vector<DMatch> matches; //DMatch是用来描述匹配好的一对特征点的类,包含这两个点之间的相关信息 29 //比如左图有个特征m,它和右图的特征点n最匹配,这个DMatch就记录它俩最匹配,并且还记录m和n的 30 //特征向量的距离和其他信息,这个距离在后面用来做筛选 31 32 detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//输入图像,输入掩码,输入特征点,输出Mat,存放所有特征点的描述向量 33 detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//这个Mat行数为特征点的个数,列数为每个特征向量的尺寸,SURF是64(维) 34 35 matcher.match(src_vector, temp_vector, matches); //匹配,数据来源是特征向量,结果存放在DMatch类型里面 36 37 //sort函数对数据进行升序排列 38 sort(matches.begin(), matches.end()); //筛选匹配点,根据match里面特征对的距离从小到大排序 39 vector< DMatch > good_matches; 40 int ptsPairs = std::min(50, (int)(matches.size() * 0.15)); 41 cout << ptsPairs << endl; 42 for (int i = 0; i < ptsPairs; i++) 43 { 44 good_matches.push_back(matches[i]);//距离最小的50个压入新的DMatch 45 } 46 Mat outimg; //drawMatches这个函数直接画出摆在一起的图 47 drawMatches(src, keypoints1, temp, keypoints2, good_matches, outimg, Scalar::all(-1), Scalar::all(-1), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); //绘制匹配点 48 imshow("KeyPoints Image", outimg); 49 50 waitKey(0); 51 return 0; 52 }
以上是关于OpenCV——SURF特征检测与匹配的主要内容,如果未能解决你的问题,请参考以下文章
OpenCV - 使用 SURF 描述符和 BruteForceMatcher 进行对象匹配
OpenCV+Python特征提取算法与图像描述符之SIFT / SURF / ORB