SIFT简介

SIFT(Scale-Invariant Feature Transform,尺度不变特征变换匹配算法)是一种高效区域检测算法。

SIFT算法可以解决的问题:

  1. RST(Rotation Scale Translation):图像的旋转、缩放、平移等变换
  2. 图像的仿射变换(Affine Transformation):图像的拉伸、压缩、扭曲等变换
  3. 图像的光照变化
  4. 目标部分遮挡
  5. 杂物和噪声干扰

SIFT算法原理

1. 高斯滤波

一个图像的尺度空间L是高斯函数G(x,y,σ)与图像I(x,y)的卷积:

L(x,y,σ)=G(x,y,σ)I(x,y)G(x,y,σ)=12πσ2e(xx0)2+(yy0)22σ2

其中,G(x,y,σ)是高斯函数,σ是尺度因子,是卷积运算,x0,y0是高斯函数的中心(卷积核的中心)。

σ越小,图像被平滑的越少,图像的细节越多。
小尺度对应于图像的细节,大尺度对应于图像的整体特征。

Gaussian Blur

2. 高斯金字塔

高斯金字塔

高斯金字塔包含多组(Octave)图像,每组图像由多层(Interval)不同尺度的高斯模糊图像组成。

构建过程:

  1. 将原图像扩大到两倍,作为第0组的第0层
  2. 对第0组的第0层进行σ0的高斯模糊,得到第0组的第1层
  3. 选定一个比例系数k,对第0组的第1层进行kσ0的高斯模糊,得到第0组的第2层
  4. 对第0组的第2层进行k2σ0的高斯模糊,得到第0组的第3层,以此类推…
  5. 上一组倒数第3层图像做比例因子为2的降采样,得到下一组的第0层,重复步骤2-4

组数计算公式:O=log2(min(M,N))3

  • M,N:原图像的长宽

层数公式:S=n+3

  • S是每组的层数(自设)
  • n是最终想在差分金字塔中提取极值点的层数(见差分金字塔)

平滑因子公式:σ(o,r)=σ02o+rn,其中o是组数,r是层数

  • SIFT算法中,σ0=1.6。但由于相机具有初始模糊σ0=0.5,实际σ0=1.620.52=1.52
  • 第o层的初始平滑因子σ(o,0)=2oσ0
  • k=21/n

高斯金字塔2

金字塔内各图片的关系:

  • 在同一组内,不同层图像的尺寸是一样的,后一层图像的高斯平滑因子σ是前一层图像平滑因子的k倍
  • 在不同组内,后一组第一个图像是前一组倒数第三个图像的二分之一采样,图像大小是前一组的一半

3. 高斯差分金字塔与极值点检测

3.1 高斯差分金字塔

对高斯金字塔的每一组图像,计算相邻两层图像的差分,得到高斯差分金字塔(DoG, Difference of Gaussian)。

D(x,y,σ)=(G(x,y,kσ)G(x,y,σ))I(x,y)

3.2 估计极值点

将每个像素点和它在3×3×3的邻域内的26个像素点进行比较。
如果这个点是这27个点中的最大值或最小值,则认为这个点是一个极值点。

DoG金字塔是离散的(因为尺度空间和像素点都是离散的),所以找到的极值点不太准确的,很大可能在真正极值点附近,因此需要对每个极值点进行插值。

3.3 泰勒展开求精确极值点

对每个极值点X0(x0,y0,σ0)T,进行三元二次泰勒展开:

f(X)=f(x0)+fXTX^+12X^T2fX2X^X^=XX0X=(x,y,σ)T

f(X)X求导:

f(X)X=fXT+12(2fX2+2fX2T)X^=fXT+2fX2X^

导数为0时,解得极值点:

X^=2fX21fX

代入f(X)得到极值:

f(X)=f(x0)+12fXTX^

3.4 去除低对比度点

舍去|f(X0)|<Tn,T=0.04的极值点,因为这些点对应的差分值太小,对比度低,不具有代表性。

3.5 去除边缘响应

DoG在边缘会有比较大的值(边缘响应强),但边缘不一定能够提供稳定的特征,因此需要去除边缘响应强的点。

对于每个极值点,计算Hessian矩阵的迹和行列式:

H=[DxxDxy DxyDyy]Tr(H)=Dxx+Dyy=α+βDet(H)=DxxDyy(Dxy)2=αβ

其中:

  • α为较大的特征值,β为较小的特征值
  • α=rβr是一个大于1的实数

过滤:

  1. Det(H)<0
  2. (Tr(H))2Det(H)(r+1)2/r,论文推荐值r=10

4. 关键点方向分配

  1. 0~360度划分为36 bins,每个bin为10度
  2. 高斯金字塔找到关键点对应位置,以它为圆心,半径为1.5σ画圆
  3. 统计圆中所有像素的梯度方向、梯度幅值(模),直方图平滑处理,用1.5σ进行高斯加权
    • 平滑处理:防止某个梯度方向角度受噪声干扰等因素突变
    • 高斯加权:使特征点附件的梯度幅值具有更大的权重,弥补因没有仿射不变性而导致的特征不稳定
  4. 统计出数值最高的梯度方向,作为主方向;保留大于主方向80%的方向作为辅方向

梯度方向和梯度幅值的计算:

m(x,y)=(L(x+1,y)L(x1,y))2+(L(x,y+1)L(x,y1))2

θ(x,y)=arctan(L(x,y+1)L(x,y1)L(x+1,y)L(x1,y))

高斯加权公式:

Wi,j=e(i2+j2)2×(1.5σ)2

  • i,j是像素点到关键点的距离

5. 关键点描述

描述符是一组向量,用于描述特征点及其领域点的特征,以便更好地与其他图片匹配

  1. 将坐轴标移到关键点方向
  2. 将特征点的领域划分为d×d个子区域,每个子区域大小为mσ×mσ,并划分为8个方向。论文推荐值:m=3d=4
  3. 每一个子块进行8个方向的直方图统计操作,共d×d×8=128个bin,得到一个128维的特征向量(描述符)

6. 特征点匹配

分别对模板图(参考图,reference image)和实时图(观测图,observation image)建立关键点描述子集合。

目标的识别是通过两点集内关键点描述子的比对来完成,一般采用欧氏距离来衡量两个描述子之间的相似度。

可以使用KD树优化搜索过程。

SIFT实现

cv2中已经给出了SIFT算法的实现,可以直接调用。

python
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
import cv2
import numpy as np
import matplotlib.pyplot as plt

# 读取图像
img=cv2.imread('nz.jpg')
cat=cv2.cvtColor(img,cv2.COLOR_BGR2GRAY)

# 创建SIFT对象
sift=cv2.SIFT_create()

# 关键点检测:kp关键点信息包括方向,尺度,位置信息,des是关键点的描述符
kp,des=sift.detectAndCompute(cat,None)

# 在图像上绘制关键点的检测结果
cv2.drawKeypoints(img,kp,img,flags=cv2.DRAW_MATCHES_FLAGS_DRAW_RICH_KEYPOINTS)

# 图像显示
plt.imshow(cv2.cvtColor(img, cv2.COLOR_BGR2RGB))
plt.title('SIFT Result')
plt.show()

SIFT Result