Opencv Surf算子特征提取与最优匹配
Opencv中Surf算子提取特征,生成特征描述子,匹配特征的流程跟Sift是完全一致的,这里主要介绍一下整个过程中需要使用到的主要的几个Opencv方法。
1. 特征提取
特征提取使用SurfFeatureDetector类中的detect方法,先定义一个SurfFeatureDetector类的对象,通过对象调用detect方法就可以提取输入图像的Surf特征。可以使用不带参数的默认构造函数构建SurfFeatureDetector对象,也可以使用含参数的构造函数:
CV_WRAP SURF(double hessianThreshold,
int nOctaves=4, int nOctaveLayers=2,
bool extended=true, bool upright=false);
从参数分布上可以看出,我们可以自定义Hessian阈值和尺度空间的组和层的个数。
特别要关注一下第一个参数hessianThreshold是图像Hessian矩阵判别式的阈值,值越大检测出的特征点就越少,也就意味着特征点越稳定。
2. 特征点绘制
特征点绘制是为了把检测出来的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,和方向,是最能显示特征信息的一种绘制方式。
3. 特征点描述
特征点描述使用SurfDescriptorExtractor类中的compute方法。
4. 特征点匹配
特征点匹配可以使用BruteForceMatcher类或FlannBasedMatcher类的match方法。
5. 最优匹配点筛选
通过以上步骤获取的匹配特征点可能有很多,会有很多误匹配,实际使用中,往往需要有限个数的最优匹配点即可,用于定位、融合、拼接或3D重构等。
最优匹配点的筛选可以通过按一定比例提取出排名靠前的匹配点来实现。
6. 绘制匹配点
绘制匹配点使用drawMatches方法实现。
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 );
参数很多,重点说一下最后一个参数flags,它跟drawKeypoints方法中flags的含义是一样的。
当仅使用筛选出的最优匹配点进行匹配的时候,意味着会有很多非最优的特征点不会被匹配,这时候可以设置flags=DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS ,意味着那些不是最优特征点的点不会被绘制出来,图上不会再有那么多花花绿绿的小圆圈了,这个简单的设置可以拯救很多重度密集恐怖症患者的生命。
以下是整个流程的Opencv实现:
#include "highgui/highgui.hpp"
#include "opencv2/nonfree/nonfree.hpp"
#include "opencv2/legacy/legacy.hpp"
#include <iostream>
using namespace cv;
using namespace std;
int main(int argc,char *argv[])
{
Mat image01=imread(argv[1]);
Mat image02=imread(argv[2]);
Mat image1,image2;
image1=image01.clone();
image2=image02.clone();
//提取特征点
SurfFeatureDetector surfDetector(4000); //hessianThreshold,海塞矩阵阈值,并不是限定特征点的个数
vector<KeyPoint> keyPoint1,keyPoint2;
surfDetector.detect(image1,keyPoint1);
surfDetector.detect(image2,keyPoint2);
//绘制特征点
drawKeypoints(image1,keyPoint1,image1,Scalar::all(-1),DrawMatchesFlags::DEFAULT);
drawKeypoints(image2,keyPoint2,image2,Scalar::all(-1),DrawMatchesFlags::DRAW_RICH_KEYPOINTS);
imshow("KeyPoints of image1",image1);
imshow("KeyPoints of image2",image2);
//特征点描述,为下边的特征点匹配做准备
SurfDescriptorExtractor SurfDescriptor;
Mat imageDesc1,imageDesc2;
SurfDescriptor.compute(image1,keyPoint1,imageDesc1);
SurfDescriptor.compute(image2,keyPoint2,imageDesc2);
//特征点匹配并显示匹配结果
//BruteForceMatcher<L2<float>> matcher;
FlannBasedMatcher matcher;
vector<DMatch> matchePoints;
matcher.match(imageDesc1,imageDesc2,matchePoints,Mat());
//提取强特征点
double minMatch=1;
double maxMatch=0;
for(int i=0;i<matchePoints.size();i++)
{
//匹配值最大最小值获取
minMatch=minMatch>matchePoints[i].distance?matchePoints[i].distance:minMatch;
maxMatch=maxMatch<matchePoints[i].distance?matchePoints[i].distance:maxMatch;
}
//最大最小值输出
cout<<"最佳匹配值是: "<<minMatch<<endl;
cout<<"最差匹配值是: "<<maxMatch<<endl;
//获取排在前边的几个最优匹配结果
vector<DMatch> goodMatchePoints;
for(int i=0;i<matchePoints.size();i++)
{
if(matchePoints[i].distance<minMatch+(maxMatch-minMatch)/2)
{
goodMatchePoints.push_back(matchePoints[i]);
}
}
//绘制最优匹配点
Mat imageOutput;
drawMatches(image01,keyPoint1,image02,keyPoint2,goodMatchePoints,imageOutput,Scalar::all(-1),
Scalar::all(-1),vector<char>(),DrawMatchesFlags::NOT_DRAW_SINGLE_POINTS);
imshow("Mathch Points",imageOutput);
waitKey();
return 0;
}
输入图像的特征点在原图对应位置上做了标注,这里使用了默认的绘制方式,特征点只标注了位置,没有方向和尺度信息:
目标图像特征点的绘制使用了DrawMatchesFlags::DRAW_RICH_KEYPOINTS绘制方式,特征点包含了位置、尺度、方向信息:
特征点的匹配是经过筛选的最优匹配点,匹配对数较少,并且不显示匹配失败的特征点:
不筛选最优匹配点的话,会有比较多的特征点配对成功,当然误匹配会更多:
Opencv Surf算子特征提取与最优匹配的更多相关文章
- Opencv Surf算子中keyPoints,描述子Mat矩阵,配对向量DMatch里都包含了哪些好玩的东东?
Surf算法是一把牛刀,我们可以很轻易的从网上或各种Opencv教程里找到Surf的用例,把例程中的代码或贴或敲过来,满心期待的按下F5,当屏幕终于被满屏花花绿绿的小圆点或者N多道连接线条霸占时,内心 ...
- Opencv Sift算子特征提取与匹配
SIFT算法的过程实质是在不同尺度空间上查找特征点(关键点),用128维方向向量的方式对特征点进行描述,最后通过对比描述向量实现目标匹配. 概括起来主要有三大步骤: 1.提取关键点: 2.对关键点附加 ...
- OpenCV——SURF特征检测、匹配与对象查找
SURF原理详解:https://wenku.baidu.com/view/2f1e4d8ef705cc1754270945.html SURF算法工作原理 选择图像中的POI(Points of i ...
- [OpenCV-Python] OpenCV 中图像特征提取与描述 部分 V (二)
部分 V图像特征提取与描述 OpenCV-Python 中文教程(搬运)目录 34 角点检测的 FAST 算法 目标 • 理解 FAST 算法的基础 • 使用 OpenCV 中的 FAST 算法相关函 ...
- 3. opencv进行SIFT特征提取
opencv中sift特征提取的步骤 使用SiftFeatureDetector的detect方法检测特征存入一个向量里,并使用drawKeypoints在图中标识出来 SiftDescriptorE ...
- SURF算子(1)
SURF算子,参考这篇文章的解释http://www.ipol.im/pub/art/2015/69/ SURF 是 Speeded Up Robust Features 加速鲁棒特征的含义. T ...
- poj 2195 二分图最优匹配 或 最小费用最大流
就是最基本的二分图最优匹配,将每个人向每个房子建一条边,权值就是他们manhattan距离.然后对所有权值取反,求一次最大二分图最优匹配,在将结果取反就行了. #include<iostream ...
- 51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)
装盒子 基准时间限制:1 秒 空间限制:131072 KB 分值: 160 有n个长方形盒子,第i个长度为Li,宽度为Wi,我们需要把他们套放.注意一个盒子只可以套入长和宽分别不小于它的盒子,并且 ...
- hdu2255 奔小康赚大钱 km算法解决最优匹配(最大权完美匹配)
/** 题目:hdu2255 奔小康赚大钱 km算法 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:lv 思路:最优匹配(最大权完美匹配) ...
随机推荐
- 洛谷 P1032 字符变换
洛谷 P1032 字符变换 题目描述 已知有两个字串 A,B 及一组字串变换的规则(至多 6 个规则): A1 -> B1 A2 -> B2 规则的含义为:在 A 中的子串 A1 ...
- Redis .Net客户端源码
1.简单介绍 当前NoSql使用已经极为普遍,无论是Java生态圈,还是.net生态圈.大大小小的Web站点在追求高性能高可靠性方面,不由自主都选择了NoSQL技术作为优先考虑的方面.主流的技术有:H ...
- Method of address space layout randomization for windows operating systems
A system and method for address space layout randomization ("ASLR") for a Windows operatin ...
- 初学者路径规划 | 人生苦短我用Python
纵观编程趋势 人生苦短,我用Python,比起C语言.C#.C++和JAVA这些编程语言相对容易很多.Python非常适合用来入门.有人预言,Python会成为继C++和Java之后的第三个主流编程语 ...
- [D3] Build an Area Chart with D3 v4
Similar to line charts, area charts are great for displaying temporal data. Whether you’re displayin ...
- 使用 Python 第三方库 daft 绘制 PGM 中的贝叶斯网络
daft 的官方文档请见 DAFT:BEAUTIFULLY RENDERED PROBABILISTIC GRAPHICAL MODELS. from matplotlib import rc rc( ...
- 硬件——nrf51822第二篇,如何设置keil用来下载程序
转自电子发烧友论坛 未完,待续...... 这里就是根据自己的项目了,并不一定是按照下面的图片去做.
- HttpClient请求发送的几种用法二:
public class HttpClientHelper { private static readonly HttpClientHelper _instance = new H ...
- CQRS之旅——旅程6(我们系统的版本管理)
旅程6:我们系统的版本管理 准备下一站:升级和迁移 "变化是生活的调味品."威廉·考珀 此阶段的最高目标是了解如何升级包含实现CQRS模式和事件源的限界上下文的系统.团队在这一阶段 ...
- 7.2 基础知识ArrayMap
1.android源码中维护有键值对,通过键可以找到值 Java中Object是所有类的父类,对于键值对的保存如果使用个ObjectArray数组,比如N个位置存放键,N+1的位置就存放值,那么如果键 ...