本文主要是介绍特征提取与检测(二) --- SIFT算法,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
SIFT(Scale-invariant feature transform)是一种检测局部特征的算法,该算法通过求一幅图中的特征点(interest points,or corner points)及其有关scale 和 orientation 的描述子得到特征并进行图像特征点匹配,获得了良好效果,详细解析如下:
一、SIFT算法综述
特点:
1. SIFT特征是图像的局部特征,其对旋转、尺度缩放、亮度变化保持不变性,对视角变化、仿射变换、噪声也保持一定程度的稳定性;
2. 独特性(Distinctiveness)好,信息量丰富,适用于在海量特征数据库中进行快速、准确的匹配;
3. 多量性,即使少数的几个物体也可以产生大量的SIFT特征向量;
4. 高速性,经优化的SIFT匹配算法甚至可以达到实时的要求;
5. 可扩展性,可以很方便的与其他形式的特征向量进行联合。
应用场景:
目标的自身状态、场景所处的环境和成像器材的成像特性等因素影响图像配准/目标识别跟踪的性能。而SIFT算法在一定程度上可解决:
1. 目标的旋转、缩放、平移(RST)
2. 图像仿射/投影变换(视点viewpoint)
3. 光照影响(illumination)
4. 目标遮挡(occlusion)
5. 杂物场景(clutter)
6. 噪声
二、SIFT算法实现步骤
2.1 构建尺度空间
要实现图像匹配,我们想在构成图像的所有点中通过某种方法选取出一些具有代表性的点,重要的是这些特殊点在图像经过伸缩、旋转、叠加噪声和其他一些变化后仍能被提取出来——即具有不变性,这样我们就可以利用这些具有不变性的特殊点来进行图像的匹配。Lowe提出了一种寻找特殊点的方法,用这种方法找到的点对于图像的尺度变化具有不变性。
最早的图像匹配使用的是角点检测(corner detector)。应该说,图像中物体的边缘是一个比较好的特征。比较常用的边缘检测方法有一阶导数边缘检测、二阶导数边缘检测。拉普拉斯边缘检测就属于二阶导数边缘检测。拉普拉斯算子为
Marr和Hildrith提出了高斯拉普拉斯边缘检测算子(LOG算子,表示为 ),在拉普拉斯操作之前先进行高斯平滑操作,以抑制高频噪声。高斯函数表示为G(x,y,σ),与原始图像做卷积后,相当于对图像进行了低通滤波,且σ越大,则滤波器截止频率越低,图像也因失去更多的高频信息而更模糊。Lindeberg又提出将上述结果乘以系数后可获得尺度不变性,即尺度归一化的高斯拉普拉斯算子。
首先是用高斯差分(DOG)来近似。Lowe说可以参考热扩散方程得到,这个公式应该比较关键,但我尚不清楚为何
左边的高斯偏导数可以用差分来近似:
其中k趋近于1就可以取等号了。所以:
从中可以看出,高斯差分与尺度归一化的高斯拉普拉斯算子仅相差一个比例因子(k-1)。如果我们取k为定值,则在高斯差分中找到的极值点位置大致相当于在中的位置。
高斯金字塔有多组,每组又有多层。一组中的多个层之间的尺度是不一样的(也就是使用的高斯参数σσ是不同的),相邻两层之间的尺度相差一个比例因子k。如果每组有S层,则。上一组图像的最底层图像是由下一组中尺度为2σ的图像进行因子为2的降采样得到的(高斯金字塔先从底层建立)。高斯金字塔构建完成后,将相邻的高斯金字塔相减就得到了DoG金字塔。
高斯金字塔的组数一般是:
o表示高斯金字塔的层数,m,n分别是图像的行和列。减去的系数a可以在0−之间的任意值,和具体需要的金字塔的顶层图像的大小有关。
高斯模糊参数σ(尺度空间),可由下面关系式得到:
其中i为所在的组,S为所在的组的层数。
下一个减少计算量的方法是分组(Octave),即通过缩小图片尺寸来减少卷积计算。
图1:分组高斯差分
2.2 DOG极值点检测
关键点是由DOG空间的局部极值点组成的,关键点的初步探查是通过同一组内各DoG相邻两层图像之间比较完成的。为了寻找DoG函数的极值点,每一个像素点要和它所有的相邻共26个点比较,看其是否比它的图像域和尺度域的相邻点大或者小。 如果令中的σ不断变大(为了计算机实现,只能取离散的σ值,对应于图1的Scale),就可以得到很多输出图像,这样局部极值点的寻找就扩展至三维空间(x,y,σ)。正如图2所示,每个像素点X需要与上下及周围共26个邻近点O比较来确定局部最大最小极值。
图2:极值点检测
图3 不同尺度不同层级检测示意图
假设s=3,也就是每个塔里有3层,则,那么按照上图可得Gauss Space和DoG space 分别有3个(s)和2个(s-1)分量,在DoG space中,1st-octave两项分别是σ,kσ; 2nd-octave两项分别是2σ,2kσ;由于无法比较极值,我们必须在高斯空间继续添加高斯模糊项,使得形成σ,kσ,σ,σ,σ这样就可以选择DoG space中的中间三项kσ,σ,σ(只有左右都有才能有极值),那么下一octave中(由上一层降采样获得)所得三项即为2kσ,2σ,2σ,其首项2kσ=。刚好与上一octave末项σ=尺度变化连续起来,所以每次要在Gaussian space添加3项,每组(塔)共S+3层图像,相应的DoG金字塔有S+2层图像。
2.3 关键点定位
离散空间的极值点并不是真正的极值点,图4显示了二维函数离散空间得到的极值点与连续空间极值点的差别。利用已知的离散空间点插值得到的连续空间极值点的方法叫做子像素插值(Sub-pixel Interpolation)。
图4 离散空间与连续空间的极值点差异
为了提高关键点的稳定性,需要对尺度空间DoG函数进行曲线拟合。利用DoG函数在尺度空间的Taylor展开式(拟合函数)为:
其中,求导并让方程等于零,可以得到极值点的偏移量为:
对应极值点,方程的值为:
其中,代表相对插值中心的偏移量,当它在任一维度上的偏移量大于0.5时(即x或y或),意味着插值中心已经偏移到它的邻近点上,所以必须改变当前关键点的位置。同时在新的位置上反复插值直到收敛;也有可能超出所设定的迭代次数或者超出图像边界的范围,此时这样的点应该删除,在Lowe中进行了5次迭代。另外,过小的点易受噪声的干扰而变得不稳定,所以将小于某个经验值(Lowe论文中使用0.03,Rob Hess等人实现时使用0.04/S)的极值点删除。同时,在此过程中获取特征点的精确位置(原位置加上拟合的偏移量)以及尺度。
2.4 消除边缘影响
一个定义不好的高斯差分算子的极值在横跨边缘的地方有较大的主曲率,而在垂直边缘的方向有较小的主曲率。
DOG算子会产生较强的边缘响应,需要剔除不稳定的边缘响应点。获取特征点处的Hessian矩阵,主曲率通过一个2x2 的Hessian矩阵H求出:
H的特征值α和β代表x和y方向的梯度,
表示矩阵H对角线元素之和,表示矩阵H的行列式。假设是α较大的特征值,而是β较小的特征值,令,则
D的主曲率和H的特征值成正比,令为α最大特征值,β为最小的特征值,则公式的值在两个特征值相等时最小,随着的增大而增大。值越大,说明两个特征值的比值越大,即在某一个方向的梯度值越大,而在另一个方向的梯度值越小,而边缘恰恰就是这种情况。所以为了剔除边缘响应点,需要让该比值小于一定的阈值,因此,为了检测主曲率是否在某域值r下,只需检测如下:
上式成立时将关键点保留,反之剔除。
2.5 寻找关键点的主方向
经过上面的步骤已经找到了在不同尺度下都存在的特征点,为了实现图像旋转不变性,需要给特征点的方向进行赋值。利用特征点邻域像素的梯度分布特性来确定其方向参数,再利用图像的梯度直方图求取关键点局部结构的稳定方向找到了特征点,也就可以得到该特征点的尺度σ,也就可以得到特征点所在的尺度图像:
计算以特征点为中心、以3×1.5σ为半径的区域图像的幅角和幅值,每个点L(x,y)的梯度的模m(x,y)以及方向θ(x,y)可通过下面公司求得:
计算得到梯度方向后,就要使用直方图统计特征点邻域内像素对应的梯度方向和幅值。梯度方向的直方图的横轴是梯度方向的角度(梯度方向的范围是0到360度,直方图每36度一个柱共10个柱,或者没45度一个柱共8个柱),纵轴是梯度方向对应梯度幅值的累加,在直方图的峰值就是特征点的主方向。在Lowe的论文还提到了使用高斯函数对直方图进行平滑以增强特征点近的邻域点对关键点方向的作用,并减少突变的影响。为了得到更精确的方向,通常还可以对离散的梯度直方图进行插值拟合。具体而言,关键点的方向可以由和主峰值最近的三个柱值通过抛物线插值得到。在梯度直方图中,当存在一个相当于主峰值80%能量的柱值时,则可以将这个方向认为是该特征点辅助方向。所以,一个特征点可能检测到多个方向(也可以理解为,一个特征点可能产生多个坐标、尺度相同,但是方向不同的特征点)。Lowe在论文中指出
15%的关键点具有多方向,而且这些点对匹配的稳定性很关键。
得到特征点的主方向后,对于每个特征点可以得到三个信息(x,y,σ,θ)(x,y,σ,θ),即位置、尺度和方向。由此可以确定一个SIFT特征区域,一个SIFT特征区域由三个值表示,中心表示特征点位置,半径表示关键点的尺度,箭头表示主方向。具有多个方向的关键点可以被复制成多份,然后将方向值分别赋给复制后的特征点,一个特征点就产生了多个坐标、尺度相等,但是方向不同的特征点。
2.6 生成特征描述
通过以上的步骤已经找到了SIFT特征点位置、尺度和方向信息,下面就需要使用一组向量来描述关键点也就是生成特征点描述子,这个描述符不只包含特征点,也含有特征点周围对其有贡献的像素点。描述子应具有较高的独立性,以保证匹配率。
特征描述符的生成大致有三个步骤:
- 校正旋转主方向,确保旋转不变性。
- 生成描述子,最终形成一个128维的特征向量
- 归一化处理,将特征向量长度进行归一化处理,进一步去除光照的影响。
为了保证特征矢量的旋转不变性,要以特征点为中心,在附近邻域内将坐标轴旋转θ(特征点的主方向)角度,即将坐标轴旋转为特征点的主方向。旋转后邻域内像素的新坐标为:
旋转后以主方向为中心取 8×8的窗口。下图所示,左图的中央为当前关键点的位置,每个小格代表为关键点邻域所在尺度空间的一个像素,求取每个像素的梯度幅值与梯度方向,箭头方向代表该像素的梯度方向,长度代表梯度幅值,然后利用高斯窗口对其进行加权运算。最后在每个4×4的小块上绘制8个方向的梯度直方图,计算每个梯度方向的累加值,即可形成一个种子点,如右图所示。每个特征点由4个种子点组成,每个种子点有8个方向的向量信息。这种邻域方向性信息联合增强了算法的抗噪声能力,同时对于含有定位误差的特征匹配也提供了比较理性的容错性。
与求主方向不同,此时每个种子区域的梯度直方图在0-360之间划分为8个方向区间,每个区间为45度,即每个种子点有8个方向的梯度强度信息。在实际的计算过程中,为了增强匹配的稳健性,Lowe建议对每个关键点使用4×44×4共16个种子点来描述,这样一个关键点就可以产生128维的SIFT特征向量。
通过对特征点周围的像素进行分块,计算块内梯度直方图,生成具有独特性的向量,这个向量是该区域图像信息的一种抽象,具有唯一性。
参考文献
1、sift算法详解及应用(课件)。(本文档简明扼要的简述了SIFT算法和图像匹配以及匹配修正。图文并茂,一览全貌)
http://wenku.baidu.com/view/87270d2c2af90242a895e52e.html?re=view
2、SIFT算法详解(sift操作过程理论通俗,尤其是高阶泰勒展开式及高阶导数分析的很好,对理解亚像素定位拟合中的图像具体编程操作很有用)
http://blog.csdn.net/zddblog/article/details/7521424
3、SIFT特征分析与源码解读(1模拟金字塔的过程解释的很详细,带有动画模拟;2 在寻找特征点进行亚像素定位拟合中的图像很形象)
http://blog.csdn.net/xw20084898/article/details/16832755
4、【OpenCV】SIFT原理与源码分析:关键点描述(对关键点描述子区域的取舍讲解的很详细)
http://blog.csdn.net/xiaowei_cqu/article/details/8113565
5、【OpenCV】SIFT原理与源码分析(对sift 算法采用分部分叙述且带有源码分析说明)
http://blog.csdn.net/xiaowei_cqu/article/details/8069548
6、opencv2.4.9sift源码分析(1赵春江的这篇文章是我目前看到分析sift算法比较全面的;2尤其给出了使用三维直方图来分析三线性插值,对理解描述子的生成作用很大;3 给出了源码分析和演示结果)
http://wenku.baidu.com/view/d7edd2464b73f242336c5ffa.html
http://download.csdn.net/detail/zhaocj/8294793
7、九之再续:教你一步一步用c语言实现sift算法、下
(1算法中寻找主方向使用的抛物线插值拟合方法;2 描述子三次插值)
http://blog.csdn.net/v_JULY_v/article/details/6246213
8、RobHess的SIFT源码分析:综述(各个子程序详解及分析很细致,一概全貌)
http://blog.csdn.net/masibuaa/article/details/9191309
9、特征点检测学习_1(sift算法)(1这篇文章没有太多理论分析,但结合QT和OpenCV做出了生动的sift算法匹配演示,有图很直观生动呀,用程序配图一目了然;2 简述对robhess 的c版本sift代码在c++中的使用注意问题 )
http://www.cnblogs.com/tornadomeet/archive/2012/08/16/2643168.html
10、OpenCV 中c版本sift源代码网址
http://blogs.oregonstate.edu/hess/code/sift/
11、【特征匹配】SIFT原理与C源码剖析(这个也不错,图文并茂,还带有 源码分析,总体来说是以程序带动问题分析)
http://blog.csdn.net/luoshixian099/article/details/47377611
12、插值与拟合(对多项式及其插值讲解还不错)
http://wenku.baidu.com/link?url=wWcqLrpokQrjZZKzFbuJ4QDbZXZkMByCu-KaVKrSyGD6fh9Bpk1kZOPitpkFpNBw_no8UoyWY2DGQg9I7aL_tO3oi7z5mUK7cN8Sca6dX-O
13、线性插值与抛物线插值(对这两种插值讲解的很详细,是目前发现最 好的一版
http://www.docin.com/p-711275966.html
14、奇异值分解(对奇异值怎么来的讲解比较细致)
http://blog.sina.com.cn/s/blog_53eb0fdf0101sfu1.html
15,SIFT特征点提取 (重点参考)
16、https://zhuanlan.zhihu.com/p/36382429 (重点)
这篇关于特征提取与检测(二) --- SIFT算法的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!