[关闭]
@lutingting 2016-11-04T16:15:11.000000Z 字数 10899 阅读 9303

SIFT特征提取及匹配

数字图像处理 图像特征提取


1.SIFT(Scale-invariant feature transform)算子的核心思想

由于SIFT特征的检测方式,使得它具有:

2.什么是尺度空间呢?

2.1 一篇百度文库的文章关于尺度空间的分析

具体内容参考文献4

通常会听到尺度变化等这类词语,看到的也总是一堆的数学公式,有时候真的不知道这到底有啥用,有啥意义,没有弄懂这些意义,当然就更不可能理解,不可能去掌握、应用它了,现在我才理解,小波变化其实也是一种尺度变化。今天我看到一篇南航数学系写的关于尺度空间解释的文章,感觉很通俗易懂,我们不从数学上来推导什么是尺度空间,只是从生活常识方面来解释尺度空间的意义,意义懂了,数学方面自然就好理解了。

例子1

首先我们提出一个问题,请看下面的图片,让我们人为的进行判断:下面所显示的左右图片中哪个的角尖锐?
image_1b0klk03k7tq1eqtfou11jgtbs9.png-200.8kB

此例子的结果阐述了“尺度”对于解决视觉问题的重要性,即一个视觉问题的答案往往会依赖于其所在的尺度。在生活中这样的例子也比比皆是,比如要观察一棵树,所选择的尺度应该是“米”级;如果观察树上的树叶,所选择的尺度则应该是“厘米”级。一般来说,摄像设备所能呈现的画面分辨率是固定的。要以同样的分辨率分别观察树和树叶,我们需要调整摄像设备的摄像位置。因此,视觉问题中的“尺度”概念也可以被形象地理解为摄像设备与被观察物体之间的距离:较远的距离对应较大的尺度,较近的距离对应较小的尺度。

例子2

接下来我们看看第二个例子吧,看看图二中显示的图片那些是角点?
image_1b0klkria1pfs53v1hun1t3j1cj3m.png-162.3kB

同例1 一样,本例中问题的答案依赖于问题所在的尺度:当我们非常靠近雪花形状观察它时(即在较小的尺度下),能够看清楚所有的细节,却不容易感知其整体轮廓,从而倾向于不加区分地选取图2(b)中所标记的192 个点作为角点。反过来,当我们从一个很远的距离观察雪花形状时(即在较大的尺度下),虽然轮廓的细节已经模糊不清,但却能够一眼看出其整体结构,从而倾向于选取图2(d) 中所标记的12 个点作为角点。此外,图2(c) 中所标记的角点对于理解雪花形状也很有帮助。事实上,如果我们不是保守地将自己固定在某个尺度下来观察物体,便能够获得充足的视觉信息。比如说图2(b)-2(d) 所呈现的三组角点已经很好地向我们展示了雪花形状的三个结构层次。这一效果是其中的任意一组角点都无法实现的。

现实生活中的例子

现实生活中视觉问题的复杂性也往往需要我们做到这一点:当我们去参观某处文化遗迹时,远远地就已经开始观察建筑物的外形,然后较近距离时开始注意到门窗、台阶、梁柱的建筑风格,最后会凑上前去细看门窗上的图案、石碑上的碑文等。当一部机器人也能够自主地做到这一点时,说明它已经具备了更高的人工智能。我们对尺度空间技术的研究也正是朝着这个方向努力。概括地说,“尺度空间”的概念就是在多个尺度下观察目标,然后加以综合的分析和理解。 这里用的是图像来解释尺度,当然,对于抽象的信号,理解还是一样的,不过到时候我们看的工具不是我们人眼或者是摄像机从外表区分了,这时候我们用的工具也可能是时域的分析法,也可能是频率域的傅里叶变化等分析法,它是我们进一步发现我们感兴趣事物的工具。

2.2 SIFT中的尺度空间的概念

3.SIFT特征提取

一幅图像的SIFT特征提取,分为4个步骤:

下面分别是这四部分的详细内容

3.1 尺度空间极值检测

SIFT特征点其实就是尺度空间中稳定的点/极值点,那么,为了得到这些稳定点:

3.1.1 尺度空间的建立(高斯金字塔的建立)

对于一幅输入图像,为了进行sift特征检测、实现scale-invariant(任何尺度下都能够有对应的特征点),需要对该图像的尺度空间进行分析,即建立高斯金字塔图像、得到不同scale的图像,这里的高斯金字塔与最原始的高斯金字塔稍微有点区别,因为它在构造尺度空间时,将这些不同尺度图像分为了多个Octave、每个Octave又分为了多层。下图左侧框内给出了Sift中的高斯金字塔的结构图;
image_1b0klmhj016gr9jl1blb83s3am13.png-561.5kB

注1:关于尺度变化的连续性应该就是指:金字塔图像中所有图像之间的尺度因子都相差一个k倍:每个octave中相邻图像之间尺度因子相差一个k,相邻2个octave的最后一层与第一层的图像之间尺度因子相差一个k!
注2:英文Octave是音乐上一个八度的意思,在这里指的是一组图像。这一组图像的分辨率是相同的,但是采用了不同尺度的高斯函数进行滤波,因此从模糊程度上看(或者说从关注的尺度上看)是有区别的。而不同组的图像具有不同的分辨率,在尺度上的差别就更大。


为什么已经使用了不同尺度的高斯函数进行滤波还需要引入高斯金字塔呢?
这是因为SIFT算法希望能具有更高的尺度分辨率(也就是希望相邻尺度的变化比较精细),所以就需要有很多层。如果不用高斯金字塔,都在原始分辨率上靠采用不同的高斯函数实现多尺度检测,那么对于比较粗尺度的特征提取在计算量上就相当浪费。因为在保持图像原始分辨率不变的情况下,提取粗尺度特征需要高斯函数的方差较大,相应的滤波窗口也比较大,计算量会激增,而由于图像在大尺度上的模糊,保持原始分辨率已经没有必要了,这种计算消耗就更是得不偿失。所以采用高斯金字塔是为了高效地提取不同尺度的特征。

不同octave之间的尺度差异靠高斯金字塔在分辨率上的区别实现,同一个octave内部不同层之间的尺度差异靠高斯函数的方差变化来实现。另外SIFT在DOG问题上并不是使用DOG函数直接滤波,而是用相邻两层的高斯滤波结果相减得到的,为什么要这样呢?
也是为了节省计算量。因为如果直接采用DOG函数,为了提取不同的尺度,就必须逐渐扩大DOG函数的窗口,这会引起计算量的增加。在实际操作中,SIFT首先对当前octave对应的分辨率的采样图像用一个窗口相对较小的高斯函数滤波,之后同一个octave的第2层一直到第k层,都是通过对前一层已经滤波过的结果再进行一次高斯滤波。对一副原始图像用方差为的高斯函数连续做两次滤波的结果,相当于对这幅图像直接用一个的高斯函数做一次滤波。所以每次都在前一层的滤波结果基础上进行滤波,跟对原始图像分别用不同窗口大小的高斯函数滤波的结果是一样的,但是因为避免了滤波函数窗口的扩大,可以有效减少计算量。

不同对应的高斯核函数到底有什么作用呢?下面做个小实验,可以发现,不同高斯核尺度会对图像产生不同的平滑效果,尺度因子越大(高斯函数方差越大),对图像的平滑程度越大;

  1. %读入图像并将其转换成灰度图像
  2. I=imread('qingdao.jpg');
  3. I=rgb2gray(I);
  4. % 利用尺度为3*3的高斯核进行滤波
  5. w1=fspecial('gaussian',3,0.5);
  6. g1=imfilter(I,w1,'conv','symmetric','same');
  7. % 利用尺度为11*11的高斯核进行滤波
  8. w2=fspecial('gaussian',11,0.5);
  9. g2=imfilter(I,w2,'conv','symmetric','same');
  10. % 显示处理结果
  11. figure;subplot(1,3,1);imshow(I);title('原始图像');
  12. subplot(1,3,2);imshow(g1);title('3*3高斯');
  13. subplot(1,3,3);imshow(g2);title('11*1高斯');

得到了图像的尺度空间后,需要在尺度中间内检测稳定特征点,从而需要比较不同尺度图像之间的差别,实现极值点的检测,实际上,Laplacian of Gaussian和Difference of Gaussian都能够实现这样的目的,但LoG需要大量的计算,而DoG的计算相对简单,并且DoG是对LoG的一个很好的今昔

3.1.2 图像差分高斯金字塔(DoG)的建立

对于高斯金字塔中的每一个塔的不同层,可以计算得到相邻层之间的差值,从而可以得到差分高斯,对高斯金字塔中每一个塔都进行同样的操作,从而得到差分高斯金字塔,如下图右侧所示,即显示了由左侧的高斯金字塔构造得到的差分高斯金字塔,该差分高斯金字塔包含2个塔,每个塔都有四层
image_1b0kloibp113e21r1ju9g5012o34.png-249.9kB

差分高斯表征了相邻尺度的高斯图像之前的差别,大值表示区别大,小值表示区别小,后续的特征点检测都是差分高斯图像金字塔中进行的!

3.1.3 尺度空间中特征点的检测(DoG中极值点的检测)

构造完尺度空间(差分高斯金字塔)后,接下来的任务就是“在尺度中间中检测出图像中的稳定特征点”:

对于DoG中每一个采样点(每一个Octave中每一层),将其与它邻域内所有像素点(8+18=26)进行比较,判断其是否为局部极值点(极大或者极小),更加具体地:如下图所示,中间的检测点和它同尺度的8个相邻点和上下相邻尺度对应的9×2个点共26个点比较,以确保在尺度空间和二维图像空间都检测到极值点。 一个点如果在DOG尺度空间本层以及上下两层的26个领域中是最大或最小值时,就认为该点是图像在该尺度下的一个特征点。但要注意:这种相邻层之间的极值点的寻找是在同一Octave中的相邻尺度之间进行寻找的,而不要跨组!
image_1b0klp3ope2gr4m1evh2urbef3h.png-46.6kB

同时,应该注意到一个问题,在极值比较的过程中,每一Octave图像的首末两层是无法进行极值比较的,为了满足尺度变化的连续性,需要进行一些修正:在高斯金字塔中生成S+3层图像,具体解释如下:假设s=3,也就是每个塔里有3层,则k=21/s=21/3:

3.2 关键点位置及尺度确定

通过拟和“三维二次函数”可以精确确定关键点的位置和尺度(达到亚像素精度),具体方法还未知,可以得到一系列的SIFT候选特征点集合,但由于这些关键点中有些具有较低的对比对,有些输属于不稳定的边缘响应点(因为DoG算子会产生较强的边缘响应),所以,为了增强匹配稳定性、提高抗噪声能力,应该将这2类关键点去除,实现对候选SIFT特征点集合的进一步净化:

3.3 关键点方向确定

至此,得到了图像中所有关键点的方向!实际上,关键点方向的确定是为了接下来的特征向量生成中的坐标旋转使用的!

3.4 特征向量生成

上面只是得到了每个关键点的方向,接下来,需要确定每个关键点的特征向量,具体方式如下:

至此,关键点特征向量完全确定!此时SIFT特征向量已经去除了尺度变化、旋转等几何变形因素的影响,再继续将特征向量的长度归一化,则可以进一步去除光照变化的影响。
image_1b0klud1uv091h771pr09uo1d758d.png-24.1kB

4.SIFT特征的匹配

现有A、B两幅图像,分别利用上面的方法从各幅图像中提取到了k1个sift特征点和k2个特征点及其对应的特征描述子,即维和维的特征,现在需要将两图中各个scale(所有scale)的描述子进行匹配。

接下来采用关键点特征向量的欧式距离来作为两幅图像中关键点的相似性判定度量。


Reference
1. SIFT keypoint detector实现代码:http://www.cs.ubc.ca/~lowe/keypoints/
2. David Lowe个人主页:http://www.cs.ubc.ca/~lowe/home.html
3. David Lowe关于SIFT的论文2004《Distinctive Image Features
from Scale-Invariant Keypoints》pdf版本:http://www.cs.ubc.ca/~lowe/papers/ijcv04.pdf
4. http://wenku.baidu.com/link?url=rsMoC8dnNclI54HCm1YDvANsj5h1dsUxGnjVCY5KOsXxdSt0XKP3ix5pgH5W41bJ9RKSn7gsZTtXIur3r8ULfTANuF2o5mCpM2kMP_MI0Pm
5. Rachel-Zhang博客-SIFT特征提取分析. http://blog.csdn.net/abcjennifer/article/details/7639681
6. http://www.zhihu.com/question/19911080
7. http://blog.csdn.net/songzitea/article/details/16986423


5.下面是一些参考程序

5.1

  1. %size为模板大小
  2. %sigma为标准差
  3. size = 3;
  4. sigma =3 ;
  5. %下面的代码其实是从fspecial中摘录出来的,我做了一些更改放到自己写的函数里面便于解释
  6. %计算高斯模板的中心位置
  7. siz = ([size size]-1)/2;
  8. sig = sigma;
  9. %用meshgrid是为了加速,不用for循环
  10. [x y] = meshgrid(-siz(2):siz(2),-siz(1):siz(1));
  11. %计算exp(-(x^2+y^2)/(2*sig^2))
  12. %我想你肯定有一个疑问,那就是为什么不除以2*pi*sig^2
  13. %因为不除也没有关系,因为最后归一化之后会约掉
  14. arg = -(x.*x+y.*y)./(2*sig*sig);
  15. h = exp(arg);
  16. %不知道它为什么要这样,忘懂得人解释一下
  17. h(h<eps*max(h(:))) = 0;
  18. %求和,用来归一化
  19. sumh = sum(h(:));
  20. %防止求和之后出现为0的情况,然后再归一化一下使高斯,模板为小数
  21. if sumh ~=0
  22. h=h/sumh;
  23. end
  24. %% 绘制二维高斯曲面
  25. u=[-10:0.1:10];
  26. v=[-10:0.1:10];
  27. [U,V]=meshgrid(u,v);
  28. H=1/2/pi/sigma*exp(-(U.^2+V.^2)./2/sigma^2);
  29. mesh(u,v,H); %绘制三维曲面的函数
  30. title('高斯函数曲面');
  31. %% 利用fspecial产生高斯核
  32. hold on;
  33. for i=1:3
  34. for j=1:3
  35. plot3(i-2,j-2,h(j,i),'r*');
  36. end
  37. end

5.2

  1. clear;clc;close all
  2. %% 输入图像,并归一化到统一的尺寸
  3. row=256;colum=256;
  4. img=imread('lenna.png');
  5. img=imresize(img,[row,colum]);
  6. img=rgb2gray(img);
  7. img=im2double(img);
  8. origin=img;
  9. %% 下面分别利用不同的sigma值对输入图像进行卷积操作
  10. sigma0 = sqrt(2);
  11. level = 3;
  12. for i=1:level
  13. scale=sigma0*sqrt(2)^(1/level)^((i-1)*level+i);
  14. f=fspecial('gaussian',[1,floor(6*scale)],scale);
  15. image_output=conv2(origin,f','same');
  16. figure;imshow(image_output);hold on;
  17. title(['scale = ',num2str(scale),',and size of kernel is ',num2str(size(f,1)),'*',num2str(size(f,2))]);
  18. end
  19. %% 绘制二维高斯曲面
  20. sigma = 3;
  21. u=[-10:0.1:10];
  22. v=[-10:0.1:10];
  23. [U,V]=meshgrid(u,v);
  24. H=1/2/pi/sigma*exp(-(U.^2+V.^2)./2/sigma^2);
  25. mesh(u,v,H); %绘制三维曲面的函数
  26. title('高斯函数曲面');
  27. %% 利用fspecial产生高斯核
  28. f=fspecial('gaussian',[3,3],sigma);
  29. hold on;
  30. for i=1:3
  31. for j=1:3
  32. plot3(i,j,f(j,i),'r*');
  33. end
  34. end
添加新批注
在作者公开此批注前,只有你和作者可见。
回复批注