SIFT算法的全称是Scale-invariant feature transform,尺度不变特征转换,是一种不随图像尺度旋转变化而变化的特征,因此SIFT特征不会随着图像的放大缩小,或者旋转而改变,同时由于在提取特征时做的一些特殊处理,使得SIFT特征对于光照变化也有比较强的适应性。以下是算法流程:
1 构建尺度空间
将原始图像执行多次上下采样得到多幅尺度不同的图像如图1所示,每幅图像的内容相同但是长宽均为上一尺度的一半。将这些图片按照由大到小的顺序自底向上叠在一起形成一种类似金字塔的结构。Tips:金字塔的层数可以根据实际情况自定,由于上采样会加大内存的消耗和计算量,因此对于较大的图片通常不要做上采样处理。
对每个尺度空间的图片执行5次高斯变换(这里的层数可以自定),将其变成6层(从-1到4),-1层为该尺度空间的原始图像,按照公式1计算每个尺度空间中的图像的高斯变换参数。
公式1中 σ0 为1.6(这应该是一个经验值),o为当前的尺度,s为图像在当前尺度中的层,S为每个尺度空间的层数。假设在处理每一个尺度空间时,输入的图像都是经过高斯平滑处理过的,其值 σn=0.5 。在David G. Lowe的论文中,由于金字塔最底部的尺度是通过插值(上采样)得到的,因此对于这一层的处理 σn=1.0 。因此在经过调整之后,实际得到的 σ(o,s) 如公式2所示。
通过上述计算我们可以得到图2所示的尺度空间中的多层图像。
到这一步,基本上算是建立起了尺度空间,SIFT算法之所以对图像的尺度变化具有不变性,原因也就在于这个尺度空间,但是尺度空间也并非万能的,因为在SIFT算法的执行过程中,建立起来的尺度空间范围有限,只能包含大部分图像的尺度,但是对于那些尺度远超过范围的的图像特征,SIFT也不能够保证其尺度不变性。
2 寻找极值点
2002年Mikolajczyk在详细的实验比较中发现尺度归一化的高斯拉普拉斯函数的极值同其他方法相比能够产生最稳定的图像特征,而高斯差分函数与尺度归一化的高斯拉普拉斯函数十分接近。在上一步中已经对所有图片执行了高斯变换,在这里只需要对同尺度内相邻的两幅高斯图片求差,就可以得到差分高斯图片,为了更加形象的表述,将差分操作按照图3来表示:
对每一个尺度空间执行相同的操作,最后可以得到一个与之前的高斯金字塔类似的差分高斯金字塔。在得到了差分高斯金字塔之后,就可以搜索极值点,搜索极值点的方式很简单,将每一个尺度空间中的高斯差分图像堆叠到一起形成一个三维的数据集合,不算边缘的像素点,每个像素点都会有26个像素与之相邻,若该像素点在这一共27点中最大或者最小就记录该点的信息将其作为极值点,计算步骤可以用图4的形式来描述,若黑点在所有灰点中像素值最大或者最小,则将黑点暂定为极值点。
3 筛选极值点
3.1 删除偏移较大和响应值较小的极值点
通过比较27个像素点得到的极值点并非真正意义上的极值点,这些点是在离散的空间中选取的。但是真正的极值点可能并不是选取出来的这些,图5描述了在二维的空间中离散极值点和连续极值点之间的关系。
由于现在处理的是一个三维的离散数据集合,需要对其求二阶Taylor展开,并令展开式倒数为0,得到公式3。
因为处于一个三维的数据集合中, (x,y,s) 是三维矢量。当倒数为0时,如果插值得到的中心 (x,y,s) 与之前的离散中心的偏移在某个分量上超过0.5,说明插值中心已经偏移到了它邻近的中心点上,这样的点要删除,同时如果 |D(x)|<0.03 时,说明这样的点响应较低,不稳定也要删除。
3.2 删除边缘效应点
由于差分高斯取出的极值点在图像的边缘处往往会有比较大的响应,这些点很容易受到噪声的干扰而变得不稳定,通过步骤3.1得到的点存在着许多干扰需要进一步筛选,因此还要使用Hessian矩阵删除边缘点。使用Hessian矩阵来检测我们之前找到的极值点的原理是,虽然高斯差分响应在横跨边缘的地方会有很大的主曲率,但是在垂直边缘的方向的主曲率却较小,由于Hessian矩阵的特征值和差分高斯方程的主曲率成正比,所以可以通过Hessian矩阵来求解主曲率。Hessian矩阵的表示如公式4所示。
在计算过程中可以不求Hessian矩阵的特征值,因为这里只关注特征值的比例,对于边缘点来说由于在两个方向上的主曲率差别较大,因此也会有较大的比值。令 α=λmax , β=λmin ,有公式5、6所示的结果。
因此令 γ 为 α/β ,可以用公式7来计算:
当两个方向的主曲率相同时 Tr(H)2/Det(H) 最小,随着主曲率大小的差距的变大,( Tr(H)2/Det(H) 会逐渐变大。在Lowe的论文中,选择的 γ 的阈值为10。当对所有的极值点进行筛选之后,检测通过的这些点就是最终的关键点。
4 计算特征点的主方向
这一步将会依次处理每个特征点提取其主方向。提取主方向的目的主要在于实现图像的旋转不变性。由于知道了每个特征点所在的尺度空间,很容易就可以得到这一尺度所在的高斯图像,使用 L(x,y) 表示尺度为 σ 的高斯图像。在高斯图像上,以特征点为中心,对半径为 3×1.5σ 的区域求取图像的梯度和幅值,计算公式如公式8、9所示:
在计算时将梯度方向的0~360度的范围分成36份执行计算,得到一个包含36个柱的直方图,为了便于显示图6只显示了其中的8个柱:
主方向不一定只有一个,在选择主方向时,只要幅值达到了最高值的80%,并且大于与之相邻的两个方向的幅值就可以将其确定为主方向。Tips:对于一些比较大的图像会提取出数以千计的特征,这些特征包含的区域会有很多覆盖,因此,在计算主方向之前,可以提取出所有的尺度的所有高斯图像的每个像素点的梯度,这样可以大大地降低运算量,不过这么做的缺点是会占用更多的内存。
5 将特征点变成一个128维的向量
这一步将会把所有的特征点的各个主方向转换成一个128维的向量,已经知道了所有特征点的坐标以及当前的尺度空间和当前高斯变换的参数 σ ,选定与特征点相邻的 Bp×Bp 个子区域,每个子区域的尺寸为 mσ ,取 m=3 、 Bp=4 (应该也是经验值),考虑到使用双线性插值和旋转,计算时的选取的区域为 (mσ(Bp+1)2√)2 。与求取特征点的主方向类似,求每个子区域里的方向,不过这一次将360度范围划分成了8组,每组的中心间隔是45度。在求解时需要注意,由于是针对主方向来求解,还要将角度旋转到主方向上去,以增强算子的旋转不变性。采用高斯加权的方式给不同位置的子区域设置权值。最终会得到一个类似图7的矢量集合,刚好是 4×4×8=128 维的向量。
在计算后还需要对得到的向量进行归一化处理,在归一化处理后对于值大于0.2的分量进行截断(大于0.2的值,取0.2),这么做的目的是为防止光照的影响。在截断之后还要再做一次归一化,最后为了方便储存和计算,将浮点型的分量转换成0~255之间的一个8位的无符号类型变量来保存。最终可以得到图8所示的实验结果。
图片来源: Oxford Building 5k Database
参考文章:
[1] David G. Lowe. Object recognition from local scale-invariant features. Computer vision, September 1999, vol.2, pp. 1050-1157
[2] David G. Lowe. Distinctive Image Features from Scale-Invariant Keypoints. International Journal of Computer Vision, November 2004, Volume 60 Issue 2, pp. 91-110
from: http://www.duzhongxiang.com/sift_algorithm/