- ubuntu12.04环境下使用kvm ioctl接口实现最简单的虚拟机
- Ubuntu 通过无线网络安装Ubuntu Server启动系统后连接无线网络的方法
- 在Ubuntu上搭建网桥的方法
- ubuntu 虚拟机上网方式及相关配置详解
CFSDN坚持开源创造价值,我们致力于搭建一个资源共享平台,让每一个IT人在这里找到属于你的精彩世界.
这篇CFSDN的博客文章python opencv之SURF算法示例由作者收集整理,如果你对这篇文章有兴趣,记得点赞哟.
本文介绍了python opencv之surf算法示例,分享给大家,具体如下:
目标:
原理:
上节课使用了sift算法,当时这种算法效率不高,需要更快速的算法。在06年有人提出了surf算法“加速稳定特征”,从名字上来看,他是sift算法的加速版本.
(原文) 在sift算法当中使用高斯差分方程(difference of gaussian)对高斯拉普拉斯方程( laplacian of gaussian)进行近似。然而,surf使用盒子滤波器进行近似,下面的图片显示了这种近似的方法。在进行卷积计算的时候可以利用积分图像,这是使用盒子形滤波器的一个优点,即计算某个窗口中的像素和的时候,计算量大小,也就是时间复杂度不受到窗口大小的影响。而且,这种运算可以在不用的尺度空间当中实现.
surf算法计算关键点的尺度和位置信息使用hessian矩阵实现.
(解释) 文中的高斯拉普拉斯方程(算子)是检测图像中斑点的一种十分常用的方法。以一维高斯函数来检测一维信号中的斑点为例。有一维信号f,高斯函数的一阶导数 d d x g" role="presentation"> ddxg ,信号与高斯函数的一阶导数卷积后,会在边缘处出现极值。如图:
上面图片是在一维情况下,使用高斯函数的一阶导数的情况,另一种方法是使用高斯函数的二阶导数与信号进行卷积,高斯函数的二阶导数也叫做拉普拉斯变换.
但是,在一维信号斑点检测的实际情况当中,一个斑点可以考虑成是两个相邻的跳突组成,如下图.
类似于在图像当中,一个轮胎可以当成一个斑点,一个苍蝇也可以当成一个斑点。但是在使用高斯函数的二阶导数来检测斑点的时候,使用不同的高斯核(就是方差)运算不同大小的斑点时,计算出来的极值,即响应值会出现衰减.
此时,需要将高斯函数的二阶导数进行正规化,去除方差值不同导致响应值出现的衰减.
以上,是一维高斯函数检测一维信号的原理。二维的图像信号,使用二维高斯函数来检测斑点原理基本相同,此处的二维高斯函数的二阶导数,就叫做高斯拉普拉斯算子也就是log,通过改变不同的方差值,可以检测不同尺寸的二维斑点,如图.
文中的高斯差分方程是sift算法当中,发明者想要利用两个相邻高斯尺度空间的图像相减来得到一个log的近似,因为这样做可以节省时间,而且可以控制精度变化,类似于高等数学当中泰勒公式那玩意-_- 。关于sift原理可以看上一篇博客 。
文中提到的积分图像实际上原理非常简单,类似递推方程。积分图像的目的是想建立一个函数,能够快速得到一个矩形图像区域当中所有像素值的和是多少。那么,设 p ( i , j )" role="presentation"> p(i,j) 表示从 ( 0 , 0 )" role="presentation"> (0,0) 点到 ( i , j )" role="presentation"> (i,j) 点的所有像素的和是多少,存储在 p ( i , j )" role="presentation"> p(i,j) 这个数组里面,如果想要获得w区域的像素和是多少,如图,只要计算 p ( i 4 , j 4 ) − p ( i 2 , j 2 ) − p ( i 3 , j 3 ) + p ( i 1 , j 1 )" role="presentation"> p(i4,j4)−p(i2,j2)−p(i3,j3)+p(i1,j1) 即可.
如何求得 p ( i , j )" role="presentation"> p(i,j) ? 递推公式为, p ( i , j ) = p ( i − 1 , j ) + p ( i , j − 1 ) + i ( i , j ) − p ( i − 1 , j − 1 )" role="presentation"> p(i,j)=p(i−1,j)+p(i,j−1)+i(i,j)−p(i−1,j−1) ,这里面 i ( i , j )" role="presentation"> i(i,j) 表示像素点 ( i , j )" role="presentation"> (i,j) 处的像素值.
文中提到的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响应值的水平方向,垂直方向进行累加。由于时使用一个圆形区域,转换成类似极坐标矢量的方式来表示,每个窗口中的结果 ( m w , θ w )" role="presentation"> (mw,θw) ,如图.
主方向最大haar响应值累加对应的方向。其中,如果除了主方向,还有其它方向的响应累加值较大,算法当中还会额外添加一个特征点,并赋予另外一个次大方向.
文中建立的特征描述符顾名思义,就是描述一个特征点的一组向量,里面唯一确定了一个特征。surf获取主方向后,需要获取特征点描述子。以特征点为原点,主方向为横轴建立一个二维坐标系,区域大小是20s×20s,分成是个之块,每个子块利用2s的haar模板进行响应计算。然后统计 Σ d x 、 Σ | d x | 、 Σ d y 、 Σ | d y |" role="presentation"> σdx、σ|dx|、σdy、σ|dy| ,每个20s的窗口分成4×4的子窗口,每个子窗口中又5s×5s个像元。如图 。
又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 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
|
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
)
|
凤的嘴上特征点占了这么多,辨识度还是蛮高的~ -_-||| 。
下面是设置方向,和输出一些值的方法 。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
|
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
)
|
以上就是本文的全部内容,希望对大家的学习有所帮助,也希望大家多多支持我.
原文链接:http://blog.csdn.net/tengfei461807914/article/details/79177897 。
最后此篇关于python opencv之SURF算法示例的文章就讲到这里了,如果你想了解更多关于python opencv之SURF算法示例的内容请搜索CFSDN的文章或继续浏览相关文章,希望大家以后支持我的博客! 。
滑动窗口限流 滑动窗口限流是一种常用的限流算法,通过维护一个固定大小的窗口,在单位时间内允许通过的请求次数不超过设定的阈值。具体来说,滑动窗口限流算法通常包括以下几个步骤: 初始化:设置窗口
表达式求值:一个只有+,-,*,/的表达式,没有括号 一种神奇的做法:使用数组存储数字和运算符,先把优先级别高的乘法和除法计算出来,再计算加法和减法 int GetVal(string s){
【算法】前缀和 题目 先来看一道题目:(前缀和模板题) 已知一个数组A[],现在想要求出其中一些数字的和。 输入格式: 先是整数N,M,表示一共有N个数字,有M组询问 接下来有N个数,表示A[1]..
1.前序遍历 根-左-右的顺序遍历,可以使用递归 void preOrder(Node *u){ if(u==NULL)return; printf("%d ",u->val);
先看题目 物品不能分隔,必须全部取走或者留下,因此称为01背包 (只有不取和取两种状态) 看第一个样例 我们需要把4个物品装入一个容量为10的背包 我们可以简化问题,从小到大入手分析 weightva
我最近在一次采访中遇到了这个问题: 给出以下矩阵: [[ R R R R R R], [ R B B B R R], [ B R R R B B], [ R B R R R R]] 找出是否有任
我正在尝试通过 C++ 算法从我的 outlook 帐户发送一封电子邮件,该帐户已经打开并记录,但真的不知道从哪里开始(对于 outlook-c++ 集成),谷歌也没有帮我这么多。任何提示将不胜感激。
我发现自己像这样编写了一个手工制作的 while 循环: std::list foo; // In my case, map, but list is simpler auto currentPoin
我有用于检测正方形的 opencv 代码。现在我想在检测正方形后,代码运行另一个命令。 代码如下: #include "cv.h" #include "cxcore.h" #include "high
我正在尝试模拟一个 matlab 函数“imfill”来填充二进制图像(1 和 0 的二维矩阵)。 我想在矩阵中指定一个起点,并像 imfill 的 4 连接版本那样进行洪水填充。 这是否已经存在于
我正在阅读 Robert Sedgewick 的《C++ 算法》。 Basic recurrences section it was mentioned as 这种循环出现在循环输入以消除一个项目的递
我正在思考如何在我的日历中生成代表任务的数据结构(仅供我个人使用)。我有来自 DBMS 的按日期排序的任务记录,如下所示: 买牛奶(18.1.2013) 任务日期 (2013-01-15) 任务标签(
输入一个未排序的整数数组A[1..n]只有 O(d) :(d int) 计算每个元素在单次迭代中出现在列表中的次数。 map 是balanced Binary Search Tree基于确保 O(nl
我遇到了一个问题,但我仍然不知道如何解决。我想出了如何用蛮力的方式来做到这一点,但是当有成千上万的元素时它就不起作用了。 Problem: Say you are given the followin
我有一个列表列表。 L1= [[...][...][.......].......]如果我在展平列表后获取所有元素并从中提取唯一值,那么我会得到一个列表 L2。我有另一个列表 L3,它是 L2 的某个
我们得到二维矩阵数组(假设长度为 i 和宽度为 j)和整数 k我们必须找到包含这个或更大总和的最小矩形的大小F.e k=7 4 1 1 1 1 1 4 4 Anwser是2,因为4+4=8 >= 7,
我实行 3 类倒制,每周换类。顺序为早类 (m)、晚类 (n) 和下午类 (a)。我固定的订单,即它永远不会改变,即使那个星期不工作也是如此。 我创建了一个函数来获取 ISO 周数。当我给它一个日期时
假设我们有一个输入,它是一个元素列表: {a, b, c, d, e, f} 还有不同的集合,可能包含这些元素的任意组合,也可能包含不在输入列表中的其他元素: A:{e,f} B:{d,f,a} C:
我有一个子集算法,可以找到给定集合的所有子集。原始集合的问题在于它是一个不断增长的集合,如果向其中添加元素,我需要再次重新计算它的子集。 有没有一种方法可以优化子集算法,该算法可以从最后一个计算点重新
我有一个包含 100 万个符号及其预期频率的表格。 我想通过为每个符号分配一个唯一(且前缀唯一)的可变长度位串来压缩这些符号的序列,然后将它们连接在一起以表示序列。 我想分配这些位串,以使编码序列的预
我是一名优秀的程序员,十分优秀!