1.概述
SURF–Speeded up Robust Features(加速稳健特征),是一种稳健的局部特征点检测和描述算法。算法的基本路程可以分为三大部分
2.算法原理
2.1、SURF特征检测步骤
1.尺度空间的极值检测:搜索所有尺度空间上的图像,通过Hessian来识别潜在的对尺度和选择不变的兴趣点
2.特征点过滤并进行精确定位
3.特征方向赋值:统计特征点圆形领域内的Harr小波特征。即在60°扇形内,每次将60°扇形区域旋转0.2弧度进行统计,将值最大的哪个扇形的方向作为特征点的主方向
4.特征点描述:沿着特征点主方向周围的邻域内,取4X4X4个矩形区域,统计每个小区域的Harr特征,然后每个区域得到一个4维的特征向量。一个特征点共有64维的特征向量作为SURF特征的描述子。
2.2、构建Hessian(黑塞矩阵)
构建Hessian矩阵的目的是为了生成图像稳定的边缘点(突变点),维特征提取做准备。
Hessian Matrix是由一个多元函数的二阶偏导数构成的矩阵,描述了函数的局部曲率,对于一个图像I(x,y),其Hassian矩阵如下:
H矩阵的判别式是:
在构建Hessian矩阵前需要对图像进行高斯滤波,经过滤波后的Hessian矩阵表达式为:
其中x,y为像素位置,L(x,y,σ)=G(σ)*I(x,y),代表着像素的高斯尺度空间,是由图像和不同的高斯卷积得到的。
在离散数学图像中,一阶导数是相邻像素的灰度差:
而在Hessian中是二阶导数:
看Hessian矩阵判别式,其实就是当前点对水平方向二阶偏导数乘以垂直方向二阶偏导数,再减去当前水平,垂直二阶偏导的二次方。
通过这种方法可以为图像中每个像素计算出其H行列式的决定值,并用这个值来判别图像局部特征点。Hession矩阵判别式中的L(x,y)L(x,y)是原始图像的高斯卷积,由于高斯核服从正态分布,从中心点往外,系数越来越小,为了提高运算速度,SURF使用了盒式滤波器代替了高斯滤波器。
目的是为了平衡因使用盒式滤波器近似带来的误差,而H矩阵判别式可表示为
盒式滤波器和高斯滤波器示意图如下
上两图是9X99X9的高斯滤波器模板分别在图像垂直方向上二阶导数的值,下边则是盒式滤波对其近似,灰色部分像素值为0,黑色为-2,白色为1.
正因为它转换为了积分图的使用,将对图像的滤波转化成了计算图像上不同区域间像素的加减运算问题,提高了运算速度
2.3、构建尺度空间
上图右半边是SURF的尺度空间;在SURF算法中,不同组间图像的尺寸都是一致的,不同的是不同组间使用的盒式滤波器的模板尺寸逐渐增大
2.4、特征点过滤并进行精确定位
将经过Hessian矩阵处理的每个像素点(即获得每个像素点Hessian矩阵的判别式值)与其图像域(相同大小的图像)和尺度域(相邻的尺度空间)的所有相邻点进行比较,当其大于或小于所有相邻点时,该点就是极值点。
如上图所示,中间的检测点要和其所在图像的3X33X3邻域8个像素点,以及其相邻的上下两层3X33X3邻域的18个像素点,共26个像素点进行比较。
初步定位出像素点后,在经过滤除能量比较弱的关键点以及错误定位的关键点,筛选出最终稳定的特征点
2.5、计算特征点主方向
在SURF算法中,采用的是统计特征点圆形领域内的Harr小波特征,即在特征点的圆形邻域内,统计60°扇形内所有点的水平,垂直Harr小波特征综合,然后扇形以0.2弧度大小的间隔进行旋转并再次统计该区域内Harr小波特征值后,最后将值最大的哪个扇形的方向作为该特征点的主方向
2.6生成特征描述
提取特征点周围的4X4 4X4个矩形区域快,所取得的方向沿着特征点的主方向。每个子区域统计25个像素点水平方向和垂直方向的Haar小波特征。
该Harr小波特征为水平方向值之和,垂直方向值之和,水平方向值绝对值之和以及垂直方向值绝对值之和四个方向
把这四个值作为每个子块区域的特征向量,所以一共有4X4X4=64维向量作为SURF特征的描述子
2.7、特征点匹配
surf是通过计算两个特征点间的欧式距离来确定匹配度的,欧式距离越短,代表两个特征点匹配的与人好。并且surf还加入了Hessian矩阵迹的判断,如果两个特征点的矩阵迹正负号相同,代表这两个特征具有相同方向上的对比度变化,如果不同则待变变化方向是相反的
3.API
4.代码
#include<opencv2/opencv.hpp>
#include<opencv2/xfeatures2d>
#include<math.h>
#include<iostream>
using namespace cv;
using namespace std;
using namespace cv::xfeatures2d;
Mat src, gray_src;
const char* output_title = "output_win";
int corners = 20;
int max_corners = 50;
void Tomasi_Demo(int, void*);
void SubPixel_Demo(int, void*);
int main(int argc, char** argv) {
src = imread("C:/Users/18929/Desktop/博客项目/项目图片/18.jpg");
if (src.empty()) {
printf("could not load image");
return -1;
}
namedWindow("input image", CV_WINDOW_AUTOSIZE);
imshow("input_img", src);
//定义黑塞矩阵阈值,低于该阈值的极大值不算边缘点
int minHessian = 400;
//定义SURF检测矩阵
Ptr<SURF> detector = SURF::create(minHessian);
//定义keypoint类型容器装检测点,可以装检测点的同时还可以直接画出
vector<KeyPoint> keypoints;
//检测
detector->detect(src, keypoints, Mat());
//画出检测点
Mat keypoint_img;
drawKeypoints(src, keypoints, keypoint_img, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
// Scalar::all(-1)--颜色随机
imshow("keypoint_img", keypoint_img);
waitKey(0);
return 0;
}