背景:前面用了几篇文章来记录和总结了,我在研究bundlefusion过程中遇到的一些问题以及解决方法,本来想实现给bundlefusion输入先验轨迹,然后让其根据给定的轨迹进行重建,这样即便在环境比较恶劣的情况下,也可以使用给定的位姿完成重建任务,但是这段时间对bundlefusion有了新的认识,意识到这件事没有我想象的那么简单。bundlefusion的研究工作就要告一段落了,所以最后我对bundlefusion做一个大的总结,把网络上一些经典的文章,整合起来。
一、 首先是先明白bundlefusion的工作原理,当然要阅读他的论文,英文的论文也不是很难读,当然也可以看我师兄的总结文章:https://blog.csdn.net/fuxingyin/article/details/52921958,有了这篇文章,如果想了解的更具体,那么就认真阅读一遍,bundlefusion的论文,主要关注一下bf的优化机制。
二、 另外一个重点当然是读代码了,说实话代码我读的不是很通透,主要是参考这篇文章,https://zhuanlan.zhihu.com/p/86718461 了解了代码的脉络,在这里,我将在这篇文章的基础上添加一些细节,这样不仅让我自己对bf的代码有更加深刻的理解,同时也希望能给志同道合的小伙伴更加高效的学习bf的方法。
三、制作.sens数据集可以参考我前一段时间写的博客:https://blog.csdn.net/weixin_38636815/article/details/107694846
四、BundleFusion代码讲解
1. bundlefusion中的主要参数
bundlefusion工程中有很多参数,众多的参数被分到两个文件中,zParametersBundlingDefault.txt和zParametersDefault.txt。
在zParametersBundlingDefault.txt中重要参数如下:
- s_numLocalNonLinIterations = 2; //局部非线性优化迭代次数
- s_numLocalLinIterations = 100; //局部线性优化迭代次数
- s_numGlobalNonLinIterations = 3; //全局非线性优化迭代次数
- s_numGlobalLinIterations = 150; //全局线性优化迭代次数
在上面的这四个参数中,s_numLocalLinIterations 起到了关键的作用,下面是我在ICL_NUIM数据集上测试的几组参数的模型效果,也可以看出s_numLocalLinIterations 起到了重要的作用。
s_numLocalNonLinIterations = 1;
s_numLocalLinIterations = 1;
s_numGlobalNonLinIterations = 1;
s_numGlobalLinIterations = 1;
s_numLocalNonLinIterations = 1;
s_numLocalLinIterations = 50;
s_numGlobalNonLinIterations = 1;
s_numGlobalLinIterations = 1;
s_numLocalNonLinIterations = 1;
s_numLocalLinIterations = 1;
s_numGlobalNonLinIterations = 1;
s_numGlobalLinIterations = 100;
- s_downsampledWidth = 80;
- s_downsampledHeight = 60;
上面两个参数主要是用于Correspondence Filtering中的dense verification中,如果设置的不恰当,会导致在跟踪过程中,容易跟踪失败,导致重建的稠密模型确实。我测试自己的数据集时,使用的是kinectv2深度相机获取的960x540的图像,发现在测试一次采集的数据时,有很长一段距离跟踪失败,导致最终重建的模型确实一大块,我抱着试试看的态度,调试参数,在修改了这两个参数后,之前跟丢的部分竟然跟踪上了。所以要根据你实际使用的图像的分辨率来调节这两个参数。
在zParametersDefault.txt文件中
- s_maxNumKeysPerImage = 1024; //每一帧图像上检测的最多的sift特征点的个数。
- s_widthSIFT = 640;
- s_heightSIFT = 480;
- s_windowWidth = 640; //render window width
- s_windowHeight = 480;
- s_integrationWidth = 320; //input depth gets re-sampled to this width (decrease to improve perf.)
- s_integrationHeight = 240; //input depth gets re-sampled to this height (decrease to improve perf.)
- s_rayCastWidth = 320; //should be same as integration except if rendering video
- s_rayCastHeight = 240;
上面这些跟输入的图像的分辨率有关的参数也一定要根据自己使用的数据来响应的修改。
2. 不怕大家见笑,我刚开始读orb-slam2代码的时候,过了好久才想到,我还一直没有去看程序的主函数呢?哈哈,现在想想这真是作为程序员的耻辱。以后无论读什么代码我都必须先找到main函数,然后去先捋清楚代码的主干脉络,并且使用xmind软件将代码的思维导图画出来,这样整个工程的主干就很清楚了。
- main() FriedLiver:程序入口
- g_RGBDSensor = getRGBDSensor();//根据你设置的s_sensorIdx来判断你输入的数据的形式,是深度相机还是.sens文件。
- g_RGBDSensor->createFirstConnected(); //这个函数主要是读取输入的.sens文件中的数据,彩色图,深度图,pose,还有info.txt
- std::thread bundlingThread(bundlingThreadFunc); //开启多线程,进行跟踪和优化。
- std::thread(bundlingOptimizationThreadFunc);
- bundlingOptimization();
- g_bundler->process()
- optimizeLocal()
- processGlobal()
- optimizeGlobal()
- g_bundler->process()
- bundlingOptimization();
- std::thread(bundlingOptimizationThreadFunc);
- startDepthSensing(g_bundler, getRGBDSensor(), g_imageManager); //重建
- startDepthSensing
- OnD3D11FrameRender
- bool bGotDepth = g_CudaImageManager->process(); // Read Input
- reintegrate(); //更新模型,包括:deintegrate和integrate
- integrate(depthCameraData, transformation); //Reconstruction of current frame
- Render
- StopScanningAndExit(); //这个函数中实现将计算的位姿保存的.sens中的pose数据,并且生成.ply模型
- OnD3D11FrameRender
- OnlineBundler
- OnlineBundler()
- m_bHasProcessedInputFrame=false
- m_bExitBundlingThread=false
- m_lastFrameProcessed = -1
- getCurrentFrame()
- processInput()
- Bundler::detectFeatures()
- Bundler::storeCachedFrame()
- Bundler::matchAndFilter()
- process()//BundleFusion Optimization
- optimizeLocal()
- processGlobal()
- optimizeGlobal()
- OnlineBundler()
- Bundler
- detectFeatures() //检测图像sift特征点
- storeCachedFrame() //缓存数据
- matchAndFilter() //匹配和过滤当前帧和之前所有帧的sift特征点,计算3D点。
- optimize() //稀疏点优化
- CUDASolverBundling 求解器
BundleFusion代码对于我来说还是太庞大了,在短时间内很难吃透很多细节,这一阶段的bundlefusion的研究就暂时告一段落了,如果以后有机会,重新开始研究他。