1. 简要介绍
SIFT算法的全称是ScaleInvariant Feature Transform(尺度不变特征变换),用于提取图像中具有显著性的特征,并保持尺度、旋转不变性。同时,对于视点变化、光照也具有一定程度的不变性。鉴于SIFT特征点具有稳定性和显著性等特点,该算法常用于图像之间的连接点提取,为基于图像处理的后续工作奠定基础,比如恢复摄影时刻的影像位置和姿态(摄影测量中称为空中三角测量)、影像密集匹配和模式识别等。
SIFT算法的提出者David G.Lowe并没有公开源码。考虑到算法的实现的复杂,Rob Hess推出了SIFT算法的C实现版本,即OpenSIFT开源项目。该项目提供了包括SIFT特征点提取,基于kd-trees的特征匹配,以及基于RANSAC的图像之间几何变换关系解算等工具。
原始的OpenSIFT项目是基于Linux平台进行开发和编译。对于Windows平台的大多数用户而言,VisualStudio集成开发环境更适合于OpenSIFT项目的编译和研究工作。因此,本文介绍了基于VS2013开发环境的OpenSIFT工程配置和编辑的详细步骤。
2. 工具和依赖库
OpenSIFT项目是基于OpenCV进行开发,并且部分功能模块依赖GTK+2。因此,首先配置依赖库。其中,OpenCV可以直接从官网下载安装包,包括开发库和源代码(下载地址http://opencv.org/)。GTK+2的下载地址为http://www.gtk.org/,可以直接下载包括所有依赖库的压缩包。具体配置参见其官方文档。
本文将采用CMake创建VS2013的工程文件。原始的OpenSIFT项目仅仅包含SIFT算法相关的源码和Makefile文件。其中,Makefile文件介绍了整个项目的基本情况,包括项目模块划分,每一个模块源码组成情况。分析可知,改项目主要由四个部分组成,包括libopensift链接库和三个用于SIFT特征点提取、匹配和显示的可执行程序(siftfeat、match和dspfeat)。因此,按照工程的组织关系,本文编写了用于生成VS工程文件的CMakeList.txt文件。
Makefile文件中工程组织关系图
====================================================
CMAKE_MINIMUM_REQUIRED(VERSION2.6)
PROJECT(OpenSIFT)
#dependencies
SET(OPENCV_ROOT E:/opencv/build)
SET(GTK_ROOT D:/GTK)
INCLUDE_DIRECTORIES("${OPENCV_ROOT}/include""${OPENCV_ROOT}/include/opencv" "include")
LINK_DIRECTORIES("${OPENCV_ROOT}/x64/vc12/lib")
SET(LINK_LIBRARY_OPENCV
optimized opencv_core2411.lib debugopencv_core2411d.lib
optimized opencv_highgui2411.lib debugopencv_highgui2411d.lib
optimized opencv_imgproc2411.lib debugopencv_imgproc2411d.lib
)
SET(LINK_LIBRARY_GTK
${GTK_ROOT}/lib/gtk-win32-3.0.lib
${GTK_ROOT}/lib/gdk-win32-3.0.lib
)
############################################################################
#libopensift
SET(LIBOPENSIFTlibopensift)
ADD_LIBRARY(${LIBOPENSIFT}STATIC
src/imgfeatures.c include/imgfeatures.h
src/kdtree.c include/kdtree.h
src/minpq.c include/minpq.h
src/sift.c include/sift.h
src/utils.c include/utils.h
src/xform.c include/xform.h
)
SET_TARGET_PROPERTIES(${LIBOPENSIFT} PROPERTIES OUTPUT_NAME_DEBUG ${LIBOPENSIFT}d )
SET_TARGET_PROPERTIES(${LIBOPENSIFT} PROPERTIES OUTPUT_NAME_RELEASE ${LIBOPENSIFT} )
TARGET_INCLUDE_DIRECTORIES(libopensiftPUBLIC
"${GTK_ROOT}/include"
"${GTK_ROOT}/include/gtk-3.0"
"${GTK_ROOT}/include/cairo"
"${GTK_ROOT}/include/pango-1.0"
"${GTK_ROOT}/include/atk-1.0"
"${GTK_ROOT}/include/pixman-1"
"${GTK_ROOT}/include/freetype2"
"${GTK_ROOT}/include/libpng15"
"${GTK_ROOT}/include/gdk-pixbuf-2.0"
"${GTK_ROOT}/include/glib-2.0"
"${GTK_ROOT}/lib/glib-2.0/include"
)
TARGET_LINK_LIBRARIES(libopensift${LINK_LIBRARY_OTHERS})
SET(LINK_LIBRARY_SIFT
optimizedE:/SIFT/opensift/lib/${LIBOPENSIFT}.lib debugE:/SIFT/opensift/lib/${LIBOPENSIFT}d.lib
)
SET(LINK_LIBRARY_OTHERS${LINK_LIBRARY_GTK} ${LINK_LIBRARY_OPENCV})
SET(LINK_LIBRARY_ALL${LINK_LIBRARY_GTK} ${LINK_LIBRARY_OPENCV} ${LINK_LIBRARY_SIFT})
############################################################################
#siftfeat
SET(SIFTFEATsiftfeat)
ADD_EXECUTABLE(${SIFTFEAT}
src/siftfeat.c
include/getopt.h
src/getopt.c
)
TARGET_LINK_LIBRARIES(${SIFTFEAT}${LINK_LIBRARY_ALL})
SET_TARGET_PROPERTIES(${SIFTFEAT} PROPERTIES OUTPUT_NAME_DEBUG ${SIFTFEAT}d )
SET_TARGET_PROPERTIES(${SIFTFEAT} PROPERTIES OUTPUT_NAME_RELEASE ${SIFTFEAT} )
############################################################################
#match
SET(MATCHmatch)
ADD_EXECUTABLE(${MATCH}
src/match.c
include/getopt.h
src/getopt.c
)
TARGET_LINK_LIBRARIES(${MATCH}${LINK_LIBRARY_ALL})
SET_TARGET_PROPERTIES(${MATCH} PROPERTIES OUTPUT_NAME_DEBUG ${MATCH}d )
SET_TARGET_PROPERTIES(${MATCH} PROPERTIES OUTPUT_NAME_RELEASE ${MATCH} )
############################################################################
#dspfeat
SET(DSPFEATdspfeat)
ADD_EXECUTABLE(${DSPFEAT}
src/dspfeat.c
include/getopt.h
src/getopt.c
)
TARGET_LINK_LIBRARIES(${DSPFEAT}${LINK_LIBRARY_ALL})
SET_TARGET_PROPERTIES(${DSPFEAT} PROPERTIES OUTPUT_NAME_DEBUG ${DSPFEAT}d )
SET_TARGET_PROPERTIES(${DSPFEAT} PROPERTIES OUTPUT_NAME_RELEASE ${DSPFEAT} )
====================================================
3. 配置和编译
根据编写的CMakeList.txt文件,利用CMake配置生成VS2013的工程文件。根据实际需求,可以配置为其他版本的工程文件。
打开生成的工程文件,首先编译libopensift工程。本项目将该工程设置为静态连接库。原始的OpenSIFT项目基于Linux平台进行开发。因此,存在一些缺少头文件或者函数没定义的错误。根据编译情况修改一下错误:
-
在utils.h中添加一行#defineinline__inline
-
“srandom”,"random”未定义:将xform.c中的srandom改为srand,random改为rand。
-
常量表达式:C语言中不支持动态数组。
将下面两行
const int _intvls = intvls;
double sig[_intvls+3], sig_total, sig_prev, k;
修改为
double *sig = (double *)calloc(intvls + 3,sizeof(double));
double sig_total, sig_prev, k;
并在函数返回前添加free(sig); 释放资源。
-
在imgfeatures.h中加入一行
-
在utils.c中,将snprintf改为_snprintf
-
缺少dirent.h头文件。
从网站(http://www.softagalleria.net/dirent.php)下载该头文件,并放在include目录下。
经过以上步骤,libopensift工程编译完成,将debug和release下的libopensiftd.lib和libopensift.lib拷贝到lib文件加下,作为其他三个工程的依赖库。
编译siftfeat、match和dspfeat三个工程,发现缺少unistd.h头文件,该文件为linux平台下的头文件。从网站拷贝拷贝该头文件的内容,新建unistd.h,并添加到include目录。
unistd.h
http://stackoverflow.com/questions/341817/is-there-a-replacement-for-unistd-h-for-windows-visual-c
同时,unistd.h依赖getopt.h和getopt.c文件。同样,从相应网站下载,并分别添加到include和src目录。
getopt.h
http://www.opensource.apple.com/source/bc/bc-21/bc/h/getopt.h
getopt.c
http://www.opensource.apple.com/source/bc/bc-21/bc/lib/getopt.c
经过以上步骤,完成OpenSIFT整个项目的配置和编译。运行debug或者release目录的程序。其中,match的执行结果。
4. 参考资料
[1]http://www.cnblogs.com/cql/archive/2013/05/23/3095749.html
[2]http://en.wikipedia.org/wiki/Scale-invariant_feature_transform
[3]http://www.cs.ubc.ca/~lowe/keypoints/
[4]http://robwhess.github.io/opensift/