我们之前的讨论,基本集中于“稀疏路标地图”部分,还没有探讨稠密地图。
稀疏地图只建模感兴趣的部分,也就是前面说了很久的特征点(路标点)。而稠密地图是指建模所有看到过的部分。
对于同一张桌子,稀疏地图可能只建模了桌子的四个角,而稠密地图则会建模整个桌面。虽然从定位角度看,只有四个角的地图也可以用于对相机进行定位,但由于我们无法从四个角推断这几个点之间的空间结构,所以无法仅用四个角完成导航、避障等需要稠密地图才能完成的工作。
所以这一章主要讲如何建立稠密地图。
主要有三个方案:
- 1.使用单目相机,估计相机运动,并且三角化计算像素的距离。
- 2.使用双目相机,利用左右目的视差计算像素的距离(多目原理相同)。
- 3.使用RGB-D相机直接获得像素距离。
前两种方法,使用单目或者多目——计算量巨大,最后得到一些不怎么可靠的深度估计。
当然,RGB-D也有一些量程、应用范围和光照的限制,不过相比于单目和双目的结果,使用RGB-D进行稠密重建往往是更常见的选择。
而单目、双目的好处是,在目前RGB-D还无法被很好地应用的室外、大场景场合中,仍能通过立体视觉估计深度信息。
emmm,虽然单目建图不咋地,但是呢,我们还是建一遍,感受一下。
单目稠密重建
主要用到的方法是:极线搜索和块匹配
极线呢,是极平面O1O2P 与两个成像平面I1 I2的交线。(我用红色箭头指的)
知道相机的运动后,就知道了极线
我们可能沿着第二幅图像中的极线的某一头走到另一头,逐个比较每个像素与p1的相似程度。
哪个比较像,就找到p2。这就叫极线搜索。
然后呢,我们前边学了也知道,比较一个像素不可靠,有很多像素都差不多的,所以我们划定一个范围,比较像素块。这就叫块匹配。
说到块匹配,还要介绍一个东西。如何比较两个小块之间的相似程度?有如下三个方法:
这里以NCC为例,我们为了比较小块与小块之间的相似度,将得到一个沿着极线的NCC分布。这个分布的形状取决于图像数据,
在搜索距离较长的情况下,通常会得到一个非凸函数。这个分布存在许多峰值,然而真实的对应点必定只有一个。在这种情况下,我们会倾向于使用概率分布描述深度值,而非用某个单一的数值来描述深度。于是,我们的问题就转到了在不断对不同图像进行极线搜索时,我们估计的深度分布将发生怎样的变化——这就是所谓的深度滤波器。
关于深度滤波器的具体推导内容,看书就好了。
这里放出结论:
代码实践:单目稠密深度重建
先去下载数据集:250多M
下好了复制到这一章节文件夹下
http://rpg.ifi.uzh.ch/datasets/remode_test_data.zip
编译的时候,报错,说找不到octomap这个包。
所以先需要安装这个库,地址如下
git clone https://github.com/OctoMap/octomap.git
再编译程序,又报错了
他说surfel_mapping.app里有一个错误
surfel_mapping.cpp:31:9: error: ‘class pcl::MovingLeastSquares<pcl::PointXYZRGB, pcl::PointXYZRGBNormal>’ has no member named ‘setPolynomialFit’; did you mean ‘setPolynomialOrder’?
说这个函数不是pcl的成员,但是她就是pcl的成员,那就还是说明这个东西没安装好
后来发现我太傻了,书上都说了怎么安装
sudo apt-get install liboctomap-dev octovis
然后试了好多方法都不行,最后我放弃了
我先不跑这个surfel_mapping.app代码了,先跑别的。所以把报错的那一句注释了
执行这个代码,传入参数就是我们刚才下载的数据
但是要注意: 需要写 ../../test_data 因为编译出来的文件和测试数据隔了两层
运行结果:迭代了几次之后,虚拟机直接卡死了(可能是我电脑太老了)
关机前的遗照,有四个图像显示出来,截图就截了两个 迭代68次