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算子特征提取与最优匹配的更多相关文章

  1. Opencv Surf算子中keyPoints,描述子Mat矩阵,配对向量DMatch里都包含了哪些好玩的东东?

    Surf算法是一把牛刀,我们可以很轻易的从网上或各种Opencv教程里找到Surf的用例,把例程中的代码或贴或敲过来,满心期待的按下F5,当屏幕终于被满屏花花绿绿的小圆点或者N多道连接线条霸占时,内心 ...

  2. Opencv Sift算子特征提取与匹配

    SIFT算法的过程实质是在不同尺度空间上查找特征点(关键点),用128维方向向量的方式对特征点进行描述,最后通过对比描述向量实现目标匹配. 概括起来主要有三大步骤: 1.提取关键点: 2.对关键点附加 ...

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

    SURF原理详解:https://wenku.baidu.com/view/2f1e4d8ef705cc1754270945.html SURF算法工作原理 选择图像中的POI(Points of i ...

  4. [OpenCV-Python] OpenCV 中图像特征提取与描述 部分 V (二)

    部分 V图像特征提取与描述 OpenCV-Python 中文教程(搬运)目录 34 角点检测的 FAST 算法 目标 • 理解 FAST 算法的基础 • 使用 OpenCV 中的 FAST 算法相关函 ...

  5. 3. opencv进行SIFT特征提取

    opencv中sift特征提取的步骤 使用SiftFeatureDetector的detect方法检测特征存入一个向量里,并使用drawKeypoints在图中标识出来 SiftDescriptorE ...

  6. SURF算子(1)

    SURF算子,参考这篇文章的解释http://www.ipol.im/pub/art/2015/69/ SURF 是   Speeded Up Robust Features 加速鲁棒特征的含义. T ...

  7. poj 2195 二分图最优匹配 或 最小费用最大流

    就是最基本的二分图最优匹配,将每个人向每个房子建一条边,权值就是他们manhattan距离.然后对所有权值取反,求一次最大二分图最优匹配,在将结果取反就行了. #include<iostream ...

  8. 51nod 算法马拉松4 D装盒子(网络流 / 二分图最优匹配)

    装盒子   基准时间限制:1 秒 空间限制:131072 KB 分值: 160 有n个长方形盒子,第i个长度为Li,宽度为Wi,我们需要把他们套放.注意一个盒子只可以套入长和宽分别不小于它的盒子,并且 ...

  9. hdu2255 奔小康赚大钱 km算法解决最优匹配(最大权完美匹配)

    /** 题目:hdu2255 奔小康赚大钱 km算法 链接:http://acm.hdu.edu.cn/showproblem.php?pid=2255 题意:lv 思路:最优匹配(最大权完美匹配) ...

随机推荐

  1. 解决使用SecureCRT不能连接Ubuntu的问题

    一.现象 SecureCRT是远程登陆工具及串口,可以远程进行登陆Linux服务器或者串口打印数据.但我下载安装了之后想通过SecureCRT来远程登陆我的Ubuntu,出现一直连接不上. 二.问题原 ...

  2. Writing buffer overflow exploits - a tutorial for beginners

    Buffer overflows in user input dependent buffers have become one of the biggest security hazards on ...

  3. SQL server 2012 安装SQL2012出现报错: 启用 Windows 功能 NetFx3 时出错

    在window server 2012服务器上,安装 SQL Server 2012的过程中,报了一个错误,一个安装失败, 在安装SQL 2012的过程中.出现下面错误:启用 Windows 功能 N ...

  4. Beginning iOS Programming

    Beginning iOS Programming 2014年 published by Wrox

  5. 1.2 Use Cases中 Commit Log官网剖析(博主推荐)

    不多说,直接上干货! 一切来源于官网 http://kafka.apache.org/documentation/ Commit Log 提交日志 Kafka can serve as a kind ...

  6. datetime小练习

    题目: 1.计算你的生日比如近30年来(1990-2019),每年的生日是星期几,统计一下星期几出现的次数比较多2,生日提醒,距离生日还有几天 # !/usr/bin/env python # -*- ...

  7. ActiveX控件开发 C#

    转自:http://hi.baidu.com/charlesx_kst/item/9c2f42e2920db3f42b09a4ff 前言: 这段时间因为工作的需要,研究了一下ActiveX控件.总结如 ...

  8. 洛谷 P1510 精卫填海

    洛谷 P1510 精卫填海 题目描述 [版权说明] 本题为改编题. [问题描述] 发鸠之山,其上多柘木.有鸟焉,其状如乌,文首,白喙,赤足,名曰精卫,其名自詨.是炎帝之少女,名曰女娃.女娃游于东海,溺 ...

  9. 【Codeforces Round #446 (Div. 2) C】Pride

    [链接] 我是链接,点我呀:) [题意] 在这里输入题意 [题解] 想一下,感觉最后的结果肯定是从某一段开始,这一段的gcd为1,然后向左和向右扩散的. 则枚举那一段在哪个地方. 我们设这一段中所有的 ...

  10. StringBuilder和String的区别

      使用   StringBuilder 语言 C# String   对象是不可改变的.每次使用   System.String   类中的方法之一时,都要在内存中创建一个新的字符串对象,这就需要为 ...