SLAM拾萃(3):siftGPU

前言

  本周博客我们给大家介绍一下SiftGPU。由于特征匹配是SLAM中非常耗时间的一步,许多人都想把它的时间降至最短,因此目前ORB成了非常受欢迎的特征。而老牌SIFT,则一直给人一种“很严谨很精确,但计算非常慢”的印象。在一个普通的PC上,计算一个640$\times$480的图中的SIFT大约需要几百毫秒左右。如果特征都要算300ms,加上别的ICP什么的,一个SLAM就只能做成两帧左右的速度了,这是很令人失望的。而ORB,FAST之类的特征,由于计算速度较快,在SLAM这种实时性要求较高的场合更受欢迎。

  那么,今天我们来说一个GPU版本的SIFT。它是由Wu Changchang同学写的。它能够明显地提升你的程序提取SIFT的速度。同时,它的代码大部分是基于OpenGL的,即使在没有英伟达显卡的机器上也能运行起来。但另一方面,出于某种(历史或人为的)原因,SiftGPU的代码配置起来并不很容易(特别是在Linux下,似乎SiftGPU作者是在win下开发的),代码新人可能会觉得比较困难。现在我们带着大家实践一下SiftGPU,我会给出一个例程供大家测试。

  首先,说说我的运行配置。我用的机器是Thinkpad T450, Intel+Nvidia GetForce 940m显卡。但我个人只用Intel卡,所以我就不编译Cuda了。各位有上好N卡的同学也可以搞个Cuda下来编,可能会提高一点速度(但我不保证)。我使用的操作系统是Ubuntu 14.04,OpenCV3.1版本。所以我假设你OpenCV已经装好啦!(所以c++编译器总有的吧!) 不过opencv是不是3.1版本是没关系的,程序在2.x版本上也是能正常运行的。

  小萝卜:师兄你这真是宅男标配啊!你到底是在讲配置环境还是在秀桌面啊!


下载SiftGPU与依赖库

  SiftGPU主页:http://www.cs.unc.edu/~ccwu/siftgpu/

  请找到“SiftGPU-V400"那个下载链接,保存到你的电脑上。然后解压缩,进入压缩后的文件夹。假定你也在用Ubuntu,那么你现在的目录应该是 ~/Downloads/SiftGPU/ 。注意,为了和我保持一致,请你暂时不要下载github上面那个版本,那个与它稍有不同。如果你就是喜欢github,可以把这个编译好,再考虑用github版本。

  现在我们来安装依赖项。首先,确保你机器上有OpenGL,请安装以下几项工具:

1 sudo apt-get install libgl1-mesa-dev libglu1-mesa-dev freeglut3-dev 

  然后,要安装glew1.5.1以上版本。据我个人经验,最好是去下载glew网站的版本。

  glew的网址:http://glew.sourceforge.net/

  请下载那个1.13.0版本,zip文件或tgz均可。下载到本地并解压,然后进入该文件夹。我的在~/Downloads/glew-1.13.0

  glew是用makefile直接编译的,不用cmake。所以我们直接敲:

1 make
2 sudo make install 

  即可。很快它就编译好了。

  注意看make install输出的信息。它默认把编译好的库文件libglew.so.1.13放到了/usr/lib64下。由于之后我们要用cmake去编,但是它可能找不到这个文件夹,所以我们现在先告诉系统,该文件夹下有要找的链接库:  

1 sudo ldconfig /usr/lib64/

  ok,现在我们处理完了glew,转去编译SiftGPU。SiftGPU也是用Makefile编译的。现在转到SiftGPU所在文件夹。调用

1 make

  来完成编译。如果顺利的话,你会在bin/目录里得到几个二进制和一个libsiftgpu.so库文件。我们主要使用这个库文件。现在看一下它的链接是否正确:

1 ldd bin/libsiftgpu.so

  这个命令会输出与它链接的库的信息。请保证没有出现某个链接(特别是刚才的GLEW)没有找到的情况(否则这里会通过,但后面会出现undefined reference)。像我这样:

  如果这步正确无误,恭喜你,SiftGPU已经编译完成了!真是可喜可贺呀!

  小萝卜:然后呢?师兄我还没看到什么感觉很厉害的东西啊?

  师兄:下面我们来实际找一个图片,写一段小程序调用SiftGPU,提一下特征试试。为测试速度,我们还要记录一下代码运行时间。


测试SiftGPU

  现在我们来写一个测试程序。由于它比较短,我就不专门搞个github了。请大家跟着我做即可。

  首先,随意新建一个目录,比如test_siftgpu。我们要写一个c++程序,然后用cmake编译它。现在新建一个main.cpp,内容如下:

 1 // SiftGPU模块
 2 #include <SiftGPU.h>
 3
 4 //标准C++
 5 #include <iostream>
 6 #include <vector>
 7
 8 // OpenCV图像
 9 #include <opencv2/core/core.hpp>
10 #include <opencv2/highgui/highgui.hpp>
11
12 // boost库中计时函数
13 #include <boost/timer.hpp>
14
15 // OpenGL
16 #include <GL/gl.h>
17
18 using namespace std;
19
20 int main( int argc, char** argv)
21 {
22     //声明SiftGPU并初始化
23     SiftGPU sift;
24     char* myargv[4] ={ "-fo", "-1", "-v", "1"};
25     sift.ParseParam(4, myargv);
26
27     //检查硬件是否支持SiftGPU
28     int support = sift.CreateContextGL();
29     if ( support != SiftGPU::SIFTGPU_FULL_SUPPORTED )
30     {
31         cerr<<"SiftGPU is not supported!"<<endl;
32         return 2;
33     }
34
35     //测试直接读取一张图像
36     cout<<"running sift"<<endl;
37     boost::timer timer;
38     //在此填入你想测试的图像的路径!不要用我的路径!不要用我的路径!不要用我的路径!
39     sift.RunSIFT( "/home/xiang/wallE-slam/data/rgb1.png" );
40     cout<<"siftgpu::runsift() cost time="<<timer.elapsed()<<endl;
41
42     // 获取关键点与描述子
43     int num = sift.GetFeatureNum();
44     cout<<"Feature number="<<num<<endl;
45     vector<float> descriptors(128*num);
46     vector<SiftGPU::SiftKeypoint> keys(num);
47     timer.restart();
48     sift.GetFeatureVector(&keys[0], &descriptors[0]);
49     cout<<"siftgpu::getFeatureVector() cost time="<<timer.elapsed()<<endl;
50
51     // 先用OpenCV读取一个图像,然后调用SiftGPU提取特征
52     cv::Mat img = cv::imread("/home/xiang/wallE-slam/data/rgb1.png", 0);
53     int width = img.cols;
54     int height = img.rows;
55     timer.restart();
56     // 注意我们处理的是灰度图,故照如下设置
57     sift.RunSIFT(width, height, img.data, GL_INTENSITY8, GL_UNSIGNED_BYTE);
58     cout<<"siftgpu::runSIFT() cost time="<<timer.elapsed()<<endl;
59
60     return 0;
61 }

  Sift接口还是相当简单的。在这程序里,我们一共做了三件事。一是直接对一个图像路径提Sift,二是获取Sift的关键点和描述子。三是对OpenCV读取的一个图像提取Sift。我们分别测了三者的效果和时间。

  接下来,写一个CMakeLists.txt来编译上面的文件。

cmake_minimum_required(VERSION 2.8.3)
project(test_siftgpu)

# OpenCV依赖
find_package( OpenCV REQUIRED )

# OpenGL
find_package(OpenGL REQUIRED)

# GLUT
find_package(GLUT REQUIRED)

# Glew
find_package(Glew REQUIRED)

# SiftGPU:手动设置其头文件与库文件所在位置
include_directories("/home/xiang/Downloads/SiftGPU/src/SiftGPU/" ${OpenGL_INCLUDE_DIR})
set(SIFTGPU_LIBS "/home/xiang/Downloads/SiftGPU/bin/libsiftgpu.so")

add_executable( testSIFTGPU main.cpp )

target_link_libraries( testSIFTGPU
    ${OpenCV_LIBS}
    ${SIFTGPU_LIBS}
    ${GLEW_LIBRARIES} ${GLUT_LIBRARIES} ${OPENGL_LIBRARIES}
)

  对于SiftGPU,由于它本身没有提供cmake的配置,我们手动去设置了它的头文件与库文件的链接方式。大家可以学习一下这种比较土的办法……然后就是常见的cmake啦:

mkdir build
cd build
cmake ..
make

  等一下!是不是还忘了些什么呢?嗯,如果你直接去cmake的话,会报一个find_package找不到glew的错!因为我们装glew的时候是直接用make install装的嘛,cmake怎么会知道我们干了这件事呢?所以此时find_package(Glew REQUIRED)就会出错啦!

  小萝卜:为什么出错了你还是很高兴的样子……

  师兄:对!现在呢我们要自己写一个FindGlew.cmake文件喽。请打开你的编辑器,输入:

 1 #
 2 # Try to find GLEW library and include path.
 3 # Once done this will define
 4 #
 5 # GLEW_FOUND
 6 # GLEW_INCLUDE_PATH
 7 # GLEW_LIBRARY
 8 #
 9
10 IF (WIN32)
11     FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
12         $ENV{PROGRAMFILES}/GLEW/include
13         ${PROJECT_SOURCE_DIR}/src/nvgl/glew/include
14         DOC "The directory where GL/glew.h resides")
15     FIND_LIBRARY( GLEW_LIBRARY
16         NAMES glew GLEW glew32 glew32s
17         PATHS
18         $ENV{PROGRAMFILES}/GLEW/lib
19         ${PROJECT_SOURCE_DIR}/src/nvgl/glew/bin
20         ${PROJECT_SOURCE_DIR}/src/nvgl/glew/lib
21         DOC "The GLEW library")
22 ELSE (WIN32)
23     FIND_PATH( GLEW_INCLUDE_PATH GL/glew.h
24         /usr/include
25         /usr/local/include
26         /sw/include
27         /opt/local/include
28         DOC "The directory where GL/glew.h resides")
29     FIND_LIBRARY( GLEW_LIBRARY
30         NAMES GLEW glew
31         PATHS
32         /usr/lib64
33         /usr/lib
34         /usr/local/lib64
35         /usr/local/lib
36         /sw/lib
37         /opt/local/lib
38         DOC "The GLEW library")
39 ENDIF (WIN32)
40
41 IF (GLEW_INCLUDE_PATH)
42     SET( GLEW_FOUND 1 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise")
43 ELSE (GLEW_INCLUDE_PATH)
44     SET( GLEW_FOUND 0 CACHE STRING "Set to 1 if GLEW is found, 0 otherwise")
45 ENDIF (GLEW_INCLUDE_PATH)
46
47 MARK_AS_ADVANCED( GLEW_FOUND )

  然后呢,把这个文件放到cmake的modules文件夹中去!这样cmake就会知道你在调用find_package(Glew)时怎么找啦!

sudo cp ./FindGlew.cmake /usr/share/cmake-2.8/Modules/

  注意到这个文件所在的目录通常是没有写权限的的哦!所以我们要用sudo提升到管理员权限才行呢。

  这时,再调用cmake ..,就不会报上面的错误啦!而编译也得以顺利进行下去了。

  但是!但是!编译还是出错了,错误如下:

/home/xiang/Downloads/SiftGPU/src/SiftGPU/SiftGPU.h:336:40: error: declaration of ‘operator new’ as non-function SIFTGPU_EXPORT void* operator new (size_t size);

  这是什么原因呢?g++的编译错误很难懂,一直为人诟病。师兄仔细查了查,发现SiftGPU作者重载了new运算符,但是它的参数"size_t size"中的"size_t"类型,在linux下编译是需要指定一个头文件的!所以我们打开~/Downloads/SiftGPU/src/SiftGPU/SiftGPU.h文件,在上头加入一个

#include <stddef.h>

 

  这样编译器就会找到size_t类型啦!编译就能通过喽!


SiftGPU运行结果

  以下就是在师兄电脑上的运行结果啦,大家可以看一下:

  对于OpenCV已经读入的数据,在640x480的分辨率下,用SiftGPU只需40多毫秒即可完成计算了呢!GPU真的是很强大啊!即使在没有Cuda的情况下都取得了近十倍的加速啊!效果拔群!

  小萝卜:我的ORB只要30毫秒就行了,哼.


小结

  本篇介绍了SiftGPU,我们带领读者完成了它的编译,并在自己的程序内实现了调用。可以看到它的加速效果还是不错的!

  另外,这也是我的一次尝试,告诉读者在编译过程中遇到问题该如何处理。我本可以直接跳过这些buggy的部分,告诉大家运行的结果。但我觉得这样子讲可能对读者更有帮助啦!



  如果你觉得我的博客有帮助,可以进行几块钱的小额赞助,帮助我把博客写得更好。

  

时间: 2024-10-26 02:26:11

SLAM拾萃(3):siftGPU的相关文章

SLAM拾萃(2):doxygen

今天给大家介绍一下doxygen.这个工具由来已久了,至少08年左右就已经在用了,但是目前还没见到好的介绍.我个人觉得这是个很简单易用的工具,但是为什么看了别人介绍反而觉得复杂了……所以趁着今天比较闲就来说一说它. doxygen是一个自动文档生成工具,根据代码里写的注释,自动生成html和latex格式的文档.通常是给c++用的,通常是出html格式的,你看到的pcl网上文档就是拿doxygen生成的. 事实上,随意一份代码,都可以拿doxygen生成一个文档,然后在本地看它的代码结构. 我们

(2)RGB-D SLAM系列- 工具篇(依赖库及编译)

1)Library depended 一个完整的SLAM系统包括,数据流获取,数据读取,特征提取,特征匹配,POSE恢复,回环检测,全局优化,数据可视化,系统界面等,基于此列出SLAM系统所需依赖的库,同时会发布各个库的编译方式以及对各个库联合编译时出现的问题提出解决方案. Eigen Eigen库有效支持线性代数,矩阵和矢量运算,数值分析及其相关的算法 Eigen 3.0, Download website: http://eigen.tuxfamily.org/index.php?title

rgbd slam V2 demo 实现

经过一番努力,终于跑通了felix.endres的rgbd slam v2 源码,中间遇到挺多问题.总结如下:(1) 关于SiftGPU问题:ERROR: SiftGPU cannot be compiled将源码中CMakeLists.txt中第6行:set(USE_SIFT_GPU  1 CACHE BOOL "build with support for siftgpu") 中的1换成0,暂不调用SiftGPU.(2)关于ERROR: cannot launch node of

视觉SLAM实战(一):RGB-D SLAM V2

写在前面 首先打个广告.SLAM研究者交流QQ群:254787961.欢迎各路大神和小白前来交流. 看了前面三篇博文之后,是不是有同学要问:博主你扯了那么多有用没用的东西,能不能再给力一点,拿出一个我们能实际上手玩玩的东西啊?没错,接下来我们就带着大家,实际地跑一下视觉SLAM里的那些经典程序,给大家一个直观的印象——因此博文就叫"视觉SLAM实战"啦.这些程序包括: RGBD SLAM V2 SVO KinectFusion Orb-SLAM 如果你有什么建议,可以发我的邮件或来群里

[摘抄] SFM 和 Visual SLAM

SFM和vSLAM基本讨论的是同一问题,不过SFM是vision方向的叫法,而vSLAM是robotics方向的叫法, vSLAM所谓的mapping,我们vision方向叫structure,vSLAM所谓的location,我们vision方向叫camera pose. 但是从出发点考虑的话,SFM主要是要完成3D reconstuction,而vSLAM主要是要完成localization. 从方法论的角度上考虑的话,传统的SFM是不要求prediction的,但是对于vSLAM而言pre

杨森翔:春节文化大观上编 第三章 春节古诗词 目录 第一节:春节诗词概述 一、 除夕诗词概述 二、元日诗词概述 三、 元宵诗词概述 第二节:春节古诗词拾萃

杨森翔:春节文化大观上编 第三章 春节古诗词 目录 第一节:春节诗词概述 一. 除夕诗词概述 二.元日诗词概述 三. 元宵诗词概述 第二节:春节古诗词拾萃 一.腊祭诗词 二.祭灶诗词 三.除夕诗词 四.元旦诗词 五.人日诗词 六.元宵诗词 第一节:春节古诗词概述 中国的春节,作为除旧迎新的节日,时间相当长,从年前的腊月二十三,天空中就似乎弥漫了节日的气息.这种节日的气氛,在保持传统风俗较好的地方,甚至会持续到二月二龙抬头的时候,但欢度春节的高潮,应该说是自除夕始一直到上元之夜.因此,历代歌咏和反

图优化在slam中的应用——柏拉图启示录

南山学长在纸上写下了一个公式: e=z-h(x) 小K:这是什么?南山学长:这是一个蕴含了宇宙的终极奥秘的公式.小K:怎么可能?太离谱了,这只是一个普通的公式!南山学长:那好你用尺子测量一下纸上的这条直线有多长.小K(一脸疑惑的):3.55cm南山学长:你何以如此确信这条直线就是3.55cm,我是说它可能介于3.55和3.56之间,如果你再把图像放大,也许就能精确到小数点后三位.小K(想了想):恩,是这样的,放的越大得到的数据就越精确.南山学长:那么问题来了,这条直线必然存在一个精确的长度,而且

视觉SLAM漫淡(二):图优化理论与g2o的使用

视觉SLAM漫谈(二):图优化理论与g2o的使用 1    前言以及回顾 各位朋友,自从上一篇<视觉SLAM漫谈>写成以来已经有一段时间了.我收到几位热心读者的邮件.有的希望我介绍一下当前视觉SLAM程序的实用程度,更多的人希望了解一下前文提到的g2o优化库.因此我另写一篇小文章来专门介绍这个新玩意. 在开始本篇文章正文以前,我们先来回顾一下图优化SLAM问题的提法.至于SLAM更基础的内容,例如SLAM是什么东西等等,请参见上一篇文章.我们直接进入较深层次的讨论.首先,关于我们要做的事情,你

从0开始Ubuntu slam cmake....

工作XX年了,对于LINUX是小白...无需喷,我早已无地自容. 最近工作需要应用研发slam,不得不承认这一前沿技术仍旧多数在老外手里.目前了解到的有orb-slam .rtab map slam.catographer,都是在LINUX平台. 第一次装好ubuntu的时候,我连源是什么都不知道,cmake更是一知半解. 只能一步一步来. 准备工作 1.ubuntu-14.04.4-desktop-amd64.iso http://old-releases.ubuntu.com/release