【手把手教你】搭建神经网络(3D点云分类)
大家好,我是羽峰,今天要和大家分享的是一个基于PointNet的3D点云分类研究。文章会把整个代码进行分割讲解,完整看完,相信你一定会有所收获。
该示例实现了开创性的点云深度学习论文PointNet (Qi et al., 2017)。 有关PointNet的详细介绍,请参阅 this blog post。
欢迎关注“羽峰码字”
目录
1. 3D点云分类简介
1.1 何为点云[1]
1.2 点云的获取[1]
1.3 点云的属性[1]
2. 使用PointNet进行点云分类[2]
2.1 基础API配置
2.2 下载数据及数据预处理
2.3 建立模型
2.4 训练模型
2.5 可视化预测
1. 3D点云分类简介
无序3D点集(即点云)的分类,检测和分割是计算机视觉中的核心问题。
1.1 何为点云[1]
我们在做 3D 视觉的时候,处理的主要是点云,点云就是一些点的集合。相对于图像,点云有其不可替代的优势——深度,也就是说三维点云直接提供了三维空间的数据,而图像则需要通过透视几何来反推三维数据。
- 其实点云是某个坐标系下的点的数据集。点包含了丰富的信息,包括三维坐标 X,Y,Z、颜色、分类值、强度值、时间等等。点云在组成特点上分为两种,一种是有序点云,一种是无序点云。
- 有序点云:一般由深度图还原的点云,有序点云按照图方阵一行一行的,从左上角到右下角排列,当然其中有一些无效点因为。有序点云按顺序排列,可以很容易的找到它的相邻点信息。有序点云在某些处理的时候还是很便利的,但是很多情况下是无法获取有序点云的。
- 无序点云:无序点云就是其中的点的集合,点排列之间没有任何顺序,点的顺序交换后没有任何影响。是比较普遍的点云形式,有序点云也可看做无序点云来处理。
1.2 点云的获取[1]
点云不是通过普通的相机拍摄得到的,一般是通过三维成像传感器获得,比如双目相机、三维扫描仪、RGB-D 相机等。目前主流的 RGB-D 相机有微软的 Kinect 系列、Intel 的 realsense 系列、structure sensor(需结合 iPad 使用)等。点云可通过扫描的 RGB-D 图像,以及扫描相机的内在参数创建点云,方法是通过相机校准,使用相机内在参数计算真实世界的点(x,y)。因此,RGB-D 图像是网格对齐的图像,而点云则是更稀疏的结构。此外,获得点云的较好方法还包括 LiDAR 激光探测与测量,主要通过星载、机载和地面三种方式获取。
根据激光测量原理得到的点云,包括三维坐标(XYZ)和激光反射强度(Intensity),强度信息与目标的表面材质、粗糙度、入射角方向以及仪器的发射能量、激光波长有关。根据摄影测量原理得到的点云,包括三维坐标(XYZ)和颜色信息(RGB)。结合激光测量和摄影测量原理得到点云,包括三维坐标(XYZ)、激光反射强度(Intensity)和颜色信息(RGB)。
1.3 点云的属性[1]
- 空间分辨率、点位精度、表面法向量等。
- 点云可以表达物体的空间轮廓和具体位置,我们能看到街道、房屋的形状,物体距离摄像机的距离也是可知的;其次,点云本身和视角无关,可以任意旋转,从不同角度和方向观察一个点云,而且不同的点云只要在同一个坐标系下就可以直接融合。
2. 使用PointNet进行点云分类[2]
2.1 基础API配置
如果使用colab,请先使用!pip安装trimesh来安装trimesh。
import os
import glob
import trimesh
import numpy as np
import tensorflow as tf
from tensorflow import keras
from tensorflow.keras import layers
from matplotlib import pyplot as plttf.random.set_seed(1234)
2.2 下载数据及数据预处理
我们使用ModelNet10模型数据集,即ModelNet40数据集的较小的10类版本。 首先下载数据:
DATA_DIR = tf.keras.utils.get_file("modelnet.zip","http://3dvision.princeton.edu/projects/2014/3DShapeNets/ModelNet10.zip",extract=True,
)
DATA_DIR = os.path.join(os.path.dirname(DATA_DIR), "ModelNet10")
Downloading data from http://3dvision.princeton.edu/projects/2014/3DShapeNets/ModelNet10.zip 473407488/473402300 [==============================] - 13s 0us/step
我们可以使用trimesh包来读取和可视化.off网格文件。
mesh = trimesh.load(os.path.join(DATA_DIR, "chair/train/chair_0001.off"))
mesh.show()
要将网格文件转换为点云,我们首先需要对网格表面上的点进行采样。 .sample()执行统一的随机采样。 在这里,我们在2048个位置采样并在matplotlib中可视化。
points = mesh.sample(2048)fig = plt.figure(figsize=(5, 5))
ax = fig.add_subplot(111, projection="3d")
ax.scatter(points[:, 0], points[:, 1], points[:, 2])
ax.set_axis_off()
plt.show()
要生成tf.data.Dataset(),我们需要首先通过ModelNet数据文件夹进行解析。 每个网格都被加载并采样到点云中,然后再添加到标准python列表中并转换为numpy数组。 我们还将当前枚举索引值存储为对象标签,并使用字典稍后对其进行调用。
def parse_dataset(num_points=2048):train_points = []train_labels = []test_points = []test_labels = []class_map = {}folders = glob.glob(os.path.join(DATA_DIR, "[!README]*"))for i, folder in enumerate(folders):print("processing class: {}".format(os.path.basename(folder)))# store folder name with ID so we can retrieve laterclass_map[i] = folder.split("/")[-1]# gather all filestrain_files = glob.glob(os.path.join(folder, "train/*"))test_files = glob.glob(os.path.join(folder, "test/*"))for f in train_files:train_points.append(trimesh.load(f).sample(num_points))train_labels.append(i)for f in test_files:test_points.append(trimesh.load(f).sample(num_points))test_labels.append(i)return (np.array(train_points),np.array(test_points),np.array(train_labels),np.array(test_labels),class_map,)
将点数设置为样本和批处理大小,然后解析数据集。 这可能需要5分钟才能完成。
NUM_POINTS = 2048
NUM_CLASSES = 10
BATCH_SIZE = 32train_points, test_points, train_labels, test_labels, CLASS_MAP = parse_dataset(NUM_POINTS
)
processing class: bathtub processing class: desk processing class: monitor processing class: sofa processing class: chair processing class: toilet processing class: dresser processing class: table processing class: bed processing class: night_stand
现在,我们的数据可以读取到tf.data.Dataset()对象中。 我们将改组缓冲区大小设置为数据集的整个大小,因为在此之前按类对数据进行排序。 在使用点云数据时,数据扩充很重要。 我们创建一个增强函数来抖动和随机化火车数据集。
def augment(points, label):# jitter pointspoints += tf.random.uniform(points.shape, -0.005, 0.005, dtype=tf.float64)# shuffle pointspoints = tf.random.shuffle(points)return points, labeltrain_dataset = tf.data.Dataset.from_tensor_slices((train_points, train_labels))
test_dataset = tf.data.Dataset.from_tensor_slices((test_points, test_labels))train_dataset = train_dataset.shuffle(len(train_points)).map(augment).batch(BATCH_SIZE)
test_dataset = test_dataset.shuffle(len(test_points)).batch(BATCH_SIZE)
2.3 建立模型
每个卷积和完全连接的层(端层除外)由卷积/密集->批归一化-> ReLU激活组成。
def conv_bn(x, filters):x = layers.Conv1D(filters, kernel_size=1, padding="valid")(x)x = layers.BatchNormalization(momentum=0.0)(x)return layers.Activation("relu")(x)def dense_bn(x, filters):x = layers.Dense(filters)(x)x = layers.BatchNormalization(momentum=0.0)(x)return layers.Activation("relu")(x)
PointNet由两个核心组件组成。 主MLP网络和变压器网络(T-net)。 T-net旨在通过自己的小型网络学习仿射变换矩阵。 T网被使用了两次。 第一次将输入要素(n,3)转换为规范表示。 第二个是仿射变换,用于在特征空间(n,3)中对齐。 根据原始论文,我们将变换约束为接近正交矩阵(即|| X * X ^ T-I || = 0)。
class OrthogonalRegularizer(keras.regularizers.Regularizer):def __init__(self, num_features, l2reg=0.001):self.num_features = num_featuresself.l2reg = l2regself.eye = tf.eye(num_features)def __call__(self, x):x = tf.reshape(x, (-1, self.num_features, self.num_features))xxt = tf.tensordot(x, x, axes=(2, 2))xxt = tf.reshape(xxt, (-1, self.num_features, self.num_features))return tf.reduce_sum(self.l2reg * tf.square(xxt - self.eye))
然后,我们可以定义一个通用功能来构建T-net层。
def tnet(inputs, num_features):# Initalise bias as the indentity matrixbias = keras.initializers.Constant(np.eye(num_features).flatten())reg = OrthogonalRegularizer(num_features)x = conv_bn(inputs, 32)x = conv_bn(x, 64)x = conv_bn(x, 512)x = layers.GlobalMaxPooling1D()(x)x = dense_bn(x, 256)x = dense_bn(x, 128)x = layers.Dense(num_features * num_features,kernel_initializer="zeros",bias_initializer=bias,activity_regularizer=reg,)(x)feat_T = layers.Reshape((num_features, num_features))(x)# Apply affine transformation to input featuresreturn layers.Dot(axes=(2, 1))([inputs, feat_T])
然后,可以使用将t-net微型模型放在图中的各层中的相同方式来实现主网络。 在这里,我们复制了原始论文中发布的网络体系结构,但由于使用的是10类较小的ModelNet数据集,因此每层的权重只有一半。
inputs = keras.Input(shape=(NUM_POINTS, 3))x = tnet(inputs, 3)
x = conv_bn(x, 32)
x = conv_bn(x, 32)
x = tnet(x, 32)
x = conv_bn(x, 32)
x = conv_bn(x, 64)
x = conv_bn(x, 512)
x = layers.GlobalMaxPooling1D()(x)
x = dense_bn(x, 256)
x = layers.Dropout(0.3)(x)
x = dense_bn(x, 128)
x = layers.Dropout(0.3)(x)outputs = layers.Dense(NUM_CLASSES, activation="softmax")(x)model = keras.Model(inputs=inputs, outputs=outputs, name="pointnet")
model.summary()
2.4 训练模型
一旦定义了模型,就可以像使用任何其他标准分类模型一样使用.compile()和.fit()对其进行训练。
model.compile(loss="sparse_categorical_crossentropy",optimizer=keras.optimizers.Adam(learning_rate=0.001),metrics=["sparse_categorical_accuracy"],
)model.fit(train_dataset, epochs=20, validation_data=test_dataset)
Epoch 1/20 125/125 [==============================] - 28s 221ms/step - loss: 3.5897 - sparse_categorical_accuracy: 0.2724 - val_loss: 5804697916006203392.0000 - val_sparse_categorical_accuracy: 0.3073 Epoch 2/20 125/125 [==============================] - 27s 215ms/step - loss: 3.1970 - sparse_categorical_accuracy: 0.3443 - val_loss: 836343949164544.0000 - val_sparse_categorical_accuracy: 0.3425 Epoch 3/20 125/125 [==============================] - 27s 215ms/step - loss: 2.8959 - sparse_categorical_accuracy: 0.4260 - val_loss: 15107376738729984.0000 - val_sparse_categorical_accuracy: 0.3084 Epoch 4/20 125/125 [==============================] - 27s 215ms/step - loss: 2.7148 - sparse_categorical_accuracy: 0.4939 - val_loss: 6823221.0000 - val_sparse_categorical_accuracy: 0.3304 Epoch 5/20 125/125 [==============================] - 27s 215ms/step - loss: 2.5500 - sparse_categorical_accuracy: 0.5560 - val_loss: 675110905872323182592.0000 - val_sparse_categorical_accuracy: 0.4493 Epoch 6/20 125/125 [==============================] - 27s 215ms/step - loss: 2.3595 - sparse_categorical_accuracy: 0.6081 - val_loss: 600389124096.0000 - val_sparse_categorical_accuracy: 0.5749 Epoch 7/20 125/125 [==============================] - 27s 215ms/step - loss: 2.2485 - sparse_categorical_accuracy: 0.6394 - val_loss: 680423464582760103936.0000 - val_sparse_categorical_accuracy: 0.4912 Epoch 8/20 125/125 [==============================] - 27s 215ms/step - loss: 2.1945 - sparse_categorical_accuracy: 0.6575 - val_loss: 44108689408.0000 - val_sparse_categorical_accuracy: 0.6410 Epoch 9/20 125/125 [==============================] - 27s 215ms/step - loss: 2.1318 - sparse_categorical_accuracy: 0.6725 - val_loss: 873314112.0000 - val_sparse_categorical_accuracy: 0.6112 Epoch 10/20 125/125 [==============================] - 27s 215ms/step - loss: 2.0140 - sparse_categorical_accuracy: 0.7018 - val_loss: 13168980992.0000 - val_sparse_categorical_accuracy: 0.6784 Epoch 11/20 125/125 [==============================] - 27s 215ms/step - loss: 1.9929 - sparse_categorical_accuracy: 0.7056 - val_loss: 36888236785664.0000 - val_sparse_categorical_accuracy: 0.6586 Epoch 12/20
2.5 可视化预测
我们可以使用matplotlib可视化我们训练有素的模型性能。
data = test_dataset.take(1)points, labels = list(data)[0]
points = points[:8, ...]
labels = labels[:8, ...]# run test data through model
preds = model.predict(points)
preds = tf.math.argmax(preds, -1)points = points.numpy()# plot points with predicted class and label
fig = plt.figure(figsize=(15, 10))
for i in range(8):ax = fig.add_subplot(2, 4, i + 1, projection="3d")ax.scatter(points[i, :, 0], points[i, :, 1], points[i, :, 2])ax.set_title("pred: {:}, label: {:}".format(CLASS_MAP[preds[i].numpy()], CLASS_MAP[labels.numpy()[i]]))ax.set_axis_off()
plt.show()
至此,今天的分享结束了。强烈建议新手能按照上述步骤一步步实践下来,必有收获。
今天代码翻译于:https://keras.io/examples/vision/pointnet/,新入门的小伙伴可以好好看看这个网站,很基础,很适合新手。
当然,这里不得不重点推荐一下这三个网站:
https://tensorflow.google.cn/tutorials/keras/classification
https://keras.io/examples
https://keras.io/zh/
其中keras中文网址中能找到各种API定义,都是中文通俗易懂,如果想看英文直接到https://keras.io/,就可以,这里也有很多案例,也是很基础明白。入门时可以看看。
我是羽峰,还在成长道路上摸爬滚打的小白,希望能够结识一起成长的你,公众号“羽峰码字”,欢迎来撩。
[1] https://zhuanlan.zhihu.com/p/344635951
[2]https://keras.io/examples/vision/pointnet/
【手把手教你】搭建神经网络(3D点云分类)相关推荐
- 阿里云服务器使用教程手把手教你搭建网站by阿里云服务器
阿里云服务器使用教程是用户比较关心的问题,其实很简单,阿里云百科告诉大家如何使用云服务器ECS,如何使用阿里云服务器搭建网站,从服务器购买到网站上线一站式教程: 阿里云服务器购买方面,阿里云百科建议大 ...
- 干货 | 手把手教你搭建一套OpenStack云平台
1 前言 今天我们为一位朋友搭建一套OpenStack云平台. 我们使用Kolla部署stein版本的OpenStack云平台. kolla是用于自动化部署OpenStack的一个项目,它基于dock ...
- 手把手教您搭建 AWS 大数据云平台
随着物联网与云平台的成熟,越来越多的企业选择在云端搭建数据平台.这次 Chat 的目的是通过实战,让大家更好的理解 AWS 大数据平台的架构与功能.主要内容包括: 如何利用 CouldWatch 与 ...
- 听音识情绪 | 程序员手把手教你搭建神经网络,更快get女朋友情绪,求生欲max!⛵
- 「云原生 | Docker」手把手教你搭建镜像仓库并上传/下载镜像
手把手教你搭建镜像仓库 一.选择镜像仓库 二.使用 Docker 官方仓库 1. 注册账号并登录 2. 创建私有仓库 3. 设置私有秘钥 3. 登录 Docker 仓库 4. 上传镜像到 Docker ...
- 云服务器架设网站教程_手把手教你搭建腾讯云服务器入门(图文教程)
本文由博主 威威喵 原创 博客主页:https://blog.csdn.net/smile_running 背景 暑假期间,愁着无聊但也不能荒废学业吧,毕竟以后想靠技术混口饭吃!为了实施自己的计划,特 ...
- 手把手教你搭建腾讯云服务器
手把手教你搭建腾讯云服务器(图文并茂) 威威貓 2019-03-28 08:10:28 58357 收藏 162 分类专栏: 杂七杂八 文章标签: 服务器搭建 腾讯云服务器 云服务器环境配置 新手 ...
- OceanBase技术直播间开播啦!蚂蚁金服技术专家手把手教你搭建OB数据库~
OceanBase技术直播间是OceanBase为用户和技术爱好者带来的系列技术直播课程,由蚂蚁金服一线技术专家分享最全面的理论知识和最实用的技术实践,内容包含数据库内核系列.手把手实操系列和最佳实践 ...
- 保姆级教程:手把手教你搭建个人网站
保姆级教程:手把手教你搭建个人网站 前言 准备与搭建 1.Git管理工具的下载与安装 2.nodejs环境安装 3.hexo博客框架下载 npm换国内源 使用npm下载hexo博客框架 初始化mybl ...
- 手把手教你搭建惊艳的博客
系列文章目录 第一章 手把手教你搭建自己的博客 文章目录 系列文章目录 前言 一.网站软件的选择 二.网站空间的选择 1. 建议选择有名.大厂的 2. 上手容易,丰富而详实的文档 3. 要稳定,少出问 ...
最新文章
- Linux服务端最大并发数是多少?
- spring中是如何解析@Profile注解的
- Java工程师之SpringBoot系列教程前言目录
- sts从mysql数据库中反向生成实体类
- SoringMVC-常用注解标签详解(摘抄)
- 【译】LXC and LXD: Explaining Linux Containers
- [BC]Four Inages Strategy(三维空间判断正方形)
- mysql 主从同步-读写分离
- 《TCP/IP详解》学习笔记(七):广播和多播、IGMP协议
- 学习思考 耐得寂寞 拥得繁华
- window.location.href的使用方法
- 无线桥接dhcp服务器关闭吗,光猫桥接要关闭dhcp吗
- 饼状统计图php,制作圆饼统计图
- 利用RTFtemplate生成rtf报表
- c语言嵌入式系统修炼之道
- 支付宝 微信 内购 支付
- 题库(1)_判断一个数是不是水仙花数
- SAS系统学习之初探
- CoAP协议学习笔记——CoAP格式详解
- [目标检测]论文翻译代码理解-SCRDet: Towards More Robust Detection for Small, Cluttered and Rotated Objects
热门文章
- 孩子写作业用护眼台好吗?光照柔和的护眼灯有效缓解眼疲劳
- win10查询计算机显卡,windows10系统电脑查看显卡型号的两种方法
- Linux系统定时任务
- 家用计算机的计算速度,计算机CPU运算速度是多少
- 百度优化排名_思路和步骤
- 【ERP软件】ERP体系二次开发有哪些危险?
- 虚拟服务器磁盘 厚置备置零,VMware ESXi 虚拟硬盘格式记录:厚置备延迟置零、厚置备置零、精简置备...
- 看《当幸福来敲门》观后感
- xd使用技巧_Adobe XD —你不知道的30条提示和技巧!
- 聊聊Java中代码优化的30个小技巧