深度学习在几何空间中的应用(一):三维可视化
前言目前点云方面的研究是一个热门方向,点云分类、零件分割、语义分割等研究正处于热门研究时期;
深度学习大热以来,渐渐地把二维世界里的框架,或移植,或改进,运用到三维世界中来,那么如何将点云可视化呢?This is a question.
下面让我们一起来探索。
可视化
点云数据准备
如无特别说明,本系列使用的数据是ModelNet40,ModelNet40包含了来自40类的12311个三维形状,其中9843个文件用来训练,2468个文件用来测试。
系统环境操作系统:ubuntu16.04或者windows10,建议在Ubuntu下开发
编程软件:PyCharm
语言环境:Python3.6
python包依赖
使用python3.6读取点云文件,需要提取安装numpy、h5py、mayavi、matplotlib,其中安装mayavi的方法如下(前提:python3.x和64位系统):1
2pip install mayavi
pip install PyQt5 # GUI
故所需要的包有:1
2
3
4
5
6
7import os
import sys
import numpy as np
import h5py
from mayavi import mlab
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
在线方式(ubuntu16.04系统下)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 当前py文件所在的路径
print(BASE_DIR) # 显示py文件当前路径
sys.path.append(BASE_DIR) # 加入到系路径里
# download modelnet40 dataset
# 将数据集下载到当前py文件所处路径里的data文件夹里,假设当前py文件在
# BASE_DIR=E:/PointCloud路径里,那么数据集将下载到E:/PointCloud
DATA_DIR = os.path.join(BASE_DIR, 'data')
if not os.path.exists(DATA_DIR): # 如果不存在此文件夹
os.mkdir(DATA_DIR) # 新建data文件夹
# 数据集应在BASE_DIR/data/modelnet40_ply_hdf5_2048里,如果不存在
# BASE_DIR/data/modelnet40_ply_hdf5_2048文件夹,则下载数据集
# modelnet40_ply_hdf5_2048.zip并解压,且输出.zip文件
if not os.path.exists(os.path.join(DATA_DIR, 'modelnet40_ply_hdf5_2048')):
# 数据集文件网址
www = 'https://shapenet.cs.stanford.edu/media/modelnet40_ply_hdf5_2048.zip'
# 返回path最后的文件名,即zipfile=modelnet40_ply_hdf5_2048.zip
zipfile = os.path.basename(www)
os.system('wget %s; unzip %s' % (www, zipfile)) # wget:下载,unzp: 解压
# zipfile=modelnet40_ply_hdf5_2048.zip
# zipfile[:-4]=modelnet40_ply_hdf5_2048
# 把解压后的文件夹modelnet40_ply_hdf5_2048移到BASE_DIR/data/路径下
os.system('mv %s %s' % (zipfile[:-4], DATA_DIR))
os.system('rm %s' % (zipfile)) # 删除压缩包
离线方式(ubuntu16.04系统或windows10)
如果没有合适的ubuntu环境,那么我们首先通过网站下载数据集,然后利用windows上的解压工具解压到对应的文件夹,文件夹可以对应到在线方式里的路径,本文采用的这种方法,简单粗暴,但是不推荐,不利于代码的自动化。
运行代码或者解压文件夹,将在BASE_DIR/data/modelnet40_ply_hdf5_2048/文件夹里看到一下内容,注意BASE_DIR指的是当前py文件的路径。
读取点云
由上图可以看到,点云文件由.h5文件格式来存储,有关h5格式的介绍请移步这里,下面我们就来读取点云文件,代码如下(以读取ply_data_train1.h5为例):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20"""
读取H5文件里的键值
"""
import h5py
# ply_data_train1.h5路径
H5_FILE = './data/modelnet40_ply_hdf5_2048/ply_data_train1.h5'
def (h5_filename): # 定义python函数,函数体前后空两行
"""
读取H5文件里的键值
:param h5_filename:
:return:
"""
with h5py.File(h5_filename) as f:
return [item for item in f.keys()]
keys = read_h5file_keys(H5_FILE)
print("key is : %s" % keys)
运行,得到以下结果:1key is : ['data', 'faceId', 'label', 'normal']
其中
'data'对应点云xyz坐标
'label'对应标签
'normal'对应法向量
'faceId'未知
我们感兴趣的是键值data和label
紧接着,读取点云数据,代码如下:1
2
3with h5py.File(H5_FILE) as f:
data = f['data'][:]
label = f['label'][:]
由于数据集较大,所以是否读取成功,可以利用PyCharm里的Scientific Mode来查看,开启姿势位View——>Scientific Mode,可追踪变量变化,如下图
运行程序后,就会看到这样的情形,
点击变量data后的View as Array,就可以在右边的SciView里看见数据,ply_data_train1.h5里共有 2048个物体的点云数据,所以范围在data[0]到data[2047]之间,每一个物体共有 2048 个点,每个点的坐标位(x, y, z).
可以打印出data和label的形状:1
2print(data.shape) # (2048, 2048, 3)
print(label.shpae) # (2048, 1)
显示点云获取坐标1
2
3
4
5
6
7
8
9
10
11
12
13import numpy as np
from mayavi import mlab
x = []
y = []
z = []
num_obj = 1079 # 比如显示第756 + 1个物体
max_num_point = 2048 # 最大渲染点的个数,最大是2048个点
# 依次获取x、y、z的坐标 —— 1D array
x = data[num_obj, 0:max_num_point, 0] # shape为(max_num_point, 1)
y = data[num_obj, 0:max_num_point, 1] # shape为(max_num_point, 1)
z = data[num_obj, 0:max_num_point, 2] # shape为(max_num_point, 1)
点云可视化方法一 —— mayavi1
2
3
4
5
6
7
8
9
10
11
12# ——————————————————————————————————————————————————————————————
# mayavi可视化
# ——————————————————————————————————————————————————————————————
# s为points3d()函数的第四个参数,与x,y和z具有相同的形状,为每个点
# 提供关联的标量值,或者返回标量值的函数f(x,y,z)
# 此标量值可用于调整点的颜色和大小。
s = np.sqrt(x ** 2 + y ** 2 + z ** 2 )
# 设置背景为白色,画布大小为300 * 200
fig = mlab.figure(bgcolor=(1, 1, 1), size=(450, 300))
# https://docs.enthought.com/mayavi/mayavi/auto/mlab_helper_functions.html#mayavi.mlab.points3d
figure = mlab.points3d(x, y, z, s, mode="point", colormap='spectral', scale_factor=1)
mlab.show() # 显示3D点云图
Notice: 使用这种方法,电脑较卡顿。
在这里,使用了mlab.points3d()函数来进行可视化,具体参数这里,需要注意的是,坐标(x, y, z)各为1D array,需要与mayavi里的surf等方法进行区别,在使用时,注意追踪变量变化,可视化结果
点云可视化方法一 —— matplotlib1
2
3
4
5
6
7
8
9# ——————————————————————————————————————————————————————————————
# matplotlib——Axes3D可视化
# ——————————————————————————————————————————————————————————————
# 使用Axes3D()创建3D图像对象
fig = plt.figure()
ax = Axes3D(fig)
# 调用散点图绘制方法绘图并显示出来
ax.scatter(x, y, z)
plt.show()
可视化结果
1
2
3
4
5
6
7
8
9# shape_name.txt文件路径
SHAPE_NAME = '../data/modelnet40_ply_hdf5_2048/shape_names.txt'
# 显示对应物体的名称
# 读取SHAPE_NAME文件,并存储为numpy数组形式
shape_name_list = np.loadtxt(SHAPE_NAME, dtype=bytes).astype(str)
# 查询该物体名称
shape_name = shape_name_list[label[num_obj]]
print('label is: %s' % shape_name)
总结mayavi和TVTK配合可以自定义点云颜色,可支持自定义点云颜色,官方范例请点击这里,mayavi运行时较卡顿,自定义程度较高,可视化语义分割和场景分割时很有用;
matplotlib库里的Axes3D对象可视化点云方法较为简单,自定义程度较低,在论文中要想显示精美的可视化效果图,不太建议用matplotlib库;
后续工作
除了用这两个库,还有一些python工具可以进行可视化,如GUI工具:meshlab、CloudCompare、Point Cloud Library库里的cloudviewer函数等
我的研究发现时利用深度学习对点云数据集进行分类、场景分割、语义分割等,可视化工具是必不缺少的一环,下一步准备学习meshlab,思路是把点云及相关颜色信息保存成.obj文件,然后在meshlab里显示,具体工作请关注我的博客,如果志同道合者,十分欢迎与联系,这是我的邮箱。
本文的完整代码如下(已在win10环境下,在PyCharm里运行成功,数据集是提前下好的,建议在Ubuntu系统尝试,体会linux的命令):1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94#! python3
# -*- coding:utf-8 -*-
"""
Author : adoredee
Date : November 28th 2018
BlogName : www.kangzhiheng.top
点云显示
"""
import os
import sys
import numpy as np
import h5py
from mayavi import mlab
from mpl_toolkits.mplot3d import Axes3D
import matplotlib.pyplot as plt
BASE_DIR = os.path.dirname(os.path.abspath(__file__)) # 当前py文件所在的路径
sys.path.append(BASE_DIR) # 显示py文件当前路径
print("the path is: %s" % BASE_DIR) # 加入到系路径里
# ply_data_train1.h5路径
H5_FILE = '../data/modelnet40_ply_hdf5_2048/ply_data_train1.h5'
# shape_names.txt文件路径
SHAPE_NAME = '../data/modelnet40_ply_hdf5_2048/shape_names.txt'
def (h5_filename):
"""
读取H5文件里的键值
:param h5_filename:
:return:
"""
with h5py.File(h5_filename) as f:
return [item for item in f.keys()]
keys = read_h5file_keys(H5_FILE)
print("key is : %s" % keys) # ['data', 'faceId', 'label', 'normal']
with h5py.File(H5_FILE) as f:
data = f['data'][:] # 读取主键'data'的值
label = f['label'][:]
print(data.shape) # 2048组,每组2048个点,每个的值位(x,y,z)
print(label.shape)
x = []
y = []
z = []
num_obj = 1079 # 比如显示第num_obj + 1个物体
max_num_point = 2048 # 最大渲染点的个数,最大是2048个点
x = data[num_obj, 0:max_num_point, 0] * 10 # shape为(max_num_point, 1)
y = data[num_obj, 0:max_num_point, 1] * 10 # shape为(max_num_point, 1)
z = data[num_obj, 0:max_num_point, 2] * 10 # shape为(max_num_point, 1)
# ——————————————————————————————————————————————————————————————
# mayavi可视化
# ——————————————————————————————————————————————————————————————
# s为points3d()函数的第四个参数,与x,y和z具有相同的形状,为每个点
# 提供关联的标量值,或者返回标量值的函数f(x,y,z)
# 此标量值可用于调整点的颜色和大小。
s = np.sqrt(x ** 2 + y ** 2 + z ** 2)
# visualization
fig = mlab.figure(bgcolor=(1, 1, 1), size=(450, 300))
figure = mlab.points3d(x, y, z, s, mode="point", colormap='spectral', scale_factor=0.25)
mlab.show()
'''
# ——————————————————————————————————————————————————————————————
# Axes3D可视化
# ——————————————————————————————————————————————————————————————
# 开始绘图
fig = plt.figure()
ax = Axes3D(fig)
ax.scatter(x, y, z)
plt.show()
'''
# 显示对应物体的名称
# 读取SHAPE_NAME文件,并存储为numpy数组形式
shape_name_list = np.loadtxt(SHAPE_NAME, dtype=bytes).astype(str)
# 查询该物体名称
shape_name = shape_name_list[label[num_obj]]
print('label is: %s' % shape_name)
× 请我吃糖~