pointnet分割自己的点云数据_细嚼慢咽读论文:PointNet论文及代码详细解析

65c3b79df6df219634a43c3dc976e4fb.png

论文标题:PointNet: Deep Learning on Point Sets for 3D Classification and Segmentation

e2ee9185fa499e47b900ac4cfbc897be.png

0752aca0312851d3e268e2e6d8c3138c.png

标签:有监督 | 特征学习、点云分类、语义分割


首先回答3个问题作为引子:

Q1:什么是点云?

简单来说就是一堆三维点的集合,必须包括各个点的三维坐标信息,其他信息比如各个点的法向量、颜色等均是可选。

点云的文件格式可以有很多种,包括xyz,npy,ply,obj,off等(有些是mesh不过问题不大,因为mesh可以通过泊松采样等方式转化成点云)。对于单个点云,如果你使用np.loadtxt得到的实际上就是一个维度为

的张量,num_channels一般为3,表示点云的三维坐标。

这里以horse.xyz文件为例,实际就是文本文件,打开后数据长这样(局部,总共有2048个点):

6f0dafdc995929392b82d8bb11d61e91.png

实际就是一堆点的信息,这里只有三维坐标,将其可视化出来长这样:

2e51c6b5bb747bbb81b0a1ed01ad618c.png

Q2:为什么点云处理任务是重要的?

三维图形具有多种表现形式,包括了mesh、体素、点云等,甚至还有些方法使用多视图来对三维图形表征。而点云在以上各种形式的数据中算是日常生活中最能够大规模获取和使用的数据结构了,包括自动驾驶、增强现实等在内的应用需要直接或间接从点云中提取信息,点云处理也逐渐成为计算机视觉非常重要的一部分。

Q3:为什么PointNet是重要的?

这个后面会说,直接对点云使用深度学习、解决了点云带来的一系列挑战,PointNet应该是开创性的。但我觉得,真正让PointNet具备很大影响力的,还是它的简洁、高效和强大。


首先要说清楚,PointNet所作的事情就是对点云做特征学习,并将学习到的特征去做不同的应用:分类(shape-wise feature)、分割(point-wise feature)等。

PointNet之所以影响力巨大,就是因为它为点云处理提供了一个简单、高效、强大的特征提取器(encoder),几乎可以应用到点云处理的各个应用中,其地位类似于图像领域的AlexNet。


1 motivation

related work

  1. Volumetric CNNs:对体素应用3DCNN。缺点是点云的坐标空间的稀疏性导致转成体素后的分辨率问题,以及3D卷积带来的开销
  2. Multiview CNNs:将点云或者shape渲染成视图,使用传统的图像卷积来做特征学习。这种方法确实取得了不错的效果,但是缺点是应用非常局限,像分割、补全等任务就不太好做
  3. Spectral CNNs
  4. feature-based DNN

why we want to do this?

点云或者mesh,大多数研究人员都是将其转化成3D体素或者多视图来做特征学习的,这其中的工作包括了VoxelNet, MVCNN等。这些工作都或多或少存在了一些问题(上面提到了)。

直接对点云做特征学习也不是不可以,但有几个问题需要考虑:特征学习需要对点云中各个点的排列保持不变性、特征学习需要对rigid transformation保持不变性等。虽然有挑战,但是深度学习强大的表征能力以及其在图像领域取得的巨大成功,因此是很有必要直接在点云上进行尝试的。

2 contribution

  1. 我们设计了一个新颖的深层网络架构来处理三维中的无序点集
  2. 我们设计的网络表征可以做三维图形分类、图形的局部分割以及场景的语义分割等任务
  3. 我们提供了完备的经验和理论分析来证明PointNet的稳定和高效。
  4. 充分的消融实验,证明网络各个部分对于表征的有效性。

3 solution

challenges

点云的几个特点:

  1. 无序性 --> 对称函数设计用于表征
  2. 点不是孤立的,需要考虑局部结构 --> 局部全局特征结合
  3. 仿射变换无关性 --> alignment network

forward propagation

3dc0ebc752c05c4a7fc0057aaa502b90.png
PointNet网络结构图

网络分成了分类网络和分割网络2个部分,大体思路类似,都是设计表征的过程

分类网络设计global feature,分割网络设计point-wise feature

两者都是为了让表征尽可能discriminative,也就是同类的能分到一类,不同类的距离能拉开

PointNet设计思路主要有以下3点:

1 Symmetry Function for Unordered Input:

要做到对点云点排列不变性有几种思路:

  1. 直接将点云中的点以某种顺序输入(比如按照坐标轴从小到大这样)

为什么不这样做?(摘自原文)in high dimensional space there in fact does not exist an ordering that is stable w.r.t. point perturbations in the general sense.简单来说就是很难找到一种稳定的排序方法

2. 作为序列去训练一个RNN,即使这个序列是随机排布的,RNN也有能力学习到排布不变性。

为什么不这样做?(摘自原文)While RNN has relatively good robustness to input ordering for sequences with small length (dozens), it’s hard to scale to thousands of input elements, which is the common size for point sets. RNN很难处理好成千上万长度的这种输入元素(比如点云)。

3. 使用一个简单的对称函数去聚集每个点的信息

da34b08549384f1065ec7e55f7b75bb4.png

我们的目标:左边

是我们的目标,右边
是我们期望设计的对称函数。由上公式可以看出,基本思路就是对各个元素(即点云中的各个点)使用
分别处理,在送入对称函数
中处理,以实现排列不变性。

在实现中

就是MLP,
就是max pooling

对于以上三种不同的做法,作者均作了实验来验证,得出第三种方法效果最好:

a98e10192873e683325b44e1b6b34781.png

2 Local and Global Information Aggregation

对于分割任务,我们需要point-wise feature

因此分割网络和分类网络设计局部略有不同,分割网络添加了每个点的local和global特征的拼接过程,以此得到同时对局部信息和全局信息感知的point-wise特征,提升表征效果。

3 alignment network:

用于实现网络对于仿射变换、刚体变换等变换的无关性

直接的思路:将所有的输入点集对齐到一个统一的点集空间

pn的做法:直接预测一个变换矩阵(3*3)来处理输入点的坐标。因为会有数据增强的操作存在,这样做可以在一定程度上保证网络可以学习到变换无关性。

特征空间的对齐也可以这么做,但是需要注意:

transformation matrix in the feature space has much higher dimension than the spatial transform matrix, which greatly increases the difficulty of optimization. 对于特征空间的alignment network,由于特征空间维度比较高,因此直接生成的alignment matrix会维度特别大,不好优化,因此这里需要加个loss约束一下。

add a regularization term to our softmax training loss:

31ed0c285edb6f24d57deeab9296e211.png

使得特征空间的变换矩阵A尽可能接近正交矩阵

消融实验验证alignment network的效果:

33fb8efaba99ee82a1f1a80bc7951933.png

loss

看代码:分类中常用的交叉熵+alignment network中用于约束生成的alignment matrix的loss

4 dataset and experiments

evaluate metric

分类:分类准确率acc
分割:mIoU

dataset

分类:ModelNet40
分割:ShapeNet Part dataset和Stanford 3D semantic parsing dataset

experiments

分类:

0033d1a05c6ba6f37534041ae2446fef.png

局部分割:

7c8b27551a845757656a433f255e5f3d.png

5 code

看代码分析PointNet结构:

3dc0ebc752c05c4a7fc0057aaa502b90.png

观察上图,有4个值得关注的点:
1. 如何对点云使用MLP?
2. alignment network怎么做的?
3. 对称函数如何实现来提取global feature的?
4. loss?

针对问题1:

以分类网络为例,整体代码:

def get_model(point_cloud, is_training, bn_decay=None):""" Classification PointNet, input is BxNx3, output Bx40 """batch_size = point_cloud.get_shape()[0].valuenum_point = point_cloud.get_shape()[1].valueend_points = {}with tf.variable_scope('transform_net1') as sc:transform = input_transform_net(point_cloud, is_training, bn_decay, K=3)point_cloud_transformed = tf.matmul(point_cloud, transform)input_image = tf.expand_dims(point_cloud_transformed, -1)net = tf_util.conv2d(input_image, 64, [1,3],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv1', bn_decay=bn_decay)net = tf_util.conv2d(net, 64, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv2', bn_decay=bn_decay)with tf.variable_scope('transform_net2') as sc:transform = feature_transform_net(net, is_training, bn_decay, K=64)end_points['transform'] = transformnet_transformed = tf.matmul(tf.squeeze(net, axis=[2]), transform)net_transformed = tf.expand_dims(net_transformed, [2])net = tf_util.conv2d(net_transformed, 64, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv3', bn_decay=bn_decay)net = tf_util.conv2d(net, 128, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv4', bn_decay=bn_decay)net = tf_util.conv2d(net, 1024, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv5', bn_decay=bn_decay)# Symmetric function: max poolingnet = tf_util.max_pool2d(net, [num_point,1],padding='VALID', scope='maxpool')net = tf.reshape(net, [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.7, 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.7, is_training=is_training,scope='dp2')net = tf_util.fully_connected(net, 40, activation_fn=None, scope='fc3')return net, end_points

MLP的核心做法:

input_image = tf.expand_dims(point_cloud_transformed, -1)
net = tf_util.conv2d(input_image, 64, [1,3],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv1', bn_decay=bn_decay)
net = tf_util.conv2d(net, 64, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='conv2', bn_decay=bn_decay)

这里input_image维度是

,因此将点云看成是W和H分为N和3的2D图像,维度是

然后直接基于这个“2D图像”做卷积,第一个卷积核size是

,正好对应的就是“2D图像”的一行,也就是一个点(三维坐标),输出通道数是64,因此输出张量维度应该是

第二个卷积核size是

卷积只改变通道数,输出张量维度是

conv2d就是将卷积封装了一下,核心部分也就是调用tf.nn.conv2d,实现如下:

def conv2d(inputs,num_output_channels,kernel_size,scope,stride=[1, 1],padding='SAME',use_xavier=True,stddev=1e-3,weight_decay=0.0,activation_fn=tf.nn.relu,bn=False,bn_decay=None,is_training=None):""" 2D convolution with non-linear operation.Args:inputs: 4-D tensor variable BxHxWxCnum_output_channels: intkernel_size: a list of 2 intsscope: stringstride: a list of 2 intspadding: 'SAME' or 'VALID'use_xavier: bool, use xavier_initializer if truestddev: float, stddev for truncated_normal initweight_decay: floatactivation_fn: functionbn: bool, whether to use batch normbn_decay: float or float tensor variable in [0,1]is_training: bool Tensor variableReturns:Variable tensor"""with tf.variable_scope(scope) as sc:kernel_h, kernel_w = kernel_sizenum_in_channels = inputs.get_shape()[-1].valuekernel_shape = [kernel_h, kernel_w,num_in_channels, num_output_channels]kernel = _variable_with_weight_decay('weights',shape=kernel_shape,use_xavier=use_xavier,stddev=stddev,wd=weight_decay)stride_h, stride_w = strideoutputs = tf.nn.conv2d(inputs, kernel,[1, stride_h, stride_w, 1],padding=padding)biases = _variable_on_cpu('biases', [num_output_channels],tf.constant_initializer(0.0))outputs = tf.nn.bias_add(outputs, biases)if bn:outputs = batch_norm_for_conv2d(outputs, is_training,bn_decay=bn_decay, scope='bn')if activation_fn is not None:outputs = activation_fn(outputs)return outputs

针对问题2:

这里以input_transform_net为例:

def input_transform_net(point_cloud, is_training, bn_decay=None, K=3):""" Input (XYZ) Transform Net, input is BxNx3 gray imageReturn:Transformation matrix of size 3xK """batch_size = point_cloud.get_shape()[0].valuenum_point = point_cloud.get_shape()[1].valueinput_image = tf.expand_dims(point_cloud, -1)net = tf_util.conv2d(input_image, 64, [1,3],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv1', bn_decay=bn_decay)net = tf_util.conv2d(net, 128, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv2', bn_decay=bn_decay)net = tf_util.conv2d(net, 1024, [1,1],padding='VALID', stride=[1,1],bn=True, is_training=is_training,scope='tconv3', bn_decay=bn_decay)net = tf_util.max_pool2d(net, [num_point,1],padding='VALID', scope='tmaxpool')net = tf.reshape(net, [batch_size, -1])net = tf_util.fully_connected(net, 512, bn=True, is_training=is_training,scope='tfc1', bn_decay=bn_decay)net = tf_util.fully_connected(net, 256, bn=True, is_training=is_training,scope='tfc2', bn_decay=bn_decay)with tf.variable_scope('transform_XYZ') as sc:assert(K==3)weights = tf.get_variable('weights', [256, 3*K],initializer=tf.constant_initializer(0.0),dtype=tf.float32)biases = tf.get_variable('biases', [3*K],initializer=tf.constant_initializer(0.0),dtype=tf.float32)biases += tf.constant([1,0,0,0,1,0,0,0,1], dtype=tf.float32)transform = tf.matmul(net, weights)transform = tf.nn.bias_add(transform, biases)transform = tf.reshape(transform, [batch_size, 3, K])return transform

实际上,前半部分就是通过卷积和max_pooling对batch内各个点云提取global feature,再将global feature降到

维度,并reshape成
,得到transform matrix

通过数据增强丰富训练数据集,网络确实应该学习到有效的transform matrix,用来实现transformation invariance

针对问题3:

max_pooling,这个在论文的图中还是代码中都有体现,代码甚至直接用注释注明了

针对问题4:

def get_loss(pred, label, end_points, reg_weight=0.001):""" pred: B*NUM_CLASSES,label: B, """loss = tf.nn.sparse_softmax_cross_entropy_with_logits(logits=pred, labels=label)classify_loss = tf.reduce_mean(loss)tf.summary.scalar('classify loss', classify_loss)# Enforce the transformation as orthogonal matrixtransform = end_points['transform'] # BxKxKK = transform.get_shape()[1].valuemat_diff = tf.matmul(transform, tf.transpose(transform, perm=[0,2,1]))mat_diff -= tf.constant(np.eye(K), dtype=tf.float32)mat_diff_loss = tf.nn.l2_loss(mat_diff) tf.summary.scalar('mat loss', mat_diff_loss)return classify_loss + mat_diff_loss * reg_weight

无论是分类还是分割,本质上都还是分类任务,只是粒度不同罢了。

因此loss一定有有监督分类任务中常用的交叉熵loss

另外loss还有之前alignment network中提到的约束loss,也就是上面的mat_diff_loss

5 conclusion

PointNet之所以影响力巨大,并不仅仅是因为它是第一篇,更重要的是它的网络很简洁(简洁中蕴含了大量的工作来探寻出简洁这条路)却非常的work,这也就使得它能够成为一个工具,一个为点云表征的encoder工具,应用到更广阔的点云处理任务中。

MLP+max pooling竟然就击败了众多SOTA,令人惊讶。另外PointNet在众多细节设计也都进行了理论分析和消融实验验证,保证了严谨性,这也为PointNet后面能够大规模被应用提供了支持。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/551659.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

linux将字符串转小写_小猿圈总结Linux常见命令(一)

科技发展的今天,互联网不断的发达,很多人学习Linux云计算的时候回因为记不住一些命令从而去找度娘,有时候因为因为找不到linux的命令而烦恼,下面是小猿圈linux讲师给大家总结的linux常见命令,希望对你有所帮助。1、cd命…

java声明arraylist,在java构造函数中声明ArrayList

我正在研究一个项目,并且我被教导在构造函数中实例化变量.我在使用ArrayList思想时遇到了一些麻烦.您能否提出一些最佳实践,我是否需要使用实例变量定义ArrayList,或者我可以在构造函数中执行此操作.谢谢你的建议!我有一个我正在谈论的内容的例子://impo…

eureka 集群失败的原因_Eureka集群的那些坑

今天遇到一个Eureka集群的一个坑。问题现场类似是这样的:两台Eureka组成的服务注册中心集群,两台服务提供方server1、server2,两个服务调用方client1、client2。正常的情况下:client1和client2通过服务中心获取的服务提供方的注册…

cnpm安装webpack_Webpack(一)介绍

一、Webpack是什么、为什么要使用它简单来说,Webpack是一个打包工具。站在2018年的角度,成为一个优秀的前端工程师,除了要会写页面样式和动态效果之外,还需要会用主流的单页面框架、Node.js、简单的前端的性能优化等等。加上现在一…

php生日验证,PHP验证生日

function pc_checkbirthdate($month, $day, $year) {$min_age 18; // 过18岁$max_age 100; // 超过122岁// 验证是不是合法时间,不会出现2月30号类似错误if (! checkdate ( $month, $day, $year )) {return false;}// 取得当前 年 月 日list ( $this_year, $this_…

python中的try与if,python中if和try的区别是什么

python中if和try的区别是什么发布时间:2020-09-10 10:04:05来源:亿速云阅读:85作者:小新这篇文章给大家分享的是有关python中if和try的区别是什么的内容。小编觉得挺实用的,因此分享给大家做个参考。一起跟随小编过来看…

bytes数组转string指定编码_一篇文章弄懂Python中所有数组数据类型

前言数组类型是各种编程语言中基本的数组结构了,本文来盘点下Python中各种“数组”类型的实现。listtuplearray.arraystrbytesbytearray其实把以上类型都说成是数组是不准确的。这里把数组当作一个广义的概念,即把列表、序列、数组都当作array-like数据类…

怎么安装php模板,PHPWind八风格模板的安装及制作教程

PHPWind八风格模板的安装及制作教程 PHPWind 8风格模板的安装及制作教程一、PHPWind风格模板的安装:1、下载自己喜欢的PHPWind模板,由于PHPWind使用者众多,所以为了符合多种客户的需要,它的风格模板也是有万千种风格,大…

sklearn保存svm分类模型_【菜菜的sklearn】07 支持向量机(上)

小伙伴们大家好~o( ̄▽ ̄)ブ,我是菜菜,这里是我的sklearn课堂第7期,今天分享的内容是支持向量机(上),下周还有下篇哦~我的开发环境是Jupyter lab,所用的库和版本大家参考&a…

cef在android中使用_关于富文本在Android中的应用以及遇到的坑

富文本可以为用户提供更加多样化的文本展示形式,但由于其使用了H5标签的特殊性,一般都需要第三方框架的支持。这里推荐一款合适的第三方富文本框架,richeditor。首先我们要使用该功能需要引入相关jar包,引入方法如下compile jp.wa…

thinkphp中如何使用PHP函数,如何在ThinkPHP中使用函数进行回调

如何在ThinkPHP中使用函数进行回调发布时间:2020-12-23 15:11:45来源:亿速云阅读:85作者:Leah本篇文章为大家展示了如何在ThinkPHP中使用函数进行回调,内容简明扼要并且容易理解,绝对能使你眼前一亮&#x…

unity 敌人自动攻击和寻路_Unity暑期萌新入门:环境篇

大家好,新一期又跟大家见面了。上一节我们完成了角色的移动控制,然而John只能在空白的场景中移动。因此接下来这一节我们将添加关卡、调节光照,让John来到阴森的鬼屋。然后设置NavMesh(导航网格,现在先听个概念就好),为…

layui tree 加载慢_图片太多,加载慢,我用了layui里的方式,放在服务器后还是太慢!怎么解决???有没有什么优化的技巧???...

怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决怎么解决???????layui.use([layer,flow], function(){v…

oracle 存储中文 u码,Oracle 汉字 占位

遇到了一个数据插入长度过长问题,记得大学时候,还说过oracle的不同编码下的的大小分配不是一样的,具体也忘记了,补上,以防下次犯二1 step先查看自己的oracle是什么字符集select userenv(language) from dual比如: SIMPLIFIED CHINESE_CHINA.ZHS16GBK 、 SIMPLIFIED CHINESE_CH…

element 表格宽度自适应_Java 设置Word中的表格自适应的3种方式

概述在Word创建表格时,可设置表格“自动调整”,有3种情况,通过Java程序设置可调用相应的方法来实现,即:根据内容调整表格AutoFitBehaviorType.Auto_Fit_To_Contents根据窗口调整表格AutoFitBehaviorType.Auto_Fit_To_W…

python实现决策树数据直接赋值导入_Python3.0 实现决策树算法的流程

决策树的一般流程检测数据集中的每个子项是否属于同一个分类if so return 类标签Else寻找划分数据集的最好特征划分数据集创建分支 节点from math import logimport operator#生成样本数据集def createDataSet():dataSet [[1,1,yes],[1,1,yes],[1,0,no],[0,1,no],[0,1,no]]lab…

linux oracle em使用,Linux平台下启动oracle 11g EM控制台

http://blog.csdn.net/webajax/article/details/6702233配置EM具体步骤一、配置EM dbconsole的步骤信息emca -config dbcontrol db -repos recreateEMCA 开始于 2007-10-12 11:16:40EM Configuration Assistant 10.2.0.1.0 正式版版权所有 (c) 2003, 2005, Oracle。保留所有权利…

源码里没有configure_深入源码理解.NET Core中Startup的注册及运行

开发.NET Core应用,直接映入眼帘的就是Startup类和Program类,它们是.NET Core应用程序的起点。通过使用Startup,可以配置化处理所有向应用程序所做的请求的管道,同时也可以减少.NET应用程序对单一服务器的依赖性,使我们…

天龙源码框架分析_天龙八部源码描述【转】

天龙八部(武侠世界)的源码很可能是天龙八部代码流出后改写的,因为在看了代码中可以找到一些证据,整个客户端分为:一个是编辑器,一个是客户端,采用OGREcegui自写的简单的物理碰撞检测FMOD自写的网络库。服务器端代码目前…

oracle查询慢怎么优化,Oracle查询优化-怎样建立索引优化下面的查询语句啊

下面是转换出来的查询语句SELECT *FROM (SELECT "Project1"."C1" AS "C1","Project1"."ID" AS "ID","Project1"."NVC_ORDERBY" AS "NVC_ORDERBY","Project1"."I_ST…