python opencv之SURF算法示例
本文介绍了python opencv之surf算法示例,分享给大家,具体如下:
目标:
- surf算法基础
- opencv总surf算法的使用
原理:
上节课使用了sift算法,当时这种算法效率不高,需要更快速的算法。在06年有人提出了surf算法“加速稳定特征”,从名字上来看,他是sift算法的加速版本。
(原文)
在sift算法当中使用高斯差分方程(difference of gaussian)对高斯拉普拉斯方程( laplacian of gaussian)进行近似。然而,surf使用盒子滤波器进行近似,下面的图片显示了这种近似的方法。在进行卷积计算的时候可以利用积分图像,这是使用盒子形滤波器的一个优点,即计算某个窗口中的像素和的时候,计算量大小,也就是时间复杂度不受到窗口大小的影响。而且,这种运算可以在不用的尺度空间当中实现。
surf算法计算关键点的尺度和位置信息使用hessian矩阵实现。
(解释)
文中的高斯拉普拉斯方程(算子)是检测图像中斑点的一种十分常用的方法。以一维高斯函数来检测一维信号中的斑点为例。有一维信号f,高斯函数的一阶导数
上面图片是在一维情况下,使用高斯函数的一阶导数的情况,另一种方法是使用高斯函数的二阶导数与信号进行卷积,高斯函数的二阶导数也叫做拉普拉斯变换。
但是,在一维信号斑点检测的实际情况当中,一个斑点可以考虑成是两个相邻的跳突组成,如下图。
类似于在图像当中,一个轮胎可以当成一个斑点,一个苍蝇也可以当成一个斑点。但是在使用高斯函数的二阶导数来检测斑点的时候,使用不同的高斯核(就是方差)运算不同大小的斑点时,计算出来的极值,即响应值会出现衰减。
此时,需要将高斯函数的二阶导数进行正规化,去除方差值不同导致响应值出现的衰减。
以上,是一维高斯函数检测一维信号的原理。二维的图像信号,使用二维高斯函数来检测斑点原理基本相同,此处的二维高斯函数的二阶导数,就叫做高斯拉普拉斯算子也就是log,通过改变不同的方差值,可以检测不同尺寸的二维斑点,如图。
文中的高斯差分方程是sift算法当中,发明者想要利用两个相邻高斯尺度空间的图像相减来得到一个log的近似,因为这样做可以节省时间,而且可以控制精度变化,类似于高等数学当中泰勒公式那玩意-_- 。关于sift原理可以看上一篇博客
文中提到的积分图像实际上原理非常简单,类似递推方程。积分图像的目的是想建立一个函数,能够快速得到一个矩形图像区域当中所有像素值的和是多少。那么,设
如何求得
文中提到的hessian矩阵,学过数学分析、最优化、机器学习之类的人肯定对这玩意非常熟悉,实际上黑塞矩阵就是一个多元函数的二阶偏导数构成的方阵,它的行列式值(determinant of hessian )可以反映的局部结构信息,简称doh。与log类似,doh可以使用不同方差生成高斯函数对各个元的二阶偏导模板,以此来对图像进行卷积运算。 同样,doh也会在卷积后的函数中,得到对图像信号斑点极值的响应。如图
在surf算法当中,黑塞矩阵中的l,即为二维高斯函数与图像的卷积,求得黑塞矩阵后,会得到如图。
将上面得到的模板与图像的卷积转换为盒子滤波器,这里使用原文中的图像,如图。
得到三个不同的盒子滤波器以后,对其进行近似和简化操作,并用其表示图像中某点的斑点响应值,遍历图像当中的所有像素,就得到了在某一尺度下斑点检测的响应图像。然后,利用不同的模板尺寸,获取多尺度斑点响应金字塔,在金字塔中搜索极值点,下面的操作就和sift算法类似了。
(原文)
为了给找到的特征点赋予方向,以特征点为中心,6s为半径获取水平和垂直小波响应运算结果,这里s是特征点尺度,同时使用高斯加权的方法。然后,他们会被绘制在如下图当中。其中,特征点的主方向估计运算是有一个弧度为60的扇形窗口,在滑动的过程中不断计算其中的响应值之和。有趣的是,小波响应值在任意尺度下使用积分图像很容易被获取。但是在多数情况下,旋转不变性不是必须的,可以代码当中将这一步取消,这样还能够提高算法计算速度,而且在+-15度的情况也保持稳定,此时该方法称作 u-surf。用户可以设置upright参数,当参数为0计算方向,参数为1不计算方向。
对于特征点描述的建立,surf再一次使用haar小波响应,同时使用积分图像使操作变得简单。在一个矩形区域当中,以特征点为中心,划取周围20s×20s区域的大小,以特征点为原点,主方向为横轴,分成四个子区域,每个子区域使用2s的haar小波响应,对于每个子区域,获取一个向量,记录垂直、水平方向上的小波响应值,如图。
这个特征描述符的长度使64,降低维度可以加速计算,又可以区分特征。为了更好的区分特征点,surf还使用了长度为128特征描述符。当dy小于0或者大于0时,计算dx或|dx|的和。同样,根据dx的符号计算不同的dy和。因此能够获得双倍的特征。计算复杂度也不会增加。opencv当中的extended参数为0或1时分别对应64和128的特征。
另外一个重要的改善是对潜在的兴趣点使用了拉普拉斯算子符号(黑塞矩阵的迹)。由于之前的计算已经完成对黑塞矩阵的构造,所以这步不会增加复杂度。
拉普拉斯符号在不同明暗背景下区分不同亮度的斑点,在匹配阶段,我们只需要比较拥有相同对比度的特征是否匹配即可,这样加快了计算速度,如图。
surf算法的速度是sift速度的3倍,善于处理模糊和旋转的图像,但是不善于处理视角变化和关照变化。
(解释)
文中的小波响应运算,全称是haar小波运算。这里使用haar小波目的是为了获取图像梯度,使用之前计算好的图像积分结果,这样能够提高计算速度。与sift算法类似,在对每个特征点获取主方向时,使用原文中提到的一个π/3大小的扇形窗口,同时以0.2弧度为步长旋转滑动此窗口,在每个窗口当中对的haar响应值的水平方向,垂直方向进行累加。由于时使用一个圆形区域,转换成类似极坐标矢量的方式来表示,每个窗口中的结果
主方向最大haar响应值累加对应的方向。其中,如果除了主方向,还有其它方向的响应累加值较大,算法当中还会额外添加一个特征点,并赋予另外一个次大方向。
文中建立的特征描述符顾名思义,就是描述一个特征点的一组向量,里面唯一确定了一个特征。surf获取主方向后,需要获取特征点描述子。以特征点为原点,主方向为横轴建立一个二维坐标系,区域大小是20s×20s,分成是个之块,每个子块利用2s的haar模板进行响应计算。然后统计
又4×4个子块,每个子块里面记录四个值,所以描述子一共又4×4×4=64个特征。
最后将沿着主方向的小波响应值扭转过来,原理就是简单的旋转矩阵。
代码部分
opencv里面提供的surf算法和sift差不多,这两个玩意都是受到版权保护的,如果你是用pip 一条命令安装的opencv,那么恭喜你用不了surf和sift算法,印象中只有2.4.9版本的opencv库才可以使用。
不过,办法还是有的,再控制台当中输入pip install opencv-contrib-python 就可以用了。
如果还是无法安装,可以直接网站早opencv-contrib-python的*,然后放到对应的文件下安装就行了。
我的版本是opencv 3.2,和教程文档中的使用方法不同。
详细参数可以自己去查一查,一查一个准的
https://docs.opencv.org/master/d5/df7/classcv_1_1xfeatures2d_1_1surf.html
import cv2 import numpy as np img = cv2.imread('feng.jpg') #参数为hessian矩阵的阈值 surf = cv2.xfeatures2d.surf_create(400) #找到关键点和描述符 key_query,desc_query = surf.detectandcompute(img,none) #把特征点标记到图片上 img=cv2.drawkeypoints(img,key_query,img) cv2.imshow('sp',img) cv2.waitkey(0)
凤的嘴上特征点占了这么多,辨识度还是蛮高的~ -_-|||
下面是设置方向,和输出一些值的方法
import cv2 import numpy as np img = cv2.imread('feng.jpg') #参数为hessian矩阵的阈值 surf = cv2.xfeatures2d.surf_create(4000) #设置是否要检测方向 surf.setupright(true) #输出设置值 print(surf.getupright()) #找到关键点和描述符 key_query,desc_query = surf.detectandcompute(img,none) img=cv2.drawkeypoints(img,key_query,img) #输出描述符的个数 print(surf.descriptorsize()) cv2.imshow('sp',img) cv2.waitkey(0)
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持。