OpenCV——SURF特征检测、匹配与对象查找

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& 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
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…\n”);
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 detector = SURF::create(minHessian);//创建一个surf类对象并初始化
21 vector 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& keypoints1,
const Mat& img2, const vector& keypoints2,
const vector& matches1to2, Mat& outImg,
const Scalar& matchColor=Scalar::all(-1), const Scalar& singlePointColor=Scalar::all(-1),
const vector& matchesMask=vector(), 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

BF(暴力)匹配(src目标图,temp需要查找的背景图)

复制代码
1 #include <opencv2/opencv.hpp>
2 #include <opencv2/xfeatures2d.hpp>
3 #include
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”);
11 Mat temp = imread(“2.png”);
12 if (src.empty() || temp.empty()) {
13 printf(“could not load image…\n”);
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 detector = SURF::create(minHessian, 4, 3, true, true);//创建一个surf类检测器对象并初始化
22 vector keypoints1, keypoints2;
23 Mat src_vector, temp_vector;//用来存放特征点的描述向量
24
25 //detector->detect(src, keypoints1, Mat());//找出关键点
26 //detector->detect(temp, keypoints2, Mat());//找出关键点
27
28 //找到特征点并计算特征描述子(向量)
29 detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//输入图像,输入掩码,输入特征点,输出Mat,存放所有特征点的描述向量
30 detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//这个Mat行数为特征点的个数,列数为每个特征向量的尺寸,SURF是64(维)
31
32
33 //匹配
34 BFMatcher matcher(NORM_L2); //实例化一个暴力匹配器(括号里可以选择匹配方法)
35
36 vector matches; //DMatch是用来描述匹配好的一对特征点的类,包含这两个点之间的匹配信息
37 //比如左图有个特征m,它和右图的特征点n最匹配,这个DMatch就记录它俩最匹配,并且还记录m和n的
38 //特征向量的距离和其他信息,这个距离在后面用来做筛选
39
40 matcher.match(src_vector, temp_vector, matches); //匹配,数据来源是特征向量,结果存放在DMatch类型里面
41
42 //匹配点筛选
43 //sort函数对数据进行升序排列
44 //筛选匹配点,根据match里面特征对的距离从小到大排序
45 //筛选出最优的30个匹配点(可以不使用,会画出所有特征点)
46
47 sort(matches.begin(), matches.end());
48 vector< DMatch > good_matches;
49 int ptsPairs = std::min(30, (int)(matches.size() * 0.15));//匹配点数量不大于50
50 cout << ptsPairs << endl;
51 for (int i = 0; i < ptsPairs; i++)
52 {
53 good_matches.push_back(matches[i]);//距离最小的50个压入新的DMatch
54 }
55
56
57 Mat MatchesImage; //drawMatches这个函数直接画出摆在一起的图
58 drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); //绘制匹配点
59 imshow(“BFMatcher Image”, MatchesImage);
60
61 waitKey(0);
62 return 0;
63 }
复制代码

FLANN匹配

复制代码
1 #include <opencv2/opencv.hpp>
2 #include <opencv2/xfeatures2d.hpp>
3 #include
4 #include <math.h>
5
6 using namespace cv;
7 using namespace cv::xfeatures2d;
8 using namespace std;
9
10 int main(int argc, char** argv) {
11 Mat src = imread(“数字.jpg”,0);
12 Mat temp = imread(“2.png”,0);
13 if (src.empty() || temp.empty()) {
14 printf(“could not load image…\n”);
15 return -1;
16 }
17 namedWindow(“input image”, CV_WINDOW_AUTOSIZE);
18 imshow(“input image”, src);
19
20 // SURF特征点检测
21 int minHessian = 400;
22 Ptr detector = SURF::create(minHessian, 4, 3, true, true);//创建一个surf类检测器对象并初始化
23 vector keypoints1, keypoints2;
24 Mat src_vector, temp_vector;//用来存放特征点的描述向量
25
26 //detector->detect(src, keypoints1, Mat());//找出关键点
27 //detector->detect(temp, keypoints2, Mat());//找出关键点
28
29 //找到特征点并计算特征描述子(向量)
30 detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//输入图像,输入掩码,输入特征点,输出Mat,存放所有特征点的描述向量
31 detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//这个Mat行数为特征点的个数,列数为每个特征向量的尺寸,SURF是64(维)
32
33
34 //匹配
35 FlannBasedMatcher matcher; //实例化一个FLANN匹配器(括号里可以选择匹配方法)
36
37 vector matches; //DMatch是用来描述匹配好的一对特征点的类,包含这两个点之间的匹配信息
38 //比如左图有个特征m,它和右图的特征点n最匹配,这个DMatch就记录它俩最匹配,并且还记录m和n的
39 //特征向量的距离和其他信息,这个距离在后面用来做筛选
40
41 matcher.match(src_vector, temp_vector, matches); //匹配,数据来源是特征向量,结果存放在DMatch类型里面
42
43 //求最小最大距离
44 double minDistance = 1000;//反向逼近
45 double maxDistance = 0;
46 for (int i=0; i< src_vector.rows; i++) {
47 double distance = matches[i].distance;
48 if (distance > maxDistance) {
49 maxDistance = distance;
50 }
51 if (distance < minDistance) {
52 minDistance = distance;
53 }
54 }
55 printf(“max distance : %f\n”, maxDistance);
56 printf(“min distance : %f\n”, minDistance);
57
58 //筛选较好的匹配点
59 vector< DMatch > good_matches;
60 for (int i = 0; i < src_vector.rows; i++) {
61 double distance = matches[i].distance;
62 if (distance < max(minDistance * 2, 0.02)) {
63 good_matches.push_back(matches[i]);//距离小于范围的压入新的DMatch
64 }
65 }
66
67 /*//sort函数对数据进行升序排列
68 //筛选匹配点,根据match里面特征对的距离从小到大排序
69 //筛选出最优的50个匹配点(可以不使用,会画出所有特征点)
70
71 sort(matches.begin(), matches.end());
72 vector< DMatch > good_matches;
73 int ptsPairs = std::min(50, (int)(matches.size() * 0.15));//匹配点数量不大于50
74 cout << ptsPairs << endl;
75 for (int i = 0; i < ptsPairs; i++)
76 {
77 good_matches.push_back(matches[i]);//距离最小的50个压入新的DMatch
78 }
79 */
80
81 Mat MatchesImage; //drawMatches这个函数直接画出摆在一起的图
82 drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); //绘制匹配点
83 imshow(“FLANN Image”, MatchesImage);
84
85 waitKey(0);
86 return 0;
87 }
复制代码
对象查找

复制代码
1 #include <opencv2/opencv.hpp>
2 #include <opencv2/xfeatures2d.hpp>
3 #include
4 #include <math.h>
5
6 using namespace cv;
7 using namespace cv::xfeatures2d;
8 using namespace std;
9
10 int main(int argc, char** argv) {
11 Mat src = imread(“fire_5.jpg”);
12 Mat temp = imread(“数字.jpg”);
13 if (src.empty() || temp.empty()) {
14 printf(“could not load image…\n”);
15 return -1;
16 }
17 namedWindow(“input image”, CV_WINDOW_AUTOSIZE);
18 imshow(“input image”, src);
19
20 // SURF特征点检测
21 int minHessian = 400;
22 Ptr detector = SURF::create(minHessian, 4, 3, true, true);//创建一个surf类检测器对象并初始化
23 vector keypoints1, keypoints2;
24 Mat src_vector, temp_vector;//用来存放特征点的描述向量
25
26 //detector->detect(src, keypoints1, Mat());//找出关键点
27 //detector->detect(temp, keypoints2, Mat());//找出关键点
28
29 //找到特征点并计算特征描述子(向量)
30 detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//输入图像,输入掩码,输入特征点,输出Mat,存放所有特征点的描述向量
31 detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//这个Mat行数为特征点的个数,列数为每个特征向量的尺寸,SURF是64(维)
32
33
34 //匹配
35 FlannBasedMatcher matcher; //实例化一个FLANN匹配器(括号里可以选择匹配方法)
36
37 vector matches; //DMatch是用来描述匹配好的一对特征点的类,包含这两个点之间的匹配信息
38 //比如左图有个特征m,它和右图的特征点n最匹配,这个DMatch就记录它俩最匹配,并且还记录m和n的
39 //特征向量的距离和其他信息,这个距离在后面用来做筛选
40
41 matcher.match(src_vector, temp_vector, matches); //匹配,数据来源是特征向量,结果存放在DMatch类型里面
42
43 //求最小最大距离
44 double minDistance = 1000;//反向逼近
45 double maxDistance = 0;
46 for (int i = 0; i < src_vector.rows; i++) {
47 double distance = matches[i].distance;
48 if (distance > maxDistance) {
49 maxDistance = distance;
50 }
51 if (distance < minDistance) {
52 minDistance = distance;
53 }
54 }
55 printf(“max distance : %f\n”, maxDistance);
56 printf(“min distance : %f\n”, minDistance);
57
58 //筛选较好的匹配点
59 vector< DMatch > good_matches;
60 for (int i = 0; i < src_vector.rows; i++) {
61 double distance = matches[i].distance;
62 if (distance < max(minDistance * 3, 0.02)) {
63 good_matches.push_back(matches[i]);//距离小于范围的压入新的DMatch
64 }
65 }
66
67
68 Mat MatchesImage; //drawMatches这个函数直接画出摆在一起的图
69 drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-1), Scalar::all(-1), vector(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); //绘制匹配点
70
71
72 vector obj;
73 vector objInScene;
74 for (size_t t = 0; t < good_matches.size(); t++) {
75 obj.push_back(keypoints1[good_matches[t].queryIdx].pt);//返回对象在模板图特征点坐标
76 objInScene.push_back(keypoints2[good_matches[t].trainIdx].pt);//返回对象在背景查找图的坐标
77 }
78
79 Mat H = findHomography(obj,objInScene,RANSAC);//计算透视变换矩阵
80
81 vector obj_corner(4);
82 vector scene_corner(4);
83 obj_corner[0] = Point(0, 0);
84 obj_corner[1] = Point(src.cols, 0);
85 obj_corner[2] = Point(src.cols,src.rows);
86 obj_corner[3] = Point(0, src.rows);
87
88 perspectiveTransform(obj_corner, scene_corner,H);//透视变换
89
90 //画出边框线
91 line(MatchesImage, scene_corner[0] + Point2f(src.cols, 0), scene_corner[1] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
92 line(MatchesImage, scene_corner[1] + Point2f(src.cols, 0), scene_corner[2] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
93 line(MatchesImage, scene_corner[2] + Point2f(src.cols, 0), scene_corner[3] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
94 line(MatchesImage, scene_corner[3] + Point2f(src.cols, 0), scene_corner[0] + Point2f(src.cols, 0), Scalar(0, 0, 255), 2, 8, 0);
95 imshow(“FLANN Image”, MatchesImage);
96
97 line(temp, scene_corner[0], scene_corner[1], Scalar(0, 0, 255), 2, 8, 0);
98 line(temp, scene_corner[1], scene_corner[2], Scalar(0, 0, 255), 2, 8, 0);
99 line(temp, scene_corner[2], scene_corner[3], Scalar(0, 0, 255), 2, 8, 0);
100 line(temp, scene_corner[3], scene_corner[0], Scalar(0, 0, 255), 2, 8, 0);
101 imshow(“temp Image”, temp);
102
103 waitKey(0);
104 return 0;
105 }
复制代码

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值