SURF(SpeededUp Robust Features)。
SURF 最大的特征在于
采用了 harr 特征以及积分图像的概念
,加快了程序的运行时间 。SURF 可以应用于计算机视觉的物体识别以及 3D 重构中。
SURF算法原理
1、
构造Hessian矩阵,构造高斯金字塔尺度空间
surf采用的是Hessian矩阵行列式近似值图像。Hessian矩阵是Surf算法的核心。在数学中,海森矩阵(Hessian matrix或Hessian)是一个自变量为向量的实值函数的二阶偏导数组成的方块矩阵。假设函数f(z,y),Hessian矩阵H是函数、偏导数组成。图像中某个像素点的Hessian矩阵,如下:
即每一
个像
素点都可
以求出一个
Hess
ian
矩阵。
H矩阵判别式为:
判别式的值是H矩阵的特征值,可以利用判定结果的符号将所有点分类,根据判别式取值正负,来判别该点是或不是极值点。
2、
利用非极大值抑制初步确定特征点
将经过hessian矩阵处理过的每个像素点与其三维领域的26个点进行大小比较,如果它是这26个点中的最大值或者最小值,则保留下来,当做初步的特征点。检测过程中使用与该尺度层图像解析度相对应大小的滤波器进行检测。以3 X 3的滤波器为例,该尺度层图像中9个像素点之一的检测特征点与自身尺度层中其余8个点和在其之上及之下的两个尺度层的各9个点进行比较,共26个点,标记的“x”的像素点的特征值若大于周围像素,则可确定该点为该区域的特征点。
3、
精确定位极值点
采用
三维线性插值法得到亚像素级的特征点
,同时也去掉那些值小于一定阈值的点,增加极值使检测到的特征点数量减少,最终只有几个特征最强点会被检测出来。
4、
选取特征点的主方向
Sift
选取特征点主方向是
采用在特征点领域内统计其梯度直方图,取直方图bin值最大的以及超过最大bin值 80%的那些方向做为特征点的主方向。
在
surf
中,不统计其梯度直方图,而是
统计特征点领域内的harr小波特征
。即在特征点的领域(比如说,半径为6s 的圆内,s为该点所在的尺度)内,统计60度扇形内所有点的水平haar小波特征和垂直 haar小波特征总和,haar小波的尺寸变长为4s,这样一个扇形得到了一个值。然后60度扇形以一定间隔进行旋转,最后将最大值那个扇形的方向作为该特征点的主方向。如图所示:
5、
构造SURF特征点描述算子
在
sift
中,是在特征点周围取16×16的邻域,并把该领域化为4×4个的小区域,每个小区域统计8个方向梯度,最后得到4×4×8=128维的向量,该向量作为该点的sift描述子。
在
surf
中,也是在特征点周围取一个正方形框,框的边长为20s (s是所检测到该特征点所在的尺度)。该框带方向,方向是第4步检测出来的主方向。然后把该框分为16个子区域,每个子区域统计25个像素的水平方向和垂直方向的 haar小波特征,这里的水平和垂直方向都是相对主方向而言。该haar小波特征为水平方向值之和,水平方向绝对值之和,垂直方向之和,垂直方向绝对值之和。该过程如图所示:
这样每个小区域就有4个值,所以每个特征点就是16×4=64维的向量,相比sift而言,少了一半,这在特征匹配过程中会大大加快匹配速度。
SURF特征点检测
涉及到的是 SURF、urfFeatureDetector 、SurtDescriptorExtractor 三个类Opencv\sources\modules\nonfreelincludelopenc v2\nonfree路径下的
features2d.hpp
头文件中
SURF宏定义
typedef SURF SurfFeatureDetector;
typedef SURF SurfDescriptorExtractor;
绘制关键点: drawKeypoints 函数
void drawKeypoints(const Mat& image, const vector<KeyPoint>& keypoints, Mat& outImage, constscalar& color = Scalar::all(-1), int flags = DrawMatchesFlags::DEFAULT)
参数1,const Mat&类型的src,输入图像。
参数2,const vector<KeyPoint>&类型的keypoints,根据源图像得到的特征点。输出参数。
参数3,Mat&类型的outImage,输出图像,其内容取决于第五个参数标识符falgs。
参数4,const Scalar&类型的color,关键点的颜色,有默认值Scalar:all(-1)。
参数5,nt类型的flags,绘制关键点的特征标识符,有默认值
DrawMatchesFlags::DEFAULT。可选取值:
struct DrawMatchesFlags {
eum {
//创建输出图像矩阵(使用Mat : : create)。使用现存的输出图像绘制匹配对和特征点
// 且对每一个关键点,只绘制中间点
DEFAULT = 0,
//不创建输出图像矩阵,而是在输出图像上绘制匹配对
DRAW_OVER_OUTIMG = 1,
//单点特征点不被绘制
NOT_DRAW_SINGLE_POINTS – 2,
//对每一个关键点,绘制带大小和方向的关键点圆圈
DRAW_RICH_KEYPOINTS = 4
};
};
KeyPoint类
KeyPoint类是一个为特征点检测而生的数据结构,用于表示特征点。
class KeyPoint { Point2f pt; //坐标 float size; //特征点邻域直径 float angle; //特征点的方向,值为[0,360),负值表示不使用 float response; int octave; //特征点所在的图像金字塔的组 int class_id; //用于聚类的id }
void xfeatures2d::SURT::detect( InputArray image, std::vector<KeyPoint>& keypoints, InputArray mask=noArray() );
参数1,InputArray类型的image,输入Mat;
参数2,std::Vector类型的keypoints,检测到的关键点;
参数3,
InputArray类型的mask,默认为空,指定在何处查找关键点的掩码(可选)。它必须是8位整数感兴趣区域中具有非零值的矩阵。
例子:
使用FeatureDetector接口来发现感兴趣点。
使用SurfFeatureDetector以及其函数detect来实现检测过程
使用函数drawKeypoints绘制检测到的关键点。
#include "opencv2/nonfree/nonfree.hpp" //载入源图 Mat srcImage1 = imread("1.jpg", 1); Mat srcImage2 = imread("2.jpg", 1); //定义需要用到的变量和类 int minHessian = 400; //定义SURF中的hessian阖值特征点检测算子 //定义一个surfFeatureDetector(SURF)特征检测类对象 SurfFeatureDetector detector(minHessian); //vector模板类是能够存放任意类型的动态数组,能够增加和压缩数据 std::vector<KeyPoint> keypoints_1, keypoints_2; //调用detect函数检测出 SURF特征关键点,保存在vector容器中 detector.detect(srcImage1, keypoints_1); detector.detect(srcImage2, keypoints_2); //绘制特征关键点 Mat img_keypoints_l; Mat img_keypoints_2; drawKeyPoints(srcImagel, keypoints_1, img_keypoints_1, Scalar::all(-1), DrawMatchesFlags::DEFAULT); drawKeyPoints(srcImage2, keypoints_2, img_keypoints_2, Scalar::all(-1), DrawMatchesFlags::DEFAULT);