SURF原理详解:https://wenku.baidu.com/view/2f1e4d8ef705cc1754270945.html

SURF算法工作原理

  1. 选择图像中的POI(Points of interest) Hessian Matrix

  2. 在不同的尺度空间发现关键点,非最大信号压制

  3. 发现特征点方法、旋转不变性要求

  4. 生成特征向量

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(-),
            int flags=DrawMatchesFlags::DEFAULT
);

第一个参数image:原始图像,可以使三通道或单通道图像;

第二个参数keypoints:特征点向量,向量内每一个元素是一个KeyPoint对象,包含了特征点的各种属性信息;

第三个参数outImage:特征点绘制的画布图像,可以是原图像;

第四个参数color:绘制的特征点的颜色信息,默认绘制的是随机彩色;

第五个参数flags:特征点的绘制模式,其实就是设置特征点的那些信息需要绘制,那些不需要绘制,有以下几种模式可选:

  DEFAULT:只绘制特征点的坐标点,显示在图像上就是一个个小圆点,每个小圆点的圆心坐标都是特征点的坐标。
  DRAW_OVER_OUTIMG:函数不创建输出的图像,而是直接在输出图像变量空间绘制,要求本身输出图像变量就是一个初始化好了的,size与type都是已经初始化好的变量
  NOT_DRAW_SINGLE_POINTS:单点的特征点不被绘制
  DRAW_RICH_KEYPOINTS:绘制特征点的时候绘制的是一个个带有方向的圆,这种方法同时显示图像的坐标,size,和方向,是最能显示特征信息的一种绘制方式。

 #include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream> using namespace cv;
using namespace cv::xfeatures2d;
using namespace std; int main(int argc, char** argv) {
Mat src = imread("test.jpg", IMREAD_GRAYSCALE);
if (src.empty()) {
printf("could not load image...\n");
return -;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src); // SURF特征点检测
int minHessian = ;
Ptr<SURF> detector = SURF::create(minHessian);//创建一个surf类对象并初始化
vector<KeyPoint> keypoints;
detector->detect(src, keypoints, Mat());//找出关键点 // 绘制关键点
Mat keypoint_img;
drawKeypoints(src, keypoints, keypoint_img, Scalar::all(-), DrawMatchesFlags::DEFAULT);
imshow("KeyPoints Image", keypoint_img); waitKey();
return ;
}

绘制匹配点

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(-), const Scalar& singlePointColor=Scalar::all(-),
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

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

 #include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream> using namespace cv;
using namespace cv::xfeatures2d;
using namespace std; int main(int argc, char** argv) {
Mat src = imread("数字.jpg");
Mat temp = imread("2.png");
if (src.empty() || temp.empty()) {
printf("could not load image...\n");
return -;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src); // SURF特征点检测
int minHessian = ;
Ptr<SURF> detector = SURF::create(minHessian, , , true, true);//创建一个surf类检测器对象并初始化
vector<KeyPoint> keypoints1, keypoints2;
Mat src_vector, temp_vector;//用来存放特征点的描述向量 //detector->detect(src, keypoints1, Mat());//找出关键点
//detector->detect(temp, keypoints2, Mat());//找出关键点 //找到特征点并计算特征描述子(向量)
detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//输入图像,输入掩码,输入特征点,输出Mat,存放所有特征点的描述向量
detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//这个Mat行数为特征点的个数,列数为每个特征向量的尺寸,SURF是64(维) //匹配
BFMatcher matcher(NORM_L2); //实例化一个暴力匹配器(括号里可以选择匹配方法) vector<DMatch> matches; //DMatch是用来描述匹配好的一对特征点的类,包含这两个点之间的匹配信息
//比如左图有个特征m,它和右图的特征点n最匹配,这个DMatch就记录它俩最匹配,并且还记录m和n的
//特征向量的距离和其他信息,这个距离在后面用来做筛选 matcher.match(src_vector, temp_vector, matches); //匹配,数据来源是特征向量,结果存放在DMatch类型里面 //匹配点筛选
//sort函数对数据进行升序排列
//筛选匹配点,根据match里面特征对的距离从小到大排序
//筛选出最优的30个匹配点(可以不使用,会画出所有特征点) sort(matches.begin(), matches.end());
vector< DMatch > good_matches;
int ptsPairs = std::min(, (int)(matches.size() * 0.15));//匹配点数量不大于50
cout << ptsPairs << endl;
for (int i = ; i < ptsPairs; i++)
{
good_matches.push_back(matches[i]);//距离最小的50个压入新的DMatch
} Mat MatchesImage; //drawMatches这个函数直接画出摆在一起的图
drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-), Scalar::all(-), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); //绘制匹配点
imshow("BFMatcher Image", MatchesImage); waitKey();
return ;
}

FLANN匹配

 #include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <math.h> using namespace cv;
using namespace cv::xfeatures2d;
using namespace std; int main(int argc, char** argv) {
Mat src = imread("数字.jpg",);
Mat temp = imread("2.png",);
if (src.empty() || temp.empty()) {
printf("could not load image...\n");
return -;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src); // SURF特征点检测
int minHessian = ;
Ptr<SURF> detector = SURF::create(minHessian, , , true, true);//创建一个surf类检测器对象并初始化
vector<KeyPoint> keypoints1, keypoints2;
Mat src_vector, temp_vector;//用来存放特征点的描述向量 //detector->detect(src, keypoints1, Mat());//找出关键点
//detector->detect(temp, keypoints2, Mat());//找出关键点 //找到特征点并计算特征描述子(向量)
detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//输入图像,输入掩码,输入特征点,输出Mat,存放所有特征点的描述向量
detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//这个Mat行数为特征点的个数,列数为每个特征向量的尺寸,SURF是64(维) //匹配
FlannBasedMatcher matcher; //实例化一个FLANN匹配器(括号里可以选择匹配方法) vector<DMatch> matches; //DMatch是用来描述匹配好的一对特征点的类,包含这两个点之间的匹配信息
//比如左图有个特征m,它和右图的特征点n最匹配,这个DMatch就记录它俩最匹配,并且还记录m和n的
//特征向量的距离和其他信息,这个距离在后面用来做筛选 matcher.match(src_vector, temp_vector, matches); //匹配,数据来源是特征向量,结果存放在DMatch类型里面 //求最小最大距离
double minDistance = ;//反向逼近
double maxDistance = ;
for (int i=; i< src_vector.rows; i++) {
double distance = matches[i].distance;
if (distance > maxDistance) {
maxDistance = distance;
}
if (distance < minDistance) {
minDistance = distance;
}
}
printf("max distance : %f\n", maxDistance);
printf("min distance : %f\n", minDistance); //筛选较好的匹配点
vector< DMatch > good_matches;
for (int i = ; i < src_vector.rows; i++) {
double distance = matches[i].distance;
if (distance < max(minDistance * , 0.02)) {
good_matches.push_back(matches[i]);//距离小于范围的压入新的DMatch
}
} /*//sort函数对数据进行升序排列
//筛选匹配点,根据match里面特征对的距离从小到大排序
//筛选出最优的50个匹配点(可以不使用,会画出所有特征点) sort(matches.begin(), matches.end());
vector< DMatch > good_matches;
int ptsPairs = std::min(50, (int)(matches.size() * 0.15));//匹配点数量不大于50
cout << ptsPairs << endl;
for (int i = 0; i < ptsPairs; i++)
{
good_matches.push_back(matches[i]);//距离最小的50个压入新的DMatch
}
*/ Mat MatchesImage; //drawMatches这个函数直接画出摆在一起的图
drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-), Scalar::all(-), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); //绘制匹配点
imshow("FLANN Image", MatchesImage); waitKey();
return ;
}

对象查找

 #include <opencv2/opencv.hpp>
#include <opencv2/xfeatures2d.hpp>
#include <iostream>
#include <math.h> using namespace cv;
using namespace cv::xfeatures2d;
using namespace std; int main(int argc, char** argv) {
Mat src = imread("fire_5.jpg");
Mat temp = imread("数字.jpg");
if (src.empty() || temp.empty()) {
printf("could not load image...\n");
return -;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input image", src); // SURF特征点检测
int minHessian = ;
Ptr<SURF> detector = SURF::create(minHessian, , , true, true);//创建一个surf类检测器对象并初始化
vector<KeyPoint> keypoints1, keypoints2;
Mat src_vector, temp_vector;//用来存放特征点的描述向量 //detector->detect(src, keypoints1, Mat());//找出关键点
//detector->detect(temp, keypoints2, Mat());//找出关键点 //找到特征点并计算特征描述子(向量)
detector->detectAndCompute(src, Mat(), keypoints1, src_vector);//输入图像,输入掩码,输入特征点,输出Mat,存放所有特征点的描述向量
detector->detectAndCompute(temp, Mat(), keypoints2, temp_vector);//这个Mat行数为特征点的个数,列数为每个特征向量的尺寸,SURF是64(维) //匹配
FlannBasedMatcher matcher; //实例化一个FLANN匹配器(括号里可以选择匹配方法) vector<DMatch> matches; //DMatch是用来描述匹配好的一对特征点的类,包含这两个点之间的匹配信息
//比如左图有个特征m,它和右图的特征点n最匹配,这个DMatch就记录它俩最匹配,并且还记录m和n的
//特征向量的距离和其他信息,这个距离在后面用来做筛选 matcher.match(src_vector, temp_vector, matches); //匹配,数据来源是特征向量,结果存放在DMatch类型里面 //求最小最大距离
double minDistance = ;//反向逼近
double maxDistance = ;
for (int i = ; i < src_vector.rows; i++) {
double distance = matches[i].distance;
if (distance > maxDistance) {
maxDistance = distance;
}
if (distance < minDistance) {
minDistance = distance;
}
}
printf("max distance : %f\n", maxDistance);
printf("min distance : %f\n", minDistance); //筛选较好的匹配点
vector< DMatch > good_matches;
for (int i = ; i < src_vector.rows; i++) {
double distance = matches[i].distance;
if (distance < max(minDistance * , 0.02)) {
good_matches.push_back(matches[i]);//距离小于范围的压入新的DMatch
}
} Mat MatchesImage; //drawMatches这个函数直接画出摆在一起的图
drawMatches(src, keypoints1, temp, keypoints2, good_matches, MatchesImage, Scalar::all(-), Scalar::all(-), vector<char>(), DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS); //绘制匹配点 vector<Point2f> obj;
vector<Point2f> objInScene;
for (size_t t = ; t < good_matches.size(); t++) {
obj.push_back(keypoints1[good_matches[t].queryIdx].pt);//返回对象在模板图特征点坐标
objInScene.push_back(keypoints2[good_matches[t].trainIdx].pt);//返回对象在背景查找图的坐标
} Mat H = findHomography(obj,objInScene,RANSAC);//计算透视变换矩阵 vector<Point2f> obj_corner();
vector<Point2f> scene_corner();
obj_corner[] = Point(, );
obj_corner[] = Point(src.cols, );
obj_corner[] = Point(src.cols,src.rows);
obj_corner[] = Point(, src.rows); perspectiveTransform(obj_corner, scene_corner,H);//透视变换 //画出边框线
line(MatchesImage, scene_corner[] + Point2f(src.cols, ), scene_corner[] + Point2f(src.cols, ), Scalar(, , ), , , );
line(MatchesImage, scene_corner[] + Point2f(src.cols, ), scene_corner[] + Point2f(src.cols, ), Scalar(, , ), , , );
line(MatchesImage, scene_corner[] + Point2f(src.cols, ), scene_corner[] + Point2f(src.cols, ), Scalar(, , ), , , );
line(MatchesImage, scene_corner[] + Point2f(src.cols, ), scene_corner[] + Point2f(src.cols, ), Scalar(, , ), , , );
imshow("FLANN Image", MatchesImage); line(temp, scene_corner[], scene_corner[], Scalar(, , ), , , );
line(temp, scene_corner[], scene_corner[], Scalar(, , ), , , );
line(temp, scene_corner[], scene_corner[], Scalar(, , ), , , );
line(temp, scene_corner[], scene_corner[], Scalar(, , ), , , );
imshow("temp Image", temp); waitKey();
return ;
}

OpenCV——SURF特征检测、匹配与对象查找的更多相关文章

  1. OpenCV——KAZE、AKAZE特征检测、匹配与对象查找

      AKAZE是KAZE的加速版 特征点查找和绘制:把surf中的surf改成KAZE或AKAZE即可 #include <opencv2/opencv.hpp> #include < ...

  2. [opencv]KAZE、AKAZE特征检测、匹配与对象查找

    AkAZE是KAZE的加速版 与SIFT,SUFR比较: 1.更加稳定 2.非线性尺度空间 3.AKAZE速度更加快 4.比较新的算法,只有Opencv新的版本才可以用 AKAZE局部匹配介绍 1.A ...

  3. OpenCV——Brisk特征检测、匹配与对象查找

    检测并绘制特征点: #include <opencv2/opencv.hpp> #include <opencv2/xfeatures2d.hpp> #include < ...

  4. 第二节,surf特征检测关键点,实现图片拼接

    初级的图像拼接为将两幅图像简单的粘贴在一起,仅仅是图像几何空间的转移和合成,与图像内容无关:高级图像拼接也叫做基于特征匹配的图像拼接,拼接时消去两幅图像相同的部分,实现拼接全景图. 实现步骤: 1.采 ...

  5. opencv::SURF特征

    SURF特征基本介绍 SURF(Speeded Up Robust Features)特征关键特性: -特征检测 -尺度空间 -选择不变性 -特征向量 工作原理 . 选择图像中POI(Points o ...

  6. (转)javascript中的对象查找

    本文转自:http://otakustay.com/object-lookup-in-javascript/  ---很棒的一篇文章,作者的其他文章还暂时没读,但相信作者是一个谦虚 谨慎的好工程师 近 ...

  7. OpenCV-Python sift/surf特征匹配与显示

    import cv2 import numpy as np def drawMatchesKnn_cv2(img1_gray,kp1,img2_gray,kp2,goodMatch): h1, w1 ...

  8. js进阶正则表达式10-分组-多行匹配-正则对象的属性(小括号作用:分组,将小括号里面的东西看成一个整体,因为量词只对前一个字符有效)(多行匹配:m)(属性使用:reg.global)

    js进阶正则表达式10-分组-多行匹配-正则对象的属性(小括号作用:分组,将小括号里面的东西看成一个整体,因为量词只对前一个字符有效)(多行匹配:m)(属性使用:reg.global) 一.总结 1. ...

  9. 基于OpenCV的双目视觉匹配测距系统

    刚读研究生的时候,自己导师研究的方向是双目视觉,于是让自己研究OpenCV,折腾了几个月,算法上没啥突破,不过工程上还是折腾出了一个能用的小玩意,基于OpenCV实现了相机的标定.双目视觉图片的矫正. ...

随机推荐

  1. Linux常用基本命令(file,chown)

    1,file命令作用,查看文件的类型 ghostwu@dev:~$ .htm ./linux/rename ghostwu@dev:~$ .htm ./linux/rename/.htm: empty ...

  2. 盲刷bios

    本帖最后由 evayh 于 2011-12-17 13:09 编辑 先看看是否是insyde的bios,如果是的话,可以救回来 insyde BIOS在损坏时,会自动进入CRISIS MODE试图刷回 ...

  3. 优雅高效的免费在线APP原型工具

    前往:xiaopiu 打开浏览器即可享受软件级的流畅体验!云端组件库.交互动效自定义.高效友好的操作方式让您的创意即刻呈现!

  4. 高性能JavaScript(字符串和正则表达式)

    字符串连接 +/+=操作符连接 str += "one" + "two"; 这是常用的连接字符串的方法,它运行的时候会经历下面四个步骤: 1.在内存中创建一个临 ...

  5. 移动设备 小米2S不显示CD驱动器(H),便携设备,MTP,驱动USB Driver,MI2感叹号的解决方法

    小米2S不显示CD驱动器(H),便携设备,MTP,驱动USB Driver,MI2感叹号的解决方法 by:授客 QQ:1033553122 用户环境 操作系统:Win7 手机设备:小米2S   问题描 ...

  6. 数据库批量操作中SqlParameter参数传递的问题

    数据库批量操作 比如会写:update T_AdminUsers set IsEnabled=@IsEnabled where Id in (@ids) 然后再SqlParameter("@ ...

  7. Vue -- vue-cli(vue脚手架) npm run build打包优化

    这段时间公司新项目立项,开发组选用 Vue2.0 进行开发.当然也就一并用到 vue cli 进行自动化构建.结果在基础版本开发完成后,用 npm run build 命令打包上线时,发现以下几个问题 ...

  8. Android--PullToRefreshListView的onRefreshComplete()不起作用的问题

    今天用到了网上开源的下拉刷新组件PullToRefreshListView的第三方下拉刷新的ListView 我们发现 有时候我们当使用它的onRefreshComplete()方法是,我们下拉出来的 ...

  9. LeetCode题解之 3Sum

    1.题目描述 2.问题分析 使用hashtable 的方法做,解法不是最优的,思路简单直观. 3.代码 vector<vector<int>> threeSum(vector& ...

  10. CAC的Debian-8-64bit安装BBR正确打开方式

    装过三台debian 64 bit, CAC, 2欧, KVM虚拟机 做法都一样---下面说下正确安装方式   0. 有装锐速记得先删除,免得换核心后,锐速在扯后腿.   1.换4.9版kernel ...