【小白深度教程 1.13】手把手教你使用 Open3D ,简明教程(含 Python 代码)
Open3D是一个开源库,支持处理3D数据的软件的 快速开发
它是由英特尔实验室的研究人员周乾一、Jaesik Park和Vladlen Koltun 开发的,这是对应的论文:
http://www.open3d.org/wordpress/wp-content/paper.pdf
1. 创建环境
conda create -n open3denv python=3.6
conda activate open3denv
conda install -c open3d-admin open3d==0.8.0.0
- 1
- 2
- 3
2. 下载数据集
http
://graphics.stanford.edu/data/3Dscanrep/
3. 加载点云数据
import open3d as o3d
import wget
url = 'https://raw.githubusercontent.com/PointCloudLibrary/pcl/master/test/bunny.pcd'
#filename = wget.download(url)
pcd = o3d.io.read_point_cloud("bunny.pcd")
print(pcd)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
4. Open3D 文件点云文件格式
#The code below writes a point cloud.
o3d.io.write_point_cloud("copy_of_bunny.pcd", pcd)
- 1
- 2
pcd = o3d.io.read_point_cloud("sample.xyz", format='xyz')
print(pcd)
- 1
- 2
5. Open3D 文件 Mesh 文件格式
# The code below reads and writes a mesh.
print("Testing IO for meshes ...")
#Function to read TriangleMesh from file
mesh = o3d.io.read_triangle_mesh("knot.ply")
print(mesh)
- 1
- 2
- 3
- 4
- 5
- 6
6. 在样例数据使用 Open3D
6.1 Bunny 数据集
import open3d as o3d
import numpy as np
import PIL.Image
import IPython.display
import os
import urllib
import tarfile
import gzip
import zipfile
import shutil
#Download the point cloud using below command
import wget
url = 'http://graphics.stanford.edu/pub/3Dscanrep/bunny.tar.gz'
#filename = wget.download(url)
bunny_path = "bunny"
with tarfile.open(bunny_path + ".tar.gz") as tar:
tar.extractall(path=os.path.dirname(bunny_path))
bunny_path = "D:/open3D_env/bunny/reconstruction/bun_zipper.ply"
mesh = o3d.io.read_triangle_mesh(bunny_path)
mesh.compute_vertex_normals()
mesh.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh])
pcd = mesh.sample_points_uniformly(number_of_points=500)
o3d.visualization.draw_geometries([pcd])
- 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
6.2 Happy Buddha 数据集
#Download the Happy Buddha dataset
import wget
url = 'http://graphics.stanford.edu/pub/3Dscanrep/happy/happy_recon.tar.gz'
#filename = wget.download(url)
budha_path = "happy_recon"
with tarfile.open(budha_path + ".tar.gz") as tar:
tar.extractall(path=os.path.dirname(budha_path))
budha_path = "D:/open3D_env/happy_recon/happy_vrip.ply"
mesh_budha = o3d.io.read_triangle_mesh(budha_path)
mesh_budha.compute_vertex_normals()
mesh_budha.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_budha])
pcd_budha = mesh_budha.sample_points_uniformly(number_of_points=500)
o3d.visualization.draw_geometries([pcd_budha])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
6.3 Dragon 数据集
import wget
url = 'http://graphics.stanford.edu/pub/3Dscanrep/dragon/dragon_recon.tar.gz'
#filename = wget.download(url)
dragon_path = "dragon_recon"
with tarfile.open(dragon_path + ".tar.gz") as tar:
tar.extractall(path=os.path.dirname(dragon_path))
dragon_path = "D:/open3D_env/dragon_recon/dragon_vrip.ply"
mesh_dragon = o3d.io.read_triangle_mesh(dragon_path)
mesh_dragon.compute_vertex_normals()
mesh_dragon.compute_vertex_normals()
o3d.visualization.draw_geometries([mesh_dragon])
pcd_dragon = mesh_dragon.sample_points_uniformly(number_of_points=500)
o3d.visualization.draw_geometries([pcd_dragon])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
7. 体素降采样
- 这是点云处理任务的预处理步骤。
- 它取点云和下采样。
- 在1体素中的点被平均,平均后我们得到1点。
为什么要降采样?
-
它使数据的大小更易于管理
-
降低数据的维数,从而实现更快的数据处理
-
减少数据的存储大小
print("Downsample the point cloud with a voxel of 0.05")
downpcd = pcd_dragon.voxel_down_sample(voxel_size=0.05)
o3d.visualization.draw_geometries([downpcd],width=1920, height=1080, left=50, top=50)
- 1
- 2
- 3
另一种实现方式:
import numpy as np
print("Load a ply point cloud, print it, and render it")
#read_point_cloud reads a point cloud from a file. It tries to decode the file based on the extension name.
pcd = o3d.io.read_point_cloud("fragment.ply")
print(pcd)
print(np.asarray(pcd.points))
#draw_geometries visualizes the point cloud.
o3d.visualization.draw_geometries([pcd],width=1920, height=1080, left=50, top=50)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
print("Downsample the point cloud with a voxel of 0.05")
downpcd = pcd.voxel_down_sample(voxel_size=0.05)
o3d.visualization.draw_geometries([downpcd],width=1920, height=1080, left=50, top=50)
- 1
- 2
- 3
8. 裁剪点云
print("Load a polygon volume and use it to crop the original point cloud")
#read_selection_polygon_volume reads a json file that specifies polygon selection area.
vol = o3d.visualization.read_selection_polygon_volume("cropped.json")
#vol.crop_point_cloud(pcd) filters out points. Only the chair remains.
chair = vol.crop_point_cloud(pcd)
o3d.visualization.draw_geometries([chair],width=1920, height=1080, left=50, top=50)
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
加载一个模型,并使用它来裁剪原始点云
9. 点云着色
print("Paint chair")
#paint_uniform_color paints all the points to a uniform color. The color is in RGB space, [0, 1] range.
chair.paint_uniform_color([1, 0.706, 0])
o3d.visualization.draw_geometries([chair], width=1920, height=1080, left=50, top=50)
- 1
- 2
- 3
- 4
- 5
10. 绘制矩形 框
PointCloud几何类型与Open3D中的所有其他几何类型一样具有边界框。
目前,Open3D实现了一个AxisAlignedBoundingBox和一个orientteddboundingbox,它们也可以用来裁剪几何图形。
aabb = chair.get_axis_aligned_bounding_box()
aabb.color = (1, 0, 0)
obb = chair.get_oriented_bounding_box()
obb.color = (0, 1, 0)
o3d.visualization.draw_geometries([chair, aabb, obb])
- 1
- 2
- 3
- 4
- 5
11. Mesh 处理
Open3D有一个3D三角形网格的数据结构,叫做TriangleMesh。下面的代码展示了如何从ply文件中读取三角形网格并打印其顶点和三角形。
#!pip install pillow
# import functions from open3d_tutorial.py
import open3d_tutorial as o3dtut
print("Testing mesh in Open3D...")
mesh = o3dtut.get_knot_mesh()
print(mesh)
print('Vertices:')
print(np.asarray(mesh.vertices))
print('Triangles:')
print(np.asarray(mesh.triangles))
#The TriangleMesh class has a few data fields such as vertices and triangles. Open3D provides direct memory access to these fields via numpy.
print("Try to render a mesh with normals (exist: " +str(mesh.has_vertex_normals()) + ") and colors (exist: " +str(mesh.has_vertex_colors()) + ")")
o3d.visualization.draw_geometries([mesh])
print("A mesh with no normals and no colors does not look good.")
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
print("Computing normal and rendering it.")
mesh.compute_vertex_normals()
print(np.asarray(mesh.triangle_normals))
o3d.visualization.draw_geometries([mesh])
- 1
- 2
- 3
- 4
12. 裁剪 Mesh
我们通过直接操作网格的triangle和triangle_normals数据字段来去除一半的表面。这是通过 numpy 完成的。
print("We make a partial mesh of only the first half triangles.")
#mesh1 = copy.deepcopy(mesh)
mesh1=mesh
mesh1.triangles = o3d.utility.Vector3iVector(
np.asarray(mesh1.triangles)[:len(mesh1.triangles) // 2, :])
mesh1.triangle_normals = o3d.utility.Vector3dVector(
np.asarray(mesh1.triangle_normals)[:len(mesh1.triangle_normals) // 2, :])
print(mesh1.triangles)
o3d.visualization.draw_geometries([mesh1])
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
13. Mesh 着色
Paint_uniform_color用统一的颜色绘制网格。颜色在RGB空间,[0,1]范围内。
print("Painting the mesh")
mesh1.paint_uniform_color([1, 0.706, 0])
o3d.visualization.draw_geometries([mesh1])
- 1
- 2
- 3