资讯详情

点云算法(深度学习)

Point cloud 非常适合3D由于: 1.点云是一个非常接近原始传感器的数据集。激光雷达扫描后,点云是直接的。原始数据可以深入研究端到端,挖掘原始数据中的模式。 2.点云在表达形式上相对简单。相比之下:Mesh需要选择面片类型和如何连接;网格需要选择多少网格,分辨率;图像需要拍摄角度,表达不全面。

以前的大部分工作都集中在点云数据的手工设计上。这些特征是针对特定任务的。有不同的假设。新任务难以优化特征。最近,有一些方法可以直接研究点云的特征学习,希望通过深入学习特征来解决数据问题。

点云数据是一种不规则的数据,输入网络需要规则化:

  1. 体素化voxel-base
  2. 投影projection-base
  3. 直接法point-base

还需要解决这些问题:

  • 无序性:maxpooling/sumpooling
  • 旋转不变:transform学习角度
  • 近密远疏:voxel、random-sample数量相同的点
  • 非结构化CNN:voxel-base、projection-base、point-base

三种方法:

Projection-base:2D点云投影是图像处理的2D图像,如转换BEV,用2D检测方法3D输入点云投影图(多结合2D图像),网络使用传统的2D-CNN,典型为MV3D。将数据压缩成二维本身将失去空间关系,有效地将点云转换为图像是检测结果的关键,但转换为图像操作,简单的理解和现成的工具。

Voxel-base:voxel对应pixel,体素对应像素,在空间中画一个固定大小的网格,形成体素,使用3d卷积来做。体素是从CNN直接扩展,非常暴力,容易理解。体素化后,许多体素中没有雷达点。通常的方法是将其特征置于0。0参与卷积后,结果仍为0,相当于无贡献。然而,这种体素稀疏的性质使得大量的卷积无法计算。另一个问题是体素是三维的,卷积模板也是三维的,所以它比二维慢,卷积核的移动方向也是三维的,随着空间大小的增加,体素的数量是以立方体的数量增加的,这不仅使计算缓慢,而且使大量的计算无用。当然,稀疏的卷积spare convolution这个问题可以部分解决。另外pointpillars去除体素的z轴维度,使用2D卷积解决了速度问题。另外pointpillars去除体素的z轴维度,使用2D卷积解决了速度问题。点云素化后,提取手工特性,然后连接FC,这样做有很大的局限性。

Point-base:由于点云的无序性,对点云直接操作的研究应从头开始进行。目前,主流是PointNet系列和Graph convolution系列。

MVNet以点云和图像为输入。 点云的处理格式分为两种种是构建俯视图(BV),施工方法是将点云格栅格化,形成三维格栅,每个格栅是格栅中雷达点的最高高度,每层格栅作为一个channel,再加上反射率(intensity)和密度(density)二是构建前视图(FV),将雷达点云投影到柱坐标系中,也有文章叫range view,然后网格化,在柱坐标系中形成二维网格,构建高度、反射率和密度channel。 按俯视图使用RPN回到二维的方式proposal,具有(x, y, w, l)角度只分为0和90度,z这一步和h的信息设置为常量。然后是三维的proposal多角度ROI pooling,fusion过程可使用concatenation或summation。最后加上经典的分类头和回归头。

我们能否直接用一种在点云上学习的方法一框架,end2end,multi-task(检测、分割)

基础分类分割,无检测功能

GitHub - charlesq34/pointnet: PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

  • 不变性替换输入顺序

点云输入顺序如何保持不变?

点云是数据表达点的集合,对点顺序不敏感,N个点,D最简单的维特征D=3(xyz),颜色和方向也可以有。

点集是无序的,可以改变,背后代表相同的点集,网络需要实现替换的不变性。解决方案是对称函数,具有替代不变性,神经网络的本质也是一个函数。最简单的例子是如何使用神经网络构建对称函数max:

虽然替换是不变的,但这种方法只计算了最远的边界,失去了很多有意义的几何信息。如何解决?

每一点都可以映射到高维空间,在高维空间中进行对称操作,高维空间可以是冗余的,在max冗余可以避免信息丢失,并且可以保留足够的点云信息。

这就是函数hgγ(原始的point-net结构组合。

每一点都做h低到高的映射(可以使用)mlp数据升维),G对称(可用)maxpooling对称也可以降低采样),所以整个结构是对称的,然后通过网络γ进一步消化信息,得到点云的特征,得到最终结果。

mlp就是多个fc堆叠。

  • 角度置换不变性(后续)pointnet版本证明没效果,废弃了)

如何应对输入点云的几何(视角)变换,比如一辆车从不同角度点云xyz它们是不同的,但它们代表汽车。我们希望网络也能应对视角的变化。

可以增加了一个基于数据本身的变换函数模块 T-net ,网络处理变换之后的点,通过优化变换网络和后面的网络使得变换函数对齐输入,如果对齐了,不同视角的问题就可以简化。

实际中点云的变化很简单,做矩阵乘法就可以。比如对于一个3*3的矩阵仅仅是一个正交变换,计算容易实现简单。

我们可以推广这个操作,不仅仅在输入作此变换,还可以在中间做 N个点 K维特征,用另外网络生成k*k 来做特征空间的变化,生成另一组特征。高维优化难度高,需要加正则化,比如希望矩阵更加接近正交矩阵。

后续的pointnet版本证明T-net没效果,废弃了,我认为之所没效果是因为对于大空间的分割检测任务,整体变换角度对学习各个目标小部件作用不大,可能只对小型分类点云有用。

  • 输入原始点云,一个n*3的矩阵,n代表点云数量,3对应xyz坐标;
  • 先做一个输入的矩阵变换(Tnet),n*3 x 3*3,还是n*3的矩阵;
  • 然后通过mlp把每个点投射到64高维空间;
  • 在做一个高维空间的变换(Tnet),形成一个更加归一化的64维矩阵;
  • 继续做MLP将64维映射到1024维;
  • 在1024中可以做对称性的操作,就是maxpooling,得到globle fearue(1*1024);
  • head:
    • 对分类任务,将全局特征通过mlp(多个fc层)来预测最后的分类分数(1*1024->1*512->1*256->1*k),k代表样本集中点云类别的个数,输入的点云只有一个类别,这不是检测任务,有多个目标;
    • 对分割任务,将全局特征复制n份,和之前学习到的局部特征即64维那层进行concat,n*(1024+64),再通过mlp得到每个数据点的分类结果(n*1088->n*512->n*256->n*128->n*m),m是分割类别数目。将局部单个点的特征和全局的坐标结合起来,实现分割的功能。

优点:

对比2D图片和3D栅格,pointnet是个非常轻量级的网络,适用于移动设备;

同时对数据的丢失也是非常的鲁棒,对比于voxelnet 的对比,在model net 40 的分类问题上,在丢失50%的点的情况下,pointnet仅仅受到2%的影响,与之想想比Voxnet3D精度相差了20%。

下图第一行是Original的,我们想知道哪些点对全局特征做出了贡献,maxpooling ,有些点embedded的特征非常小,在经过maxpooling之后对全局特征没有任何的贡献,哪些点是剩下来的Critial(Maxpooling 之后存活下来的大特征点),只要轮廓和骨骼得到保存,就能把形状分类正确。

缺点:

point-net一开始对每个点做MLP低维到高维的映射,把所有点映射到高维的特征通过Max pooling 结合到一起。本质上来说,要么对一个点做操作,要么对所有点做操作,实际上没有局部的概念(loal context) ,比较难对精细的特征做学习,在分割和检测上有局限性,适合小点云的分类

没有local context 在平移不变性上也有局限性,对点云数据做平移,所有的数据都不一样了,导致所有的特征,全局特征都不一样了,分类也不一样。对于单个的物体还好,可以将其平移到坐标系的中心,把他的大小归一化到一个球中,在一个场景中有多个物体不好办,对哪个物体做归一化呢。

为了解决这些问题诞生了PointNet++。

GitHub - charlesq34/pointnet2: PointNet++: Deep Hierarchical Feature Learning on Point Sets in a Metric Space PointNet提取特征的方式是对所有点云数据提取了,显然,CNN逐层提取局部特征的更适合检测,作者又提出了PointNet++,它能够在不同尺度提取局部特征,通过多层网络结构得到深层特征。PointNet++同样做分类和分割,无检测3Dbox的head。

  • 平移不变性多级的区域特征学习

pointnet++ 核心的想法在局部区域重复性的迭代使用pointnet ,在小区域使用pointnet 生成新的点,新的点定义新的小区域多级的特征学习,因为是在区域中,我们可以用局部坐标系,可以实现平移的不变性,同时在小区域中还是使用pointnet,对点的顺序是无关的,保证置换不变性。

世界坐标系,先找到一个局部的区域,因为不想受整体平移的影响:

1、可以先把局部的点转换到一个局部坐标系中

2、在局部中使用pointnet 来提取特征

3、提取完特征以后会得到一个新的点F,F在整个点云中的位置

4、向量特征F(高纬的特征空间)代表小区域的几何形状,如果重复这个操作就会得到一组新的点,在数量上少于原先的点,但是新的每个点代表了它周围一个区域的几何特点。    ​

set abstraction:Sampling(FPS)、Grouping、PointNet构成了PointNet++的一组基础处理模块。

我们可以重复set abstraction的过程,实现一个多级(code是三级,图展示两级)的网络,使得点的数量越来越少,但是每个点代表的区域以及感受野越来越大,这个和cnn的概念很类似。

pointnet里已经废弃Tnet了,因为PN++ 已经学了局部特征,局部特征其实对旋转不太敏感,已经可以取得比较好效果。

# 单尺度 point++ 分类模型 pointnet2_cls_ssg.py
    # Set abstraction layers 
    # 三组set abstraction, 
    # L0 为原始点云 (B,n,3)  batch、点数、特征通道数、
    l1_xyz, l1_points, l1_indices = pointnet_sa_module(l0_xyz, l0_points, npoint=512, radius=0.2, nsample=32, mlp=[64,64,128], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer1', use_nchw=True)
    # L1  (B,512,128) 
    l2_xyz, l2_points, l2_indices = pointnet_sa_module(l1_xyz, l1_points, npoint=128, radius=0.4, nsample=64, mlp=[128,128,256], mlp2=None, group_all=False, is_training=is_training, bn_decay=bn_decay, scope='layer2')
    # L2  (B,128,256)
    l3_xyz, l3_points, l3_indices = pointnet_sa_module(l2_xyz, l2_points, npoint=None, radius=None, nsample=None, mlp=[256,512,1024], mlp2=None, group_all=True, is_training=is_training, bn_decay=bn_decay, scope='layer3')

    # Fully connected layers
    net = tf.reshape(l3_points, [batch_size, -1])
    net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay)
    net = tf_util.dropout(net, keep_prob=0.5, is_training=is_training, scope='dp1')
    net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay)
    net = tf_util.dropout(net, keep_prob=0.5, is_training=is_training, scope='dp2')
    # 分40类
    net = tf_util.fully_connected(net, 40, activation_fn=None, scope='fc3')
  1. Sampling点云的数据量重多,如果对每一个点都提取局部特征,计算量是巨大。因此先对数据点进行采样,算法是FPS最远点采样(c++ cuda编程),相对于随机采样,这种采样算法能够更好地覆盖整个采样空间;第一次的set abstraction在原始点云上采样512个点,选中了512个特征中心;第二次的set abstraction是在特征图上采样128个特征中心;第三次的set abstraction特征图上所以点都是特征中心。 FPS希望达到尽可能采远处的点。
  2. Grouping为了提取一个点(特征中心)的局部特征,首先需要定义这个点的“局部”是什么。点云数据中的一个点的局部由其周围给定半径划出的球形空间内的其他点构成(c++ cuda编程)。组合层的作用就是找出通过采样层后的每一个点的所有构成其局部的点,以方便后续对每个局部提取特征。第一次的set abstraction特征中心局部球体半径0.2,提取点数为32;第二次的set abstraction特征中心局部球体半径0.4,提取点数为64;第三次的则全部点就是局部。此外代码对于提取局部点除了这种query_ball_point策略还有第二种策略:knn search的方法。
  3. PointNet layer(feature extract):PointNet给出了一个基于点云数据的特征提取网络,因此用PointNet对组合层给出的各个局部进行特征提取来得到局部特征。虽然组合层给出的各个局部可能由不同数量的点构成,但是通过PointNet后都能得到维度一致的特征(由K值决定)。
单尺度网络模型:
input:(B n 3)

pointnet_sa_module1{
  sample 
    (B 512 3)     # sample output
  group  
    (B 512 3 32 ) # group output
  Point Feature Embedding  
    (B 512 3 32 ) # Fisrt conv2d output
    (B 512 3 64 ) # Second conv2d output
    (B 512 3 128) # Third conv2d output
  MaxPooling 
    (B 512 128)
}

pointnet_sa_module2{
  sample 
    (B 128 128)
  group  
    (B 128 128 64)
  Point Feature Embedding  
    (B 128 128 128)
    (B 128 128 128)
    (B 128 128 256)
  MaxPooling 
    (B 128 256)
}

pointnet_sa_module3{
  sample 
    (B 128 256)
  group  
    (B 128 256 128) 
  Point Feature Embedding  
    (B 128 128 256)
    (B 128 128 256)
    (B 128 128 1024)
  MaxPooling 
    (B 128 1024)
}

reshape
 (B 128x1024)
fc1
 (B 512) 
fc2
 (B 256)
fc3
 (B 40) # 40 class output

分类:set abstraction的结果 得到globle feature,再经过mlp(多层fc),得到分类结果。

分割:对于分割,还需要将下采样后的特征进行上采样,使得原始点云中的每个点都有对应的特征,这个上采样的过程通过最近的k个临近点进行插值(3D的插值)计算得到,模型类似Unet,最终得到分割结果。

  • 单尺度网络的局限性

在pointnet++中,piontnet就是卷积核,如何选择局部区域的大小,就是如何选择卷积核的大小宽度,如何选择pointnet 作用区域的球的半径?

在卷积神经网络中大量应用小的kernal(VGG 3*3*3),在pointcloud中是否一样呢?不一定。 

因为pointnet 常见的采样率的不均匀,比如有个depth camera 采到的图像,近的点非常密集,远的点非常稀疏,在密的地方没有问题,在稀疏的会有问题,比如极端的情况,只有一个点,这样学到的特征会非常的不稳定,我们应该避免。

为了量化这个问题,有个控制变量的实验,在刚开始1024点的时候pointnet++ 更加强大,得到更高的精确度,随着密度的下降,性能受到了极大的影响,在小于500个点以后性能低于pointnet。

如果点云稀疏,局部的kernel(pointnet)太小的话,会影响性能,各处采样率不均匀。

针对于这个问题,我们希望设计一个神经网络来智能学习,如何综合不同区域大小的特征,得到一个鲁棒的学习网络,希望在密集的地方相信这个特征,稀疏的地方不相信这个特征,而去看更大的区域。

  • MSG/MRG解决单尺度网络的局限性

比较简单的做法是设计一个Multi-scale :在这个2D的例子中 将不同半径的区域 ,联合在一起。

多尺度,多分辨率的Grouping的学习。MSG有点像金字塔网络,MRG有点像inception中的结构多种卷积核。

MSG,即把每种半径下的局部特征都提取出来,然后组合到一起,作者在如何组合的问题上提到了一种random dropping out input points的方法,存在两个参数p和q(原文中为theta),每个点以q的概率进行丢弃,而q为在[0,p]之间均匀采样,这样做,可以让整体数据集体现出不同的稠密性和均匀性。MSG有一个巨大的问题是运算的问题,然后作者经过思量,提出we can avoid the feature extraction in large scale neighborhoods at lowest levels,因为在低层级处理大规模数据,可能模板处理能力不够,感受野有些过大,基于此,作者提出了MRG。

MRG有两部分向量构成,分别为上一层即Li-1层的向量和直接从raw point上提取的特征构成,当点比较稀疏时,给从raw point提取的特征基于较高的权值,而若点比较稠密,则给Li-1层提取的向量给予较高的权值,因为此时raw point的抽象程度可能不够,而从Li-1层的向量也由底层抽取而得,代表着更大的感受野。它有个好处,可以节省计算,在下一级的特征已经计算好了,只需要把它池化拿来用就行了。 而在MSG中需要对不同尺度分别计算。

 发现加了MRG和MSG中,丢失数据后鲁棒性能好很多。

# 多尺度 point++ 分类模型  pointnet2_cls_msg.py
    # 三个尺度的特征中心的局部半径[0.1,0.2,0.4]
    l1_xyz, l1_points = pointnet_sa_module_msg(l0_xyz, l0_points, 512, [0.1,0.2,0.4], [16,32,128], [[32,32,64], [64,64,128], [64,96,128]], is_training, bn_decay, scope='layer1', use_nchw=True)
    l2_xyz, l2_points = pointnet_sa_module_msg(l1_xyz, l1_points, 128, [0.2,0.4,0.8], [32,64,128], [[64,64,128], [128,128,256], [128,128,256]], is_training, bn_decay, scope='layer2')
    l3_xyz, l3_points, _ = pointnet_sa_module(l2_xyz, l2_points, npoint=None, radius=None, nsample=None, mlp=[256,512,1024], mlp2=None, group_all=True, is_training=is_training, bn_decay=bn_decay, scope='layer3')
 
    # Fully connected layers
    net = tf.reshape(l3_points, [batch_size, -1])
    net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training, scope='fc1', bn_decay=bn_decay)
    net = tf_util.dropout(net, keep_prob=0.4, is_training=is_training, scope='dp1')
    net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training, scope='fc2', bn_decay=bn_decay)
    net = tf_util.dropout(net, keep_prob=0.4, is_training=is_training, scope='dp2')   
    net = tf_util.fully_connected(net, 40, activation_fn=None, scope='fc3')  
    return net, end_points

pointnet++ 大幅提高了场景分割性能,因为多级的结构,使得他更鲁棒的对局部的特征更好的学习,同时还有平移不变性的特点。

pointnet++ 不局限于2D或者3D欧式空间,可以拓展到任意的测度空间,只要有个定义好的距离函数。

pointnet++开创了点云直接法的先河。pointnet++之前的方法是基于点云投影到图片上(鸟瞰图),在图片中做,缺点是丢失了三位的结构信息,在图片的表达形式下,2D的cnn受到了很大的局限,很难精确的估计物体的深度和大小;或者三维的box也可以是3D的cnn来做,propos完之后可以把2D和3D的feature结合,缺点是三维搜索空间非常大,计算量也非常大,而且在3D中proposal 点云的分辨率非常有限,很多时候很难发现比较小的物体。

  • 大场景点云分割的难点

PointNet, PointNet++等一系列方法在处理S3DIS这种大场景数据集时,都需要先将点云切成一个个1m×1m的小点云块,然后在每个点云块中采样得到4096个点输入网络。

这种预处理方式虽然说方便了后续的网络训练和测试,但同时也存在着一定的问题。

将整个场景切成非常小的点云块是否会损失整体的几何结构?用一个个小点云块训练出来的网络是否能够有效地学习到空间中的几何结构呢?

数据集

KITTI

S3DIS

S3DIS数据集解析为点云_ybg的博客-CSDN博客_s3disPointnet语义分割任务S3DIS数据集上的注意点_Breeze-CSDN博客_s3dis

标签: 传感器dp2

锐单商城拥有海量元器件数据手册IC替代型号,打造 电子元器件IC百科大全!

锐单商城 - 一站式电子元器件采购平台