SIFT即尺度不变特征变换(SIFT-Scale Invariant Feature Transform)
SIFT简介
通常的角点检测方法在图片旋转时能够找到同样的角点即具有旋转不变性,但对图像进行缩放时角点就有可能不再是角点了.(如图即较小的图像中用一个较小的窗口可以检测出角点,但当图像放大时同样的窗口可能就检测不到角点了.)
因此D.Lowe提出了SIFT(尺度不变特征变换)算法.算法主要由四部分组成:
为了解决图像放大缩小时即不同的尺度空间需要使用不同大小窗口的问题,使用了尺度空间滤波器(由一系列具有不同方差
σ
σ
的高斯卷积核构成)。用不同方差值
σ
σ
的高斯拉普拉斯算子(LoG)对图像进行卷积,可以检测不同大小的特征点(当LoG的方差
σ
σ
与特征点直径相等时能够使特征点完全平滑)。
关于LoG算子:
LoG算子的基本步骤为:
- 用二维高斯滤波器平滑滤波;
- 用二维拉普拉斯算子进行图像增强;
- 依据二阶导数过零点进行边缘检测;
二维高斯滤波函数:
G(x,y)=12πσ2exp(−x2+y22σ2)
G
(
x
,
y
)
=
1
2
π
σ
2
e
x
p
(
−
x
2
+
y
2
2
σ
2
)
与原始图像f(x,y)进行卷积,得到平滑图像I(x,y):
I(x,y)=G(x,y)∗f(x,y)
I
(
x
,
y
)
=
G
(
x
,
y
)
∗
f
(
x
,
y
)
再用拉普拉斯算子获取I(x,y)的二阶方向导数图像M(x,y)。由线性系统卷积与微分的可交换性得:
M(x,y)=▽2{I(x,y)}=▽2[G(x,y)∗f(x,y)]=[▽2G(x,y)]∗f(x,y)
M
(
x
,
y
)
=
▽
2
{
I
(
x
,
y
)
}
=
▽
2
[
G
(
x
,
y
)
∗
f
(
x
,
y
)
]
=
[
▽
2
G
(
x
,
y
)
]
∗
f
(
x
,
y
)
对图像的高斯平滑滤波与拉普拉斯微分运算结合成算子
▽2G(x,y)
▽
2
G
(
x
,
y
)
即高斯拉普拉斯算子(LoG):
LoG(x,y)=−1πσ2[1−x2+y22σ2]e−x2+y22σ2 L o G ( x , y ) = − 1 π σ 2 [ 1 − x 2 + y 2 2 σ 2 ] e − x 2 + y 2 2 σ 2
则在一个图像的尺度空间中,将方差
σ
σ
看作是一个尺度变换因子。即一个变化尺度的高斯函数
G(x,y,σ)
G
(
x
,
y
,
σ
)
与原图像
I(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,σ)=12πσ2exp[−(x−m/2)2+(y−n/2)22σ2]
G
(
x
,
y
,
σ
)
=
1
2
π
σ
2
e
x
p
[
−
(
x
−
m
/
2
)
2
+
(
y
−
n
/
2
)
2
2
σ
2
]
m,n为高斯模板的维度由
(6σ+1)×(6σ+1)
(
6
σ
+
1
)
×
(
6
σ
+
1
)
确定,即高斯方差大小与窗口大小存在一个倍数关系
(6σ+1)
(
6
σ
+
1
)
。
σ
σ
值越小表示图像被平滑的越少,尺度越小。这样大尺度对应大的特征点小尺度对应小的特征点。
尺度空间实现时使用高斯金字塔表示,先通过对图像进行不同尺度的高斯模糊,再对图像进行降采样处理,建立高斯金字塔:
金字塔每层的一张图像使用不同参数做高斯模糊,这样每层就包含多张高斯模糊图像合称为一组(Octave)。这样可以在尺度空间和二维平面中检测到局部最大值
(x′,y′,σ′)
(
x
′
,
y
′
,
σ
′
)
。(表示在
σ′
σ
′
尺度中点
(x′,y′)
(
x
′
,
y
′
)
可能是一个特征点)
但这种LoG计算量非常大,SIFT算法使用高斯差分算子(DoG)来对LoG做近似。DoG就是上面不同分辨率的金字塔中相邻的两层之间的差值,如图:
然后可以在不同的尺度空间和2D平面中搜索局部最大值,对图像中的像素点,只需与周围的8邻域以及尺度空间中的上下的18个像素点(上层9个与下层9个)。如图:
若是局部最大值,则该像素点就可能是一个关键点。
算法作者给出的SIFT参数的经验值Octaves=4(通过降采样构成尺寸减小的图像金字塔),空间尺度取5,即使用5个不同的高斯核进行卷积,初始方差为1.6等。
一旦找到关键点,作者使用尺度空间的泰勒级数展开来获得极值的准确位置,若极值点的灰度值小于阈值0.03(OpenCV中阈值为contrastThreshold)就会被忽略掉。DoG算法对边界敏感,因此必须把边界去除。在Harris算法中当一个特征值远远大于另外一个特征值时检测到的为边界。因此设置一个阈值(OpenCV中称为为边界阈值edgeThreshold,默认值为10),当高于该阈值时这个关键点就被忽略。这样低对比度的关键点和边界关键点就会被滤除。
OpenCV3中的SIFT类
OpenCV中基类Feature2D下的SIFT类为SIFT算法提取关键点和计算描述符的类。
其中函数create()的参数说明为:
CV_WRAP static Ptr<SIFT> create(
int nfeatures = 0, //要保留的最佳特征的数量。特征按得分排列(在SIFT算法中用局部对比度测量)
int nOctaveLayers = 3,//每组的层数
double contrastThreshold = 0.04, //用于过滤低对比度区域中的弱特征的对比度阈值(对比度阈值越大,检测的特征越少)
double edgeThreshold = 10,//用于滤除边缘状特征的阈值(边缘阈值越大,滤出特征越少)
double sigma = 1.6);//输入图像的高斯sigma
示例
SIRF特征检测示例:
#include<opencv2/opencv.hpp>
#include<opencv2/xfeatures2d.hpp>
using namespace cv;
using namespace cv::xfeatures2d;
//SIRF特征检测
Mat src;
int numFeatures = 120;
void trackBar(int, void*);
int main()
{
src = imread("E:/image/image/bdb.jpg");
if (src.empty())
{
printf("can not load image \n");
return -1;
}
namedWindow("input", WINDOW_AUTOSIZE);
imshow("input", src);
namedWindow("output", WINDOW_AUTOSIZE);
createTrackbar("minHessian","output",&numFeatures, 500, trackBar);
waitKey(0);
return 0;
}
void trackBar(int, void*)
{
Mat dst;
// SIRF特征检测
Ptr<SIFT> detector = SIFT::create(numFeatures);
std::vector<KeyPoint> keypoints;
detector->detect(src, keypoints, Mat());
// 绘制关键点
drawKeypoints(src, keypoints, dst, Scalar::all(-1), DrawMatchesFlags::DEFAULT);
imshow("output", dst);
}
相关链接:
Distinctive Image Features from Scale-Invariant Keypoints