CVPR2020中关于3D点云分割
点击上方“3D视觉工坊”,选择“星标”
干货第一时间送达
作者:不知道叫什么好 | 来源:知乎
https://zhuanlan.zhihu.com/p/152872040
本文仅做学术分享,如有侵权,请联系删除。
本文介绍一篇CVPR2020中关于点云分割的文章。目前,大部分点云文章主要研究的是,如何构建适用于点云的卷积操作,从而直接在3D点云上执行卷积,实现分类、分割、检测等任务。而这篇文章使用了完全不同的方法,其先将点云映射为2D图片(3D点与2D像素坐标一一对应),然后直接用2D卷积网络来处理得到的2D图片。本文主要从代码实现的角度来对这篇文章进行大概介绍。文章、代码:
论文:Learning to Segment 3D Point Clouds in 2D Image
下载地址:Spacehttps://openaccess.thecvf.com/content_CVPR_2020/papers/Lyu_Learning_to_Segment_3D_Point_Clouds_in_2D_Image_Space_CVPR_2020_paper.pdf
论文:Zhang-VISLab/Learning-to-Segment-3D-Point-Clouds-in-2D-Image-Space
代码:https://github.com/Zhang-VISLab/Learning-to-Segment-3D-Point-Clouds-in-2D-Image-Space
1. 3D点云到2D图片的影射
一个3D点云,如何影射为一张2D图片,是这篇文章的核心。因此,先对其进行介绍。映射过程主要分为以下几步:
建图(Graph Contruction):使用三角剖分(Delaunay triangulation)算法建图,建立起点与点之间的联系。有了图,才能用后续的方法将点云映射到2D平面上。
映射到2D平面(Graph Drawing):使用fruchterman_reingold_layout(或者叫做 spring layout)算法完成映射,得到每个3D点,在2D平面上的坐标。
映射到2D网格:将连续的2D平面scale后,划分为一个2D网格,每个点都会落到一个格子内。最终的这个网格,就可以看作是一张2D图片。在这步操作中,多个点可能会落在一个相同的格子内。此时,为每个多出来的点,找一个距离这个格子最近的空白格子,将点挪到空白格子中。
2. 效率问题
上面的映射步骤,其时间复杂度跟点数 的关系是:
。为了减少单次映射操作的点数
从而降低时间复杂度,文章使用了两级映射的方式,如下图所示:
总体来说,将一个点云的点分为两级:
第一级:KMeans 聚类得到的中心点
第二级:每个类包含的点
分别对类中心点、每个类内部的点采用上面提到的3D到2D的映射算法,最后再将结果组合到一起。按照这种分级的方式,单次映射中,点数 就会降低很多,整体上可以降低算法的时间复杂度。
如上图所示:
1、上边的路径表示将KMeans聚类得到的中心点映射到16x16的网格里面,得到
2、下边的路径表示将每个类包含的点分别映射到一个16x16的网格里面,得到多个
3、最后把每个类得到的
,嵌到
中其类中心映射到的那个位置上,得到一个512x512的网格。这个网格,即可视为最终训练用的图片。
3. Balanced KMeans
KMeans聚类得到的多个cluster,可能一些cluster包含的点多、一些包含的点少。论文希望每个cluster包含的点数差别不要太大。因此,可以从点数太多的cluster中(点数超过一个预设阀值),选出一个点,把这个点挪到一个与该点距离最近且包含点数少的cluster中(低于一个预设阀值)。经过多次迭代操作后,可以认为得到一个balanced clusters。
最后可以得出每个cluster中心点,以及每个点属于哪个cluster。
4. 网络结构
网络:使用一个U-Net网络来训练,结构图如下:
输入:在上面构造出来的图片中,空白位置设为0,非空白位置用其对应的3D点的3维坐标来填充其3个channel。
label:对于每个位置,相当于一个多分类问题。考虑到空白区域,需要额外增加一个类别,表示空白位置为无用类别,但在计算loss时,不用考虑该无用类别。
loss:categorical_crossentropy
5. 总结
文章通过Delaunay triangulation、fruchterman_reingold_layout等算法将3D点云映射为2D图片,然后用2D卷积网络U-Net来训练。