Sift算法的原理描述以及对比Harris算法的特征匹配结果
1、SIFT特征原理描述
1.1 SIFT 概述
SIFT的全称是Scale Invariant Feature Transform,尺度不变特征变换,由加拿大教授David G.Lowe提出的。SIFT特征对旋转、尺度缩放、亮度变化等保持不变性,是一种非常稳定的局部特征。
SIFT特征检测主要有四个步骤:
- 尺度空间的极值检测
- 特征点定位
- 特征方向赋值
- 特征点描述
1.2 尺度空间
1.2.1 多分辨率图像金字塔
在早期图像的多尺度通常使用图像金字塔表示形式。图像金字塔是同一图像在不同的分辨率下得到的一组结果,其生成过程一般包括两个步骤:
- 对原始图像进行平滑
- 对处理后的图像进行降采样
1.2.2 高斯尺度空间
我们还可以通过图像的模糊程度来模拟人在距离物体由远到近时物体在视网膜上成像过程,距离物体越近其尺寸越大图像也越模糊,这就是高斯尺度空间,使用不同的参数模糊图像(分辨率不变),是尺度空间的另一种表现形式。
我们知道图像和高斯函数进行卷积运算能够对图像进行模糊,使用不同的“高斯核”可得到不同模糊程度的图像。一副图像其高斯尺度空间可由其和不同的高斯卷积得到:
L
(
x
,
y
,
σ
)
=
G
(
x
,
y
,
σ
)
∗
I
(
x
,
y
)
\ L(x,y,σ)=G(x,y,σ)∗I(x,y)
L(x,y,σ)=G(x,y,σ)∗I(x,y)
其中, G ( x , y , σ ) \ G(x,y,σ) G(x,y,σ)是高斯核函数。
σ称为尺度空间因子,它是高斯正态分布的标准差,反映了图像被模糊的程度,其值越大图像越模糊,对应的尺度也就越大。
L
(
x
,
y
,
σ
)
\ L(x,y,σ)
L(x,y,σ)代表着图像的高斯尺度空间。
构建尺度空间的目的是为了检测出在不同的尺度下都存在的特征点,而检测特征点较好的算子是
Δ
2
G
\ Δ^2G
Δ2G(高斯拉普拉斯,LoG),
Δ
2
=
∂
2
∂
x
2
+
∂
2
∂
y
2
\ \Delta ^2 = \frac{\partial ^2}{\partial x^2} + \frac{\partial ^2}{\partial y^2}
Δ2=∂x2∂2+∂y2∂2
使用LoG虽然能较好的检测到图像中的特征点,但是其运算量过大,通常可使用DoG(差分高斯,Difference of Gaussina)来近似计算LoG[Marr and Hidreth]。
设k为相邻两个高斯尺度空间的比例因子,则DoG的定义:
D
(
x
,
y
,
σ
)
=
[
G
(
x
,
y
,
k
σ
)
−
G
(
x
,
y
,
σ
)
]
∗
I
(
x
,
y
)
=
L
(
x
,
y
,
k
σ
)
−
L
(
x
,
y
,
σ
)
\ D(x,y,\sigma) = [G(x,y,k\sigma) - G(x,y,\sigma)] \ast I(x,y) \\ = L(x,y,k\sigma) - L(x,y,\sigma)
D(x,y,σ)=[G(x,y,kσ)−G(x,y,σ)]∗I(x,y)=L(x,y,kσ)−L(x,y,σ)
其中,
L
(
x
,
y
,
σ
)
\ L(x,y,σ)
L(x,y,σ)是图像的高斯尺度空间。
从上式可以知道,将相邻的两个高斯空间的图像相减就得到了DoG的响应图像。为了得到DoG图像,先要构建高斯尺度空间,而高斯的尺度空间可以在图像金字塔降采样的基础上加上高斯滤波得到,也就是对图像金字塔的每层图像使用不同的参数σ进行高斯模糊,使每层金字塔有多张高斯模糊过的图像。降采样时,金字塔上边一组图像的第一张是由其下面一组图像倒数第三张降采样得到。
易知,高斯金字塔有多组,每组又有多层。一组中的多个层之间的尺度是不一样的(也就是使用的高斯参数σ是不同的),相邻两层之间的尺度相差一个比例因子k。如果每组有S层,则
k
=
2
1
S
\ k = 2 ^{\frac{1}{S}}
k=2S1。上一组图像的最底层图像是由下一组中尺度为2σ的图像进行因子为2的降采样得到的(高斯金字塔先从底层建立)。高斯金字塔构建完成后,将相邻的高斯金字塔相减就得到了DoG金字塔。
高斯金字塔的组数一般是
o
=
[
log
2
m
i
n
(
m
,
n
)
]
−
a
\ o = [\log _2min(m,n)] - a
o=[log2min(m,n)]−a
o
\ o
o 表示高斯金字塔的层数,m,n分别是图像的行和列。减去的系数a可以在
0
−
l
o
g
2
m
i
n
(
m
,
n
)
\ 0−log2min(m,n)
0−log2min(m,n)之间的任意值,和具体需要的金字塔的顶层图像的大小有关。
高斯模糊参数σ(尺度空间),可由下面关系式得到
σ
(
o
,
s
)
=
σ
0
⋅
2
o
+
s
S
\ \sigma(o,s) = \sigma_0 \cdot 2^{\frac{o + s}{S}}
σ(o,s)=σ0⋅2So+s
高斯金字塔构建成功后,将每一组相邻的两层相减就可以得到DoG金字塔.
1.3 DoG空间极值检测
为了寻找尺度空间的极值点,每个像素点要和其图像域(同一尺度空间)和尺度域(相邻的尺度空间)的所有相邻点进行比较,当其大于(或者小于)所有相邻点时,改点就是极值点。如图所示,中间的检测点要和其所在图像的3×3邻域8个像素点,以及其相邻的上下两层的3×3领域18个像素点,共26个像素点进行比较。
从上面的描述中可以知道,每组图像的第一层和最后一层是无法进行比较取得极值的。为了满足尺度变换的连续性,在每一组图像的顶层继续使用高斯模糊生成3幅图像,高斯金字塔每组有S+3层图像,DoG金字塔的每组有S+2组图像。
1.4 删除不好的特征点
通过比较检测得到的DoG的局部极值点实在离散的空间搜索得到的,由于离散空间是对连续空间采样得到的结果,因此在离散空间找到的极值点不一定是真正意义上的极值点,因此要设法将不满足条件的点剔除掉。可以通过尺度空间DoG函数进行曲线拟合寻找极值点,这一步的本质是去掉DoG局部曲率非常不对称的点。
要剔除掉的不符合要求的点主要有两种:
1.低对比度的特征点
2.不稳定的边缘响应点
1.5 求取特征点的主方向
经过上面的步骤已经找到了在不同尺度下都存在的特征点,为了实现图像旋转不变性,需要给特征点的方向进行赋值。利用特征点邻域像素的梯度分布特性来确定其方向参数,再利用图像的梯度直方图求取关键点局部结构的稳定方向。
找到了特征点,也就可以得到该特征点的尺度σ,也就可以得到特征点所在的尺度图像
L
(
x
,
y
)
=
G
(
x
,
y
,
σ
)
∗
I
(
x
,
y
)
\ L(x,y) = G(x,y,\sigma) \ast I(x,y)
L(x,y)=G(x,y,σ)∗I(x,y)
计算以特征点为中心、以3×1.5σ为半径的区域图像的幅角和幅值,每个点L(x,y)的梯度的模m(x,y)以及方向θ(x,y)可通过下面公司求得
m
(
x
,
y
)
=
[
L
(
x
+
1
,
y
)
−
L
(
x
−
1
,
y
)
]
2
+
[
L
(
x
,
y
+
1
)
−
L
(
x
,
y
−
1
)
]
2
\ m(x,y) = \sqrt{[L(x+1,y) - L(x-1,y)]^2 + [L(x,y + 1) - L(x,y - 1)]^2}
m(x,y)=[L(x+1,y)−L(x−1,y)]2+[L(x,y+1)−L(x,y−1)]2
θ
(
x
,
y
)
=
arctan
L
(
x
,
y
+
1
)
−
L
(
x
,
y
−
1
)
L
(
x
+
1
,
y
)
−
L
(
x
−
1
,
y
)
\ \theta(x,y) = \arctan{\frac{L(x,y+1) - L(x,y - 1)}{L(x + 1,y) - L(x-1,y)}}
θ(x,y)=arctanL(x+1,y)−L(x−1,y)L(x,y+1)−L(x,y−1)
计算得到梯度方向后,就要使用直方图统计特征点邻域内像素对应的梯度方向和幅值。梯度方向的直方图的横轴是梯度方向的角度(梯度方向的范围是0到360度,直方图每36度一个柱共10个柱,或者没45度一个柱共8个柱),纵轴是梯度方向对应梯度幅值的累加,在直方图的峰值就是特征点的主方向。
得到特征点的主方向后,对于每个特征点可以得到三个信息
(
x
,
y
,
σ
,
θ
)
\ (x,y,σ,θ)
(x,y,σ,θ),即位置、尺度和方向。由此可以确定一个SIFT特征区域,一个SIFT特征区域由三个值表示,中心表示特征点位置,半径表示关键点的尺度,箭头表示主方向。具有多个方向的关键点可以被复制成多份,然后将方向值分别赋给复制后的特征点,一个特征点就产生了多个坐标、尺度相等,但是方向不同的特征点。
1.6生成特征描述
通过以上的步骤已经找到了SIFT特征点位置、尺度和方向信息,下面就需要使用一组向量来描述关键点也就是生成特征点描述子,描述子应具有较高的独立性,以保证匹配率。
特征描述符的生成大致有三个步骤:
1.校正旋转主方向,确保旋转不变性。
2.生成描述子,最终形成一个128维的特征向量
3.归一化处理,将特征向量长度进行归一化处理,进一步去除光照的影响。
为了保证特征矢量的旋转不变性,要以特征点为中心,在附近邻域内将坐标轴旋转θ(特征点的主方向)角度,即将坐标轴旋转为特征点的主方向。旋转后邻域内像素的新坐标为:
[
x
′
y
′
]
=
[
cos
θ
−
sin
θ
sin
θ
cos
θ
]
[
x
y
]
\ \left[ \begin{array}{c} x ^ \prime \\ y ^ \prime \end{array} \right] = \left[ \begin{array}{cc} \cos \theta \quad - \sin \theta \\ \sin \theta \quad \cos \theta \end{array} \right] \left[ \begin{array}{c} x \\ y \end{array}\right]
[x′y′]=[cosθ−sinθsinθcosθ][xy]
旋转后以主方向为中心取 8×8的窗口。左图的中央为当前关键点的位置,每个小格代表为关键点邻域所在尺度空间的一个像素,求取每个像素的梯度幅值与梯度方向,箭头方向代表该像素的梯度方向,长度代表梯度幅值,然后利用高斯窗口对其进行加权运算。最后在每个4×4的小块上绘制8个方向的梯度直方图,计算每个梯度方向的累加值,即可形成一个种子点,如右图所示。每个特征点由4个种子点组成,每个种子点有8个方向的向量信息。
对每个关键点使用4×4共16个种子点来描述,这样一个关键点就可以产生128维的SIFT特征向量。
2、对两张图片进行SIFT特征匹配处理
在运行sift算法前要先安装一下vlfeat
大家可以登录http://www.vlfeat.org/官网进行下载安装
我安装的是 vlfeat-0.9.20-bin.tar.gz 发在了网盘,如果要同一版本的同学可以直接下载: 提取码: 8kw7
下载完后打开bin文件夹
打开后选择自己的系统进行解压,我是win64所以解压了win64的文件夹
然后打开你PCV包里的sift。py文件,搜索process_image,将你的win64文件夹(或者其他系统)里的sift.exe的路径添加到下图的位置。
如果出现SyntaxError: invalid syntax错误如下图:
可能是因为print后面没有加括号,python3.x版本的print后面需要加上括号,在后面加上就行了
sift算法运行代码如下:
from PIL import Image
from pylab import *
import sys
from PCV.localdescriptors import sift
if len(sys.argv) >= 3:
im1f, im2f = sys.argv[1], sys.argv[2]
else:
# im1f = '../data/sf_view1.jpg'
# im2f = '../data/sf_view2.jpg'
im1f = 'jiageng2.jpg'
im2f = 'jiageng4.jpg'
# im1f = '../data/climbing_1_small.jpg'
# im2f = '../data/climbing_2_small.jpg'
im1 = array(Image.open(im1f))
im2 = array(Image.open(im2f))
sift.process_image(im1f, 'out_sift_1.txt')
l1, d1 = sift.read_features_from_file('out_sift_1.txt')
figure()
gray()
subplot(121)
sift.plot_features(im1, l1, circle=False)
sift.process_image(im2f, 'out_sift_2.txt')
l2, d2 = sift.read_features_from_file('out_sift_2.txt')
subplot(122)
sift.plot_features(im2, l2, circle=False)
#matches = sift.match(d1, d2)
matches = sift.match_twosided(d1, d2)
print ('{} matches'.format(len(matches.nonzero()[0])))
figure()
gray()
sift.plot_matches(im1, im2, l1, l2, matches, show_below=True)
show()
对嘉庚图书馆和中山纪念馆分别进行sift算法特征值匹配结果
对比Harris算法的特征值匹配:
结论:可以看出,sift算法匹配特征值的结果较好,受到图像尺寸 以及 不同视角拍摄的影响较小。而Harris算法在同一视角中的匹配结果效果还算良好,但在光前纪念馆 图像尺寸调小,不同视角上的匹配效果较差。