1.概述

在基础篇里面讲模板匹配的时候已经介绍过,图像匹配主要有基于灰度和基于特征两种方法。基于特征匹配的方法有很多种如:FAST、HARRIS、SIFT、SURF、SUSAN等。其中SIFT算法由D.G.Lowe于1999年提出,2004年完善总结。SIFT是一种鲁棒性好的尺度不变特征描述方法,但SIFT算法计算数据量大、时间复杂度高、算法耗时长。针对上述缺点许多研究者对SIFT算法做了不同的改进,Yanke等人提出用PCA-SIFT方法对特征描述进行数据降维,但在没有任何先验知识的情况下反而增加了计算量;Delpont等人提出用SVD方法进行特征匹配,但匹配过程计算复杂,且不能用于宽基线匹配;Grabner等人用积分图像虽提高了SIFT的计算速度,但是降低了SIFT方法的优越性。
Herbert Bay等人于2006年提出了SIFT算法的改进算法SURF算法,其性能超过了SIFT算法且能够获得更快的速度。SURF在光照变化和视角变化不变性方面的性能接近SIFT算法,尤其对图像严重模糊和旋转处理得非常好。且标准的SURF算子比SIFT算子快好几倍,SURF算法最大的特征在于采用了harr特征以及积分图像的概念,这大大加快了程序的运行速度。
SURF算法和SIFT算法在opencv中是一种很高级的算法,opencv提供了SURF算法的API接口。需要说明的是SURF和SIFT算法在OpenCV提供的nonfree中,而且在OpenCV3.x后不再集成到OpenCV发行版中,同意存放到opencv_contrib中,需要去opencv github页面手动下载编译。点击跳转,编译方法网上有很多教程。

2.Surf原理

特征点的提取基于尺度空间理论,我们通过检测图像局部极值点来锁定特征点坐标,即局部的最亮点或最暗点。

2.1构建Hessian矩阵

SURF算法检测特征点是基于Hessian矩阵实现的,Hessian矩阵是SURF算法的核心。设f(x,y)为二阶可微函数,Hessian矩阵H是函数、偏导数组成如下:

Hessian矩阵判别式为:

判别式的值是H矩阵的特征值,可以利用判别式的符号确定是否是极值,若det⁡(H)<0则可判断(x, y)不是局部极值点,若det⁡(H)>0则可判断点(x, y)为局部极值点。
将上述方法应用到图像中,给出图像中的一个点,其像素可表示为I(x, y),在尺度为σ其Hessian矩阵定义如下:

式中:L_xx是高斯滤波二阶导同I=(x,y)卷积的结果,其中L_xy、L_yy的含义类似。
空间尺度理论中高斯是最优化的分析方法。Bay等人指出高斯分析需要对图像进行离散化和裁剪,即使使用高斯滤波对图像进行采样也会出现走样的情况。所以可以使用方框滤波来代替高斯滤波,使用积分图像来加快卷积以提高计算速度。
在原始图像上,使用方框滤波器的效果反映在掩膜版尺寸上。如图所示为9×9方框滤波掩膜版,其中灰色部分掩膜版值为0.对应二阶高斯滤波系数σ=1.2,方框滤波模板同图像卷积运算后的值记分别记为D_xx,D_yy,D_xy。

为平衡准确值与近似值间的误差引入权值,权值随尺度变化,H矩阵判别式可以表示为:

由于高斯滤波与近似高斯滤波的差异性,我们用根据公式计算滤波响应的相对权重系数进一步平衡Hessian矩阵行列式的相对权重,其中|��|��是Frobenius范数,这样就保证了Frobenius范数能够适用于任何尺寸的滤波器模板。在实际应用中,用常量0.9表示其相对权重系数不会对结果产生较大的影响。

2.2尺度不变性

为了使图像具有尺度不变性以适应不同的图像中目标尺度的变化,我们需要构建尺度空间进行SURF特征点的提取。图像金字塔是图像多尺度表达的一种方式,为了获取图像在不同尺度下通过Hessian矩阵判别式得到极值点,用类似SIFT的方法构建尺度图像金字塔,将尺度空间分为若干阶(octave),每一阶存储了不同尺寸的方框滤波对输入图像进行滤波后得到的模糊程度不同的图片。但SURF算法中图片大小是一直不变的,只是不同阶中方框滤波模板大小不相同。在每一阶中选择4层的尺度图像,构建参数如图所示:

灰色底的数字表示方框滤波模板的大小。如果图像尺寸远大于模板大小,还可以继续增加阶数。若模板尺寸为N×N,则该模板对应的尺度为σ=1.2×9/N。通过Hessian矩阵求出个尺度极值后,在3×3×3的立体邻域内进行非极大值比较,若该极值点仍为最大值或最小值,则该极值点为候选特征点,然后在尺度空间和图像空间中进行插值运算,得到稳定的特征点位置及所在的尺度值。

2.3特征点主方向选取

SIFT算法选取特征点主方向是采用在特征点领域内统计其梯度直方图,取直方图bin值最大的以及超过最大bin值80%的那些方向作为特征点的主方向。而SURF算法是通过统计特征点领域内的Haar小波特征确定其主方向。

为保证旋转不变性,以特征点为中心,计算特征点邻域(如半径为6s的圆,s为该点所在尺度)内的点在x,y方向的Haar小波响应,Haar小波边长取4s,这样一个扇形得到了一个值。然后60°扇形以一定间隔进行旋转,将60°范围内的响应相加以形成新的矢量,遍历整个圆形区域,选择最长矢量的方向为该特征点的主方向。

2.4特征点描述算子

SURF算法中,以特征点为中心,将坐标轴旋转到主方向以确保旋转不变性。按照主方向选取边长为20s的正方形区域,然后将该区域划分为4×4的子区域,每个子区域计算5s×5s范围内的小波响应。

相对于主方向的水平、垂直方向的Haar小波响应分别记做d_x 、d_y,同样赋予响应值以权值系数,以增加对集合变换的鲁棒性;之后将每个子区域的响应及其绝对值相加形成,这样在每个子区域形成四维分量的矢量,因此对每一个特征点,则形成64维的描述向量,再进行向量的归一化,从而对光照具有一定的鲁棒性。

3.OpenCV API

在opencv中可以看到如下定义

typedef SURF    cv::xfeatures2d::SurfDescriptorExtractortypedef SURF    cv::xfeatures2d::SurfFeatureDetector

也就是说在我们实际使用中是根据不同的功能分别调用SurfDescriptorExtractor和SurfFeatureDetector两个函数的,同样SIFT算法也有类似定义如下:

typedef SIFT    cv::xfeatures2d::SiftDescriptorExtractortypedef SIFT    cv::xfeatures2d::SiftFeatureDetector

有需要使用SIFT算法的同学可以参考下。重点说一下SURF算法的两个函数。
SURF算法作为一个大类,其继承关系可参照下图:

其成员函数有很多,如下:

virtual bool    getExtended () const =0virtual double  getHessianThreshold () const =0virtual int     getNOctaveLayers () const =0virtual int     getNOctaves () const =0virtual bool    getUpright () const =0virtual void    setExtended (bool extended)=0virtual void    setHessianThreshold (double hessianThreshold)=0virtual void    setNOctaveLayers (int nOctaveLayers)=0virtual void    setNOctaves (int nOctaves)=0virtual void    setUpright (bool upright)=0

函数详细含义可以查询OpenCV文档得知。这里介绍一下特征点的检测。
利用SURF算法进行特征点检测可以使用SurfFeatureDetector及它的子函数detect(位于其父类Feature2D中)来实现检测过程,使用drawKeypoints函数绘制检测到的关键点。
drawKeypoints

void cv::drawKeypoints  (   InputArray  image,const std::vector< KeyPoint > &     keypoints,InputOutputArray    outImage,const Scalar &  color = Scalar::all(-1),int     flags = DrawMatchesFlags::DEFAULT )

image:输入图像
**keyPoint:**SURF算法检测到的特征点
outImage:输出图像,其内容取决于第五个参数标识符
color:绘制特征点颜色,有默认值Scalar::all(-1)
flags:绘制特征点的特征标识符,有默认值,有如下方式:

enum    { DEFAULT = 0, //创建输出图像矩阵,使用现存的输出图像绘制匹配对和特征点,对每一个关键点只绘制中间点DRAW_OVER_OUTIMG = 1,//不创建输出图像矩阵,而是在输出图像上绘制匹配对 NOT_DRAW_SINGLE_POINTS = 2, //单点特征点不被绘制 DRAW_RICH_KEYPOINTS = 4 //对每一个特征点绘制带大小和方向的关键点图形。}

这里有必要说一下KeyPoint()类,是一个为特征点检测而形成的数据结构,用于表示特征点,其类结构如下:

cv::KeyPoint::KeyPoint  (   Point2f     _pt,float   _size,float   _angle = -1,float   _response = 0,int     _octave = 0,int     _class_id = -1 )

_pt:特征点坐标
_size特征点直径
_angle:特征点方向,范围为[0,360),负值表示不使用
_response:关键点检测器对于关键点的响应程度,也就是关键点强度
_octave:特征点所在金字塔的层
_class_id:用于聚类的id
函数还有另外一种定义形式如下:

cv::KeyPoint::KeyPoint  (   float   x,float   y,float   _size,float   _angle = -1,float   _response = 0,int     _octave = 0,int     _class_id = -1 )

4.示例代码

#include <iostream>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <opencv2/nonfree/nonfree.hpp>
#include <opencv2/imgproc/imgproc.hpp>using namespace std;
using namespace cv;int main()
{Mat srcImage = imread("Surf_test_image.jpg");//判断图像是否读取成功if (srcImage.empty()){cout << "图像加载失败" << endl;return -1;} else{cout << "图像加载成功" << endl << endl;}namedWindow("原图像",WINDOW_AUTOSIZE);imshow("原图像",srcImage);Mat imageMid;   //定义滤波后图像//GaussianBlur(srcImage,imageMid,Size(9, 9),0,0);       //kernel尺寸为3x3的高斯滤波//namedWindow("高斯滤波后图像",WINDOW_AUTOSIZE);//imshow("高斯滤波后图像",imageMid);int minHessian = 700;                           //定义Hessian矩阵阈值特征点检测算子SurfFeatureDetector detector(minHessian);       //定义SURF检测器vector<KeyPoint> keypoints;                     //定义KeyPoint类型的矢量容器vector存储检测到的特征点detector.detect(srcImage,keypoints);            //调用detect检测特征点//绘制检测到的特征点Mat dstImage;//drawKeypoints(imageMid,keypoints,dstImage,Scalar::all(-1),DrawMatchesFlags::DEFAULT); //高斯滤波后关键点检测drawKeypoints(srcImage, keypoints, dstImage, Scalar::all(-1), DrawMatchesFlags::DEFAULT);namedWindow("特征点检测",WINDOW_AUTOSIZE);imshow("特征点检测",dstImage);waitKey(0);return 0;
}

运行结果

opencv之SURF算法原理及关键点检测相关推荐

  1. 使用opencv的LBF算法进行人脸关键点检测

    首先下载最新的opencv 和opencv_contrib, 然后按照在Windows下编译扩展OpenCV 3.1.0 + opencv_contrib的方法进行编译,其中核心一点就是先编译open ...

  2. pythonopencv算法_python opencv之SURF算法示例

    本文介绍了python opencv之SURF算法示例,分享给大家,具体如下: 目标: SURF算法基础 opencv总SURF算法的使用 原理: 上节课使用了SIFT算法,当时这种算法效率不高,需要 ...

  3. Surf——算法原理

    Surf算法是对Sift算法的一种改进,主要是在算法的执行效率上,比Sift算法来讲运行更快! 1.算法原理:2.源码简析:3.OpenCV中Demo分析:4.一些关于Surf算法的剖析. Surf算 ...

  4. python opencv入门 SURF算法(34)

    内容来自OpenCV-Python Tutorials 自己翻译整理 目标: SURF算法基础 opencv总SURF算法的使用 原理: 上节课使用了SIFT算法,当时这种算法效率不高,需要更快速的算 ...

  5. OpenCV:SURF算法浅析

    引子: 课题需要SURF特征提取算法,在运动中提取摄像头图像中的特征点,并进行跟踪匹配,以此估计运动状态.开始找到了SIFT算法,SIFT特征提取具有极强的适应能力,但运算量稍大,后来就有了SURF特 ...

  6. 基于Python,OpenCV,Numpy和Albumentations实现关键点检测的合成数据集

    1.概述 训练关键点检测模型,如 Keypoint RCNN,需要一个数据集,其中包含具有感兴趣对象和标注的图像(具有对象关键点和边界框坐标的文本文件). 例如,在下图中,您可以看到可视化的关键点和边 ...

  7. surf算法原理-包你明白surf过程

    SURF 算法,全称是 Speeded-Up Robust Features.该算子在保持 SIFT 算子优良性能特点的基础上,同时解决了 SIFT 计算复杂度高.耗时长的缺点,对兴趣点提取及其特征向 ...

  8. Opencv与dlib联合进行人脸关键点检测与识别

    前言 依赖库:opencv 2.4.9 /dlib 19.0/libfacedetection 本篇不记录如何配置,重点在实现上.使用libfacedetection实现人脸区域检测,联合dlib标记 ...

  9. python+OpenCv+dlib实现人脸68个关键点检测

    pip install dlib==19.7.0 下载地址: http://dlib.net/files/ dlib中为我们提供了关于人脸检测标注训练好的文件可在http://dlib.net/fil ...

最新文章

  1. 如何区分直连串口线和交叉串口线?
  2. Libvirt — 4 种主机虚拟化网络模式
  3. 计算机编程语言python-PYTHON之计算机语言基础知识 —— 编程语言的分类
  4. android 百度悬浮搜索框,百度的搜索框效果如何实现的???
  5. 中国企业飞鸽传书市场
  6. python爬虫模拟浏览器的两种方法_python爬虫模拟浏览器访问-User-Agent过程解析
  7. 深入理解NIO - Selector、ServerSocketChannel、SocketChannel底层原理
  8. VMware快照的工作原理
  9. 华为鸿蒙11什么时候发布,原创 华为EMUI11正式发布,今年12月可升级为鸿蒙OS2.0国产操作系统...
  10. 右键文件夹没有git clone命令的解决方法
  11. JAVA实现Word转Pdf文件
  12. javacv 人脸追踪_JavaCV开发详解之5:基于 JavaCV 的人脸识别
  13. pygame中的mixer(含music)模块
  14. 实验三 交换机的配置
  15. 公众号运营-Datawhale-1
  16. MATLAB中:冒号用法
  17. Qt中提示“常量中有换行符“的解决方法
  18. java读取Excel内容添加到list集合里面去
  19. clamwin anti-virus编译问题
  20. 热烈庆祝下Air2.0版Rock506Dock beta1.0上线~

热门文章

  1. Selenium:简介
  2. web页面引用OCX控件,客户端浏览器设置
  3. java 月份日历表_java 输入年月,获取日历表
  4. 杂谈 吓自己一跳的新浪微博验证pin码
  5. 2021【软件测试】面试题合集大放送
  6. TryHackMe-Wreath [网络杀伤链](windows网络)渗透测试
  7. IPTV收官之战-----机顶盒浏览器内核获取及适配
  8. 景联文科技:深度探究自动驾驶重要方向——车路协同
  9. AIFF-C压缩格式容器规范解析
  10. Pyart学习笔记:风场模拟