SIFT算法(Scale-Invariant feature transform,尺度不变特征变换)通过在图像中提取独特性不变特征,可以实现物体或场景在不同视角下的可靠匹配。其提取的特征对于图像缩放、旋转和一定范围内的三维仿射变换、噪声叠加、光照变化均具有不变性。由于特征的高度独特性,场景中的每一个特征都有很大的可能在由多幅图像提取的特征数据库中得到正确的匹配结果。因此使用这些特征可以用于物体识别。识别首先需将每个特征与由已知物体组成的特征数据库进行快速最邻匹配,然后通过霍夫变换确定属于同一个物体的特征点对,最后通过对一致性姿态参数的最小二乘法进行验证。这种方法可以在噪声和光照影响下获得稳定的识别效果,而不失实时性。
使用一系列局部关键点进行图像匹配最早可追溯至Moravec(1981),他在立体匹配中使用了角点检测。Moravec detector 在1988年被Harris和Stephens改进,Harris又在1992年改进用于动作追踪,自此Harris corner detector被广泛应用。1997年Schmid和Mohr做出了开拓性的工作,证明局部的不变特征可以应用于图像识别。但是Harris corner detector对图像尺度改变非常敏感,所以对不同大小的图像匹配效果不佳。
Lowe,D.G.1999年发表论文《Object recognition from local scale-invariant features》,提出了一种具有尺度不变性的特征。之后,又有一系列研究试图将这种不变性扩展至对全部的仿射变换有效。在2004年Lowe发表的论文《Distinctive Image Features from Scale-Invariant Keypoints》中,其SIFT特征可以适用于一定范围内的仿射变换。Y.Ke和R.Sukthankar 2004年在《PCA-SIFT:A More Distinctive Representation for Local Image Descriptors》中提出PCA-SIFT,将原算法中的直方图法换成主元分析法(Principle Component Analysis),实现描述子的降维。Herbert Bay 于2006年提出SURF加速稳健特征算法,实现算法加速,并于2008年发表论文《Speeded-Up Robust Features(SURF)》。很多其他的特征类型也被用于图像识别中,例如图像轮廓、图像相位、颜色等。局部点特征与这些特征相结合可以增强识别的鲁棒性,未来的图像识别系统很可能采用多特征结合的方法。
David Lowe,SIFT算法的提出者,在论文之外提供了其算法的示例程序——SIFT demo program (Version 4, July 2005),可惜其关键部分没有给出源码。Rob Hess利用C语言结合OpenCV写了开源的SIFT实现——opensift,且具有与原作者示例相差不多的运行性能。Rob Hess在其github上给出了全部的源代码:点击打开链接
解压其源代码,Rob Hess写的代码中没有链接math库,如果不修改,会出现如下的错误:
[plain] view plain copy
- <span style="font-size:18px;"><span style="font-size:12px;">gcc -I../include `pkg-config --cflags opencv gtk+-2.0` siftfeat.c -o ../bin/siftfeat -L../lib -lopensift `pkg-config --libs opencv gtk+-2.0`
- /usr/bin/ld: /tmp/ccwEACAH.o: undefined reference to symbol 'lrint@@GLIBC_2.1'
- /usr/local/lib/libm.so.6: error adding symbols: DSO missing from command line
- collect2: error: ld returned 1 exit status
- make[1]: *** [siftfeat] 错误 1</span>
- </span>
我们查看错误的原因是无法找到math库。所以进入opensift的源文件src目录下,打开Makefile文件,添加Lmath = -lm。如下所示:
[plain] view plain copy
- <span style="font-size:18px;"><span style="font-size:12px;">INCL = -I$(INC_DIR) `pkg-config --cflags opencv gtk+-2.0`
- LIBS = -L$(LIB_DIR) -lopensift `pkg-config --libs opencv gtk+-2.0`
- Lmath = -lm //添加链接到math库
- OBJ = imgfeatures.o utils.o sift.o kdtree.o minpq.o xform.o
- BIN = siftfeat match dspfeat</span>
- </span>
再修改编译程序的命令部分:
[plain] view plain copy
- <span style="font-size:18px;"><span style="font-size:12px;">siftfeat: libopensift.a siftfeat.c
- $(CC) $(CFLAGS) $(INCL) siftfeat.c <span style="background-color:rgb(255,0,0)">$(Lmath)</span> -o $(BIN_DIR)/$@ $(LIBS)
- match: libopensift.a match.c
- $(CC) $(CFLAGS) $(INCL) match.c <span style="background-color:rgb(255,0,0)">$(Lmath)</span> -o $(BIN_DIR)/$@ $(LIBS)
- dspfeat: libopensift.a dspfeat.c
- $(CC) $(CFLAGS) $(INCL) dspfeat.c <span style="background-color:rgb(255,0,0)">$(Lmath)</span> -o $(BIN_DIR)/$@ $(LIBS)</span>
- </span>
然后保存退出。
回到opensift源程序目录下,执行make,编译成功后,在此目录的bin目录下会有三个可执行文件生成:dspfeat match siftfeat
可以测试下程序是否可用,终端键入如下的命令:
[plain] view plain copy
- ./match ../beaver.png ../beaver_xform.png
效果图如下:
有关SIFT算法的理解与实现,后面陆续贴上,与大家共同进步!!