结构化的室内场景建模_输入数据

  • 2019 年 10 月 7 日
  • 筆記

上篇文章对 Structured Indoor Modeling 这篇论文做了介绍。该文章在学术上和工业上都有充分的应用,而且这也是我的博士课题,我对这一领域了解非常充分。所以在后续的文章中,我将极其详细的讲解这篇论文。

对于任何一个算法,我们首先应该知道该算法的输入是什么。Structured Indoor Modeling 输入一个场景的全部点云。该论文网站开放了部分数据,我也下载下来了。看一下其中一组数据。

画面右端输入的是使用 Matterport 设备拍摄的 全景 RGB-D 图像。可以看到画面左端把点云逐个拼起来的过程,在我的程序中处理的就是这组数据。

Matterport 拍摄的过程如下。

客户在一个三脚架上架上 Matterport 这个设备。然后 Matterport 原地旋转 360 度,拍摄一张 全景 RGB-D 图片。

我们可以看到 Matterport 的构造,由三个深度摄像头组成,关于深度摄像头的介绍,我在之前的文章中介绍了目前最好的深度摄像头 Azure Kinect

深度摄像头 Azure Kinect 介绍 无雨森,公众号:无雨森的技术分享KinectAzureDK编程实战_用OpenCV、PCL操作和可视化Kinect数据

这三个摄像头分别拍摄上中下的场景,让每次拍摄都能覆盖到整个场景。

如上Gif,这是一张 全景 RGB-D 图片转成的点云。

类似于这种多个深度摄像头构成的模组,我们需要标定这几个摄像头之间的相对姿态。每次拍摄,只需要把这三个深度摄像头的点云拼接起来即可。关于如何标定相对姿态,请看我之前发表的文章。

标定多组深度摄像头 无雨森,公众号:无雨森的技术分享KinectAzureDK编程实战_实时双Kinect标定

该论文开放的数据是用文本格式保存的 ply 文件。

ply  format ascii 1.0  comment created by MATLAB plywrite  element vertex 309156  property int height  property int width  property float x  property float y  property float z  property uchar red  property uchar green  property uchar blue  property float nx  property float ny  property float nz  property uchar intensity  end_header  0 0 0 0 0 0 0 0 0 0 0 0 [The camera position (XYZ in the global coordinate system)]  1 1 -22.3002 6.98361 1148.76 0 0 0 -0.0305268 0.09118 -0.995366 135 [1x2 u-v pixel index on the panorama] [1x3 3-d coordinate] [1x3 RGB color] [1x1 sensir intensity]  2 1 -20.0256 2.51624 1148.82 0 0 0 0.0422516 -0.0506529 -0.997822 135 [same as above]  3 1 -17.7198 -1.94781 1146.86 0 0 0 0.0557792 -0.0773581 -0.995442 136  4 1 -15.4755 -6.41863 1148.88 0 0 0 0.0735129 -0.112192 -0.990964 137  .....

如上为 ply 中保存的格式。我们一行一行的看。

ply  format ascii 1.0  comment created by MATLAB plywrite

这几行表示这里的 ply 文件是用文本格式保存的,而且是由 Matlab 的 plywrite 函数输出的。

element vertex 309156

这一行表示该 ply 文件中包含 309156 个点。

property int height  property int width  property float x  property float y  property float z  property uchar red  property uchar green  property uchar blue  property float nx  property float ny  property float nz  property uchar intensity

这里说明的是 ply 中保存的每一行数据包含的内容。每一行表示每一个三维点。每个三维点包含如上这些信息:全景 RGB-D 中的像素位置 (px, py),三维坐标 (x, y z),颜色信息 (red, green, blue),法向量信息 (nx, ny, nz),光亮强度值 intensity(深度摄像头需要发出红外光斑,这是红外接收器捕捉到的场景的红外光亮强度)。

0 0 0 0 0 0 0 0 0 0 0 0 [The camera position (XYZ in the global coordinate system)]  1 1 -22.3002 6.98361 1148.76 0 0 0 -0.0305268 0.09118 -0.995366 135 [1x2 u-v pixel index on the panorama] [1x3 3-d coordinate] [1x3 RGB color] [1x1 sensir intensity]  2 1 -20.0256 2.51624 1148.82 0 0 0 0.0422516 -0.0506529 -0.997822 135 [same as above]  3 1 -17.7198 -1.94781 1146.86 0 0 0 0.0557792 -0.0773581 -0.995442 136  4 1 -15.4755 -6.41863 1148.88 0 0 0 0.0735129 -0.112192 -0.990964 137  .....

这里是最开始的那几个点。最重要的是,第一个点表示这个 ply 标识的点云获取设备所在的世界坐标系的位置,这里是 (0, 0, 0)。不要误以为这里没有标定好,其实别的点云的第一行数据可能是。

0 0 -1003.92 1635.75 -4.43258 0 0 0 0 0 0 0

另外,还需要说的是。Matterport 拍摄的点云是可以映射为一张 2D 的 全景 RGB-D 图像。

这是其中一个点云映射回全景彩色图像。刚才我们说到每一行数据都包含全景 RGB-D 中的像素位置 (px, py),根据这个像素位置就可以将点云映射回全景彩色图像。

熟悉 PCL 的小伙伴一定想到这不就是一个 organized 点云吗?关于 organized 点云,不熟悉的小伙伴可以看这篇 PCL 的官方文章。

Introduction to the organized point cloud http://pointclouds.org/documentation/tutorials/basic_structures.php#id11

organized 点云是可以映射为一张 2D 图像的点云。常见于深度摄像头的点云,每一张 RGB-D 图像都对应一个点云。这样的点云就是 organized。

在 PCL 中,organized 点云可以用更多更好的算法来处理。比如用 Bilateral Filter 对点云做过滤。

在我对这篇论文的实现过程,我使用 PCL 来处理点云。虽然 PCL 支持很多点云格式,但像这样包含这么多信息的数据格式,PCL 还无法支持。其实我们只需要按照 PCL 的代码自己声明一个数据格式即可。详情请见这篇文章。

Adding your own custom PointT type http://pointclouds.org/documentation/tutorials/adding_custom_ptype.php#adding-custom-ptype

namespace pcl  {      struct PointXYZRGBINormal;  }  #include "PointXYZRGBINormal.hpp"    POINT_CLOUD_REGISTER_POINT_STRUCT(pcl::PointXYZRGBINormal,      (float, x, x)      (float, y, y)      (float, z, z)      (float, normal_x, normal_x)      (float, normal_y, normal_y)      (float, normal_z, normal_z)      (uint32_t, rgba, rgba)      (float, intensity, intensity)      (float, curvature, curvature)  )

这是我声明的仅适用于这样格式的点云的数据类型。

PCL 的类、函数都是用 C++ 模板写的,我们只需要用这个数据格式,就可以使用绝大部分 PCL 函数来处理该点云。

但是,每次调试程序,都要把文本格式的点云输入到内存中,像我用的这组数据每次都要加载到内存中需要耗时 20 秒 左右。这对经常调试算法的我来说是无法忍受的。

为了加快加载速度。我对这些文本格式的点云做预处理。把文本格式的点云 ply 文件,转换为 PCL 独有的 PCD 格式,并且压缩为二进制格式的 pcd 文件。经过我的测试,每次加载这接近 1 G 的点云文件只需要 2~3 秒即可。而且这 2~ 3秒包含了 “提取文件”,“解压文件”两个过程。

后续文章,还要对这组数据进行初步的过滤,按照论文提供的过滤方法,我写了几个继承于 PCL 的 Filter 的点云过滤工具类。