您的位置:首页 > 其它

欢迎使用CSDN-markdown编辑器

2016-11-17 11:12 302 查看

SIFT之高斯金字塔

高斯金字塔(Gaussian Pyramid):高斯金字塔里有两个概念:组(Octave)和层(Level或Interval),每组里有若干层。

高斯金字塔的构造是这样的:

(1)第一组的第一层为原图像,然后将图像做一次高斯平滑(高斯卷积、高斯模糊)高斯平滑里有一个参数σ,在SIFT里作者取1.6;

(2)将σ乘一个比例系数k作为新的平滑因子来平滑第一组第二层得到第三层。

(3)重复若干次,得到L层他们分别对应的平滑参数为:0,σ,kσ,k2σ….。

(4)将最后一幅图像做比例因子为2的降采样得到第二组的第一层,然后对第二组的第一层做参数是σ的高斯平滑,对第二层做kσ的平滑得到第三层…..这里一定注意:每组对应的平滑因子是一样的。而不是像有的资料上说的持续递增。

这样反复形成了O组L层。一般模糊的高斯模板长宽都约为6σ(这里σ为当次的平滑因子,就是可能是kσ,k2σ..)

DoG(Difference of Gaussian)金字塔:他是由高斯金字塔构造出来的,他的第一组第一层是由高斯金字塔的第一组第二层减第一组第一层,他的第一组第二层是由高斯金字塔的第一组第三层减第一组第二层得到,(说的这么繁琐是为了大家能理解的直观点)。每组都这样就生成了DoG金字塔。顺便说一下,DoG金字塔每组图像几乎都是一片黑,但仔细看你能看出轮廓的。



1、在SIFT里高斯金字塔的第一组第一层通常是由一个原图像长宽扩大一倍开始的,这样做是为了可以得到更多的特征点。

2、大家可以发现如果用每组5层的高斯金字塔构造一个DoG金字塔的的话,DoG的每组的层数是4。

3、对于DoG金字塔,特征点的搜索从每组的二层到倒数第二层的(后面说明为什么),所以如果实际用n层那么DoG金字塔应该有n+2层,那么对应的高斯金字塔应该有n+3层。

4、這裡為了得到比較dense的sampling,因此又在每一層octave多切了好幾層,每一層基本上我們需要s+3張image,s+1張是從σ到2σ之間所產上的,另外因為在求extrema的時候為了要跟鄰居相比,所以我們還需要兩張是比σ小一點和比2σ再大一點的image。所以可以看成是Laplacian pyramid的extension。每一層在經過Gaussian filtering過後,把image相減就可以得到相當於是經由DoG filter所產生的image,之後就在這個space上面做運算。由于这样所以高斯金字塔从第二组开始的每组第一层是由上一组的倒数第二层降采样得到的。

什么是尺度

以上已经从人视觉感知的角度让大家感性认识了“尺度”,上文也提到使用高斯核来实现尺度的变换,那么具体实现过程中,尺度体现在哪里?是如何量化的呢?怎么在高斯金字塔中,两个变量很重要,即第几个八度(o)和八度中的第几层(s),这两个量合起来(o,s)就构成了高斯金字塔的尺度空间。尺度空间也不难理解,首先一个八度中图像的长和宽是相等的,即变量o控制的是塔中尺寸这个尺度;区分同一个尺寸尺度下的图像,就需要s了,s控制了一个八度中不同的模糊程度。这样(o,s)就能够确定高斯金字塔中的唯一一幅图像了,这是个三维空间,两维坐标,一维是图像。

根据lowe的论文,(o,s)作用于一幅图像是通过公式



确定的。通过公式也可以看出,尺度空间是连续的,两个变量控制着δ的值,其中在第一个八度中有 1<(o+s/S)<=2 ,同理在第二个八度中有2<(o+s/S)<=3,以此类推,δ中的关键部分(o+s/S)部分是逐渐增大的(具体实现时,有些高斯金字塔中这个值是增大,但不是逐渐均匀增大,只能说是连续的)。

第一个八度的中图像的尺度分别是δ,kδ,k^2δ……,第二个八度的尺度分别是2δ,2kδ,2k^2δ……..,同理第三个八度的尺度分别是4δ,4kδ,4k^2δ……..。这个序列是通过下式来确定的:



所以每增加一级八度,δ都要扩大2倍,在一个八度中,k的上标s来区分不同的高斯核。

至此,高斯金字塔中的尺度空间已经说得差不多了,包括尺度是什么,包括高斯金字塔中尺度的连续性,后文将详细说明尺度空间的连续性。下图形象说明了什么是尺度空间:



尺度空间的连续性

我们要在每个八度中求s层点,通过lowe论文可知,每一层极值点是在三维空间(图像二维,尺度一维)中比较获得,因此为了获得s层点,那么在差分高斯金字塔中需要有s+2图像,好了,继续上溯,如果差分高斯金字塔中有s+2幅图像,那么高斯金字塔中就必须要有s+3幅图像了,因为差分高斯金字塔是由高斯金字塔相邻两层相减得到的。好了,到了这里似乎真相大白,但是我们上面的推导有一个致命的问题,我们上来就假设“我们要在每个八度中求s层点”,为什么要s层点呢?这才是这个小节的主题:是为了保持尺度的连续性!下面进行详细的分析:

以一个八度中的图像为例说明(此处最好结合OpenCV中金字塔构建部分的源码<下文已列出,可以参照>)

高斯金字塔和差分高斯金字塔那几个公式还要在这里贴出来一下:

高斯函数G对图像I的模糊函数:



高斯差分函数:



通过以上这两个公式,可以确定一个八度中(以第一个八度为例)高斯图像和差分高斯图像的尺度如下(以lowe论文为例,s=3,所以每个八度中会有3+3=6幅图像),每一幅图像的尺度也在图像标示了出来。

通过以上这两个公式,可以确定一个八度中(以第一个八度为例)高斯图像和差分高斯图像的尺度如下(以lowe论文为例,s=3,所以每个八度中会有3+3=6幅图像),每一幅图像的尺度也在图像标示了出来。



在lowe的论文中s=3,因此有



因此,当前八度中各高斯图像的尺度依次为:

σ,2^(1/3)σ, 2^(2/3)σ, 2^(3/3)σ, 2^(4/3)σ, 2^(5/3)σ;

当前八度中各差分高斯图像的尺度依次为:

σ,2^(1/3)σ, 2^(2/3)σ, 2^(3/3)σ, 2^(4/3)σ。

同理,我们可以推断出,下一个八度中各高斯图像的尺度依次为:

2×σ,2×2^(1/3)σ,2×2^(2/3)σ,2×2^(3/3)σ,2×2^(4/3)σ,2×2^(5/3)σ;

下一个八度中各差分高斯图像的尺度依次为:

2×σ,2×2^(1/3)σ,2×2^(2/3)σ,2×2^(3/3)σ,2×2^(4/3)σ。

可以观察到,其中粗体标注数据所代表的层,是差分高斯金字塔中获得极值点的层,也就是说只有在这些层上才发生与上下两层比较获得极值点的操作。下面将这些粗体连成一串:2^(1/3)σ, 2^(2/3)σ, 2^(3/3)σ,2×2^(1/3)σ,2×2^(2/3)σ,2×2^(3/3)σ……。发现了什么?对了,这些数据是连续的,我们通过在每个八度中多构造三幅高斯图像,达到了尺度空间连续的效果,这一效果带来的直接的好处是在尺度空间的极值点确定过程中,我们不会漏掉任何一个尺度上的极值点,而是能够综合考虑量化的尺度因子。

下一个八度的第一幅图像如何确定

这个问题,是上面问题(尺度空间的连续性)的延伸,我们可以通过反推OpenCV中这一部分的源代码,来理解这个问题。

当前八度中的第一幅图像是通过前一个八度的倒数第三幅图像得到。OpenCV这段源码有个很重要的问题:不同的八度间的尺度不是会有一个2的差异吗?为什么本部分源码并没有体现这一点,而是在对每一个八度处理中都是用相同的数组sig[]。首先明确一下sig数组内.存储的并不是一个绝对的模糊核,而是相对的模糊核,这一点很重要,既然是相对的模糊核,那么第一幅图像的核就很重要了,所以尺度的连续就看每个八度的第一幅图像了。

对于以下列出的高斯金字塔的构建过程来看,每个八度中的第一幅图像并没有一个2倍的尺度跃进过程。但是,这个2倍的跃进式隐含在整个高斯金字塔的构建过程中了!

再看倒数第三幅图像,这幅图像的尺度是2^(3/3)δ,3/3=1,也就是说,在这个八度中,第一幅图像的尺度是δ,而倒数第三幅图像的尺度是2δ,正好发生了一个2的跃进!这就是以这幅图像作为基准进行下采样的原因,如此的话,下一个八度的第一幅图像的初始尺度就是2*δ了。

这就是真相,这就是为什么选用倒数第三幅图像进行下采样的原因。

[cpp] view plaincopy

void SIFT::buildGaussianPyramid( const Mat& base, vector& pyr, int nOctaves ) const

{

vector sig(nOctaveLayers + 3);

pyr.resize(nOctaves*(nOctaveLayers + 3));

// precompute Gaussian sigmas using the following formula:

// \sigma_{total}^2 = \sigma_{i}^2 + \sigma_{i-1}^2

sig[0] = sigma;

double k = pow( 2., 1. / nOctaveLayers );

for( int i = 1; i < nOctaveLayers + 3; i++ )

{

double sig_prev = pow(k, (double)(i-1))*sigma;

double sig_total = sig_prev*k;

sig[i] = std::sqrt(sig_total*sig_total - sig_prev*sig_prev);

}

for( int o = 0; o < nOctaves; o++ )

{

for( int i = 0; i < nOctaveLayers + 3; i++ )

{

Mat& dst = pyr[o*(nOctaveLayers + 3) + i];

if( o == 0 && i == 0 )

dst = base;

// base of new octave is halved image from end of previous octave

else if( i == 0 )/每一个八度中第一幅图像的确定过程/

{

const Mat& src = pyr[(o-1)*(nOctaveLayers + 3) + nOctaveLayers];

resize(src, dst, Size(src.cols/2, src.rows/2), 0, 0, INTER_NEAREST);

}

else

{

const Mat& src = pyr[o*(nOctaveLayers + 3) + i-1];

GaussianBlur(src, dst, Size(), sig[i], sig[i]);

}

}

}

}

void SIFT::buildDoGPyramid( const vector& gpyr, vector& dogpyr ) const

{

int nOctaves = (int)gpyr.size()/(nOctaveLayers + 3);

dogpyr.resize( nOctaves*(nOctaveLayers + 2) );

for( int o = 0; o < nOctaves; o++ )

{

for( int i = 0; i < nOctaveLayers + 2; i++ )

{

const Mat& src1 = gpyr[o*(nOctaveLayers + 3) + i];

const Mat& src2 = gpyr[o*(nOctaveLayers + 3) + i + 1];

Mat& dst = dogpyr[o*(nOctaveLayers + 2) + i];

subtract(src2, src1, dst, noArray(), DataType::type);

}

}

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  sift