现在的位置: 首页 > 综合 > 正文

Testing Davison’s MonoSLAM

2013年09月10日 ⁄ 综合 ⁄ 共 4992字 ⁄ 字号 评论关闭

Testing Davison's MonoSLAM

半个月前从Davison的主页上下载了monoSLAM的源码,在ubuntu 6.10(gcc 4.1.2)上编译通过,并运行正常,最近又将它移植到windows平台,主要是考虑以后的兼容使用。其中有一些心得和经验,记录于此。

1. support usb camera under linux
Davison的代码只支持1394 camera,在linux下我先为其添加了USB camera支持. 这个工作其实也挺简单,参考VW34/VWFirewire和VW34/VWGLOW/Interface/*代码,写了个VWUSBCam接口,其中调用v4l2(2.6
kernel支持)API,这里又参考了spcaview中的代码,再修改一下makefile就行了,也就用了一天时间,麻烦的事情在于makefile的修改,automake生成的东东总是显得过于繁杂,手动修改起来比较烦。
sequence的工程机理是这样的:底层有一个循环,进行IO操作,不断地读取文件或摄像机数据;一旦得到数据后,发送消息给上层,上层调用响应消息的回调函数,在其中进行数据处理。 这样的循环式操作有一个弊端:CPU占用率一直比较高。特别是读取视频时,没有数据时也会一直在"空转"。不像MS的DirectShow,底层的WDM检测到数据信号时,自动发送消息通知上层,即中断式的操作。不过对于linux下的v4l2编程,目前还没有看到过支持中断方式视频捕获。

2.port to windows
移植往往是比较麻烦的工作,linux与windows的平台差异比较大。不过Oxford的VW4是cross platform的,并提供了VC7的project,monoslamglow和scenelib也是完全platform independent,并全用c++实现。这样的工作还是挺好的,我比较喜欢这样的方式,以前写的一些程序也都是这么处理的。
不过在移植过程中还是有一些问题。我使用的是VC2005,可能是目前最好的编译器与IDE了,对C++标准支持得很好,毕竟是Lippman领导设计的。这使得monoslam中大量的模板编译能够顺利通过。
首先需要编译glut和glow,是opengl的一些扩展工具,我使用的分别是glut-3.7.6和glow_104,编译中没有问题。
其次需要编译wxWidgets,目前有2.8.3,第一次尝试搞错了一些设计,出了错,便选用了2.6.4,也是一样的问题。后来分析了一下错误,再结合readme,明白了原因:需要设置一些宏,打开或关闭一些选项。顺利通过后也懒得换高版本了,2.6.4够用了。
现在便可编译VW34了,直接用其中的VC7 solution,并设置好前面几个库的路径,编译也可以通过,但在后来编译MonoSLAMGlow时,却有unresolved
link error,显然是找不到库的模块。回头再看VW34,发现了是因为有一些.cpp文件没有添加进solution,没有编译进lib,还有就是文件读取的几个template没实例化,手动加上就可以了(虽说简单,但找到错误却不容易,一开始没想到是这些问题~~)。在这里,gcc与vc2005似乎有比较大的差别,gcc似乎不合乎标准。
最后编译monoslamglow和scenelib。这两个没有现成的工程,monoslamglow其实就是scenelib中API的简单调用,负责一些界面处理,主要的vSLAM工作在scenelib中完成。直接将这两个模块放到了同一个project中,修改了一些头文件路径和gcc、vc2005的语言差别,最后也能编译完成,但冒出来很多multiple
symbols error,都是来自于VW34,像是VW34中已经定义了一些标准C++的库函数,如basic_string, vector之类,细查一下又没有,比较奇怪。google了一下,从VXL(一个比较好的computer
vision library,VW34中的VNL便是它的一个模块)的文档中找到了答案:C++编译编译选项设置不一致。solution如下:

Project->Settings->C/C++ Tab->Category: Code Generation->Use run-time library: Multithreaded DLL

于是编译就通过了,porting就初步完成了。

3. fix bugs
前面完成了移植工作,这只是一部分工作而已。程序在windows上读取Davison提供的test sequence,一会便出错了,而且是比较莫名的错误:基于wxWidget的窗口一重绘便出错。wxWidget的问题?若如此,便很麻烦了,不确定是wxWidget还是opengl或是基于opengl的glut、glow有bug,没精力去研读几十M的代码的~~
仍然编译了个debug版本,初步调试了一下,发现只是在窗口重绘时出问题。像一般的界面程序一样,重绘是基于消息的,消息又与回调函数挂钩。在调试中发现调用回调函数的对象指针失效了,这是失败的原因!深入VW32的底层代码,跟踪程序的过程,了解了它的处理方式:从一个带虚函数的EventHandler类派生出窗口子类,再利于EventHandler保存子类的句柄,回调时,由该句柄调用多态调用子类的重绘函数。一切看起来很合理,充分利用了C++的多态性。但EventHandler却在重绘时失效了。不可理解。
好看月前仔细阅读了,了解了C++一些底层的对象模型处理过程,对于虚拟继承内部错综复杂的关系也比较清楚了。很快便想到:基类指针失效应该是由于指针在对象转型时offset调整出了问题。这部分是编译器的工作,我们无法干预。这便又是gcc与vc2005的一个显著不同!看了一下MonoSLAMGlow类的声明:多重继承!4个类的多重继承!令人生畏的多重继承!其中EventHandler被放在第二个!这些类都有虚函数,很显然,也就会有多个虚函数表,指针调整时也会比较复杂。从理论上来说,EventHandler应该设计成抽象类,并作为公有虚拟基类,这样便不会有上述问题。我采用了一个比较简单的修改方案:将EventHandler设为第一个继承类,因为不是虚拟基类,它的地址便是MonoSLAMGlow的地址(vc2005中是这么处理的),不再需要指针调整,快速、方便而又正确!就是这么一个问题,真是得感谢Lippman,难怪侯捷竭力推荐他的这本书,很有道理。
紧接着便是第二个错误:运行一会程序会崩溃了。使用debug版本观察了一下,是vector出错了,看似是指针无效。这个错误很难找,整个工程大量使用了vector,无法定位是哪里出了问题。前段时间发现这个问题时,觉得一时难以下手,也正好在忙别的事,就此搁下了。昨晚又拿起来分析了一下,初步判定是monoslamglow中的问题。今天花了一天时间调试,才找到这个问题所在。真是个非常隐晦而又阴暗的错误!当然,也怪我一时疏忽了,话说过来,这种bug若非亲历并尝过艰辛,是不可能想到并很快发现的,虽然我早就知道bug原因和解决方法~~建议使用STL的程序员都好好读读scott
meyer的effective stl,唉,其实我已经读过两遍了~~
这个bug便是vector::erase便得基于vector的所有iterator都失效了!很简单的理由,在effective stl中反复说了好几遍。比如程序中有这样的一段代码:
for(vector::iterator feat = feature_init_info_vector.begin();
feat != feature_init_info_vector.end();feat ++)
{
if(feat->...){}
else{
delete_partially_initialised_feature(feat); // 调用vector::erase
}
}
看似没有问题,delete_partially_initialised_feature erase的是feat的一个副本,feat已经更新了。看过effective stl的人也都会这么说:这是meyer推荐的一个技巧啊,后置++返回旧值。其实不然,erase后,vector内存已经重新分配,以前的iterator都已经失效,因此更新后的feat实际是无效的,在下一次for比较中就会崩溃,错误提示为:incompatible iterator!一个我刚开始始终看不懂的错误。
修改方法就比较简单了,修改delete_partially_initialised_feature的原型,返回iterator,然后
feat = delete_partially_initialised_feature(feat)
即可。
注:程序中有三处这样的错误,需要一一修改。
gcc对于这个问题也没有出错。gcc使用的是sgi的stl,不知道底层是如何处理的,按理说不应如此。还可以说明一点的是:Davison(也有可能是其他人)的c++和stl水平不怎么样,不应该犯这样的错误的,嘿嘿!

update 1 : 2007-04-12
yet another bug of the same kind : incompatible iterator !
in Scene_single.cpp, line 301, delete_feature erases an item from feature vector and invalids all the iterators kept previously in the context, so in the next loop, the "incompatible iterator" error will jump out while comparing the iterators !
solution :
I subsitude the original prototype of delete_feature below

bool delete_feature()
with
std::vector::iterator delete_feature()

in fact, the latter conforms to the convention in STL, such as vector::erase, list::erase, etc.

update 2 : 2007-04-19
add usb camera support on both linux and windows !
It's quite interesting to run the demo with real environment.

4. conclusion
移植与修改这个程序还是很有意思的,有利于提高自己的程序水平。特别是使我们看到了大师提出的经典与意见是很有用的,经典著作不能不读!
另外,对于gcc,我也觉得比较有意思,上面发现的一些错误在gcc中完全正常,虽说有些地方不符合标准,但确实好用。还是比较喜欢gcc的。
写了这么多,觉得可以写封信给Davison了,report bugs to him and ask him to read some classic books on stl :)

5. forwards
以后再为monoslam加一个windows上的USB摄像头接口,那就可以做实验了。这倒是比较容易的,对于摄像头采集还是很熟的,今天就到此为止吧。
我还是比较喜欢在linux下写程序,工具比较丰富,也比较好玩,如emacs,eclipse之类的,只是不如windows中方便,因为vs2005的功能实在太强大了!不过支持开源、支持linux!

3 评论:

匿名 说...

学无止境!狗狗,加油!

dar6267 说...

您好,
我最近在研究monoslam這個演算法
想請問您,
要如何得知相機在任何時間下的position & rotation呢?

匿名 说...

您好~我想請問一下
我在ubuntu 10.04上作monoslam的編譯,可是我在編譯上一直會有錯誤,請問可以提供再linux上的完整步驟嗎?(如需要的套裝元件等等)

抱歉!评论已关闭.