0%

OPEN3D_IO

Open3D提供了三种数据结构:

  • 点云 (point cloud)
  • 网格 (mesh)
  • RGB-D图像

点云

点云数据可以有多种格式,其包含的信息常见的有10个维度:位置信息\([x, y, z] \in R^3\),法线\([n_x, n_y, n_z] \in R^3\),颜色\([r, g, b] \in R^3\),强度\(i \in R\)

读写

1
2
3
4
5
import open3d as o3d 
import numpy as np
pcd = o3d.io.read_point_cloud("data/fragment.pcd")
o3d.io.write_point_cloud("first.pcd", pcd)
print(np.asarray(pcd.points))

o3d.io.read_point_cloud(filename, format='auto')其中假如指定了format参数,以下是支持的格式

format Description
xyz 每一行包括 [x,y,z] 三个值,x,y,z 是三维坐标
xyzn 每一行包括 [x,y,z,nx,ny,nz] 六个值,其中nx,ny,nz 是法线
xyzzyrgb 每一行包括 [x,y,z,r,g,b] 六个值,这里r,g,b的范围在[0,1]浮动
pts 第一行是一个整数,表示点的个数。之后每一行包括 [x,y,z,i,r,g,b] 七个值,其中rgb的类型为uint8
ply 这个格式可以包含点云和网格数据,详情请参考这个链接
pcd 请看官方给出的php文件,链接
auto 自动通过后缀名来识别

例如

1
pcd =o3d.io.read_point_cloud("data/fragment.pcd",format='xyz')

numpy转PointCloud

1
2
3
4
5
6
7
8
9
10
xyz = np.asarray(pcd.points)
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(xyz)
pcd.colors = o3d.utility.Vector3dVector(np.random.uniform(size=xyz.shape))
o3d.visualization.draw_geometries([pcd],
zoom=0.3412,
front=[0.4257, -0.2125, -0.8795],
lookat=[2.6172, 2.0475, 1.532],
up=[-0.0694, -0.9768, 0.2024])
print(np.asarray(pcd.points))

可视化

1
2
3
4
5
6
7
8
import open3d as o3d 
import numpy as np
pcd = o3d.io.read_point_cloud("data/fragment.pcd")
o3d.visualization.draw_geometries([pcd],
zoom=0.3412,
front=[0.4257, -0.2125, -0.8795],
lookat=[2.6172, 2.0475, 1.532],
up=[-0.0694, -0.9768, 0.2024])

弹出一个gui,按下h显示支持的命令

image-20230529195249712

网格

网格(Mesh)指的是一种用以表示几何对象的三维数据结构,它是由顶点、边和面组成的。一般面可以由三角面组成,由于三个点就可以确认一个面,所以面定义为三个顶点的序号。

  • 顶点(vertices): 顶点的空间坐标\((x,y,z)\in R^3\)
  • 面 (faces): 组成三角面的三个顶点的序号\((i, j, k)\in R^3\)

读写

1
2
3
4
5
6
7
8
9
10
import open3d as o3d 
import numpy as np
import ipdb
mesh = o3d.io.read_triangle_mesh('data/KnotMesh.ply')
print(mesh)
print('Vertices:')
print(np.asarray(mesh.vertices))
print('Triangles:')
print(np.asarray(mesh.triangles))
o3d.io.write_triangle_mesh("mesh.ply", mesh)

可视化

1
2
3
4
5
6
7
8
9
10
import open3d as o3d 
import numpy as np
import ipdb
mesh = o3d.io.read_triangle_mesh('data/KnotMesh.ply')

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.")
image-20230529200903511

RGB-D图像

读写

1
2
3
4
5
6
7
8
9
10
11
12
import open3d as o3d 
import numpy as np
import ipdb
image = o3d.io.read_image('data/SampleRedwoodRGBDImages/color/00000.jpg')
image = o3d.geometry.Image(np.asarray(image))
depth = o3d.io.read_image('data/SampleRedwoodRGBDImages/depth/00000.png')
rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth(image, depth)
o3d.io.write_image("image.jpg", image)
o3d.io.write_image("depth.png", depth)
print(rgbd_image)
print(np.asarray(rgbd_image.color))
print(np.asarray(rgbd_image.depth))

其中彩色图被转为了灰色图[0, 1],深度图的单位为米。o3d.geometry.Image支持将numpy数组转为Image

转点云

create_from_rgbd_image(rgbd_image, intrinsic, extrinsic=I)

将RGB-D图像转为点云。给定坐标\((u, v)\)处像素的深度\(d\),则对应的3d点云坐标为: \[ \begin{aligned} z = d/depth\_scale \\ x = (u-cx) * z /fx \\ y = (v-cy) * z /fy \end{aligned} \] 其中extrinsicnumpyintrinsic可以由open3d.camera.PinholeCameraIntrinsic生成

1
2
3
4
5
6
7
8
9
intrinsic = o3d.camera.PinholeCameraIntrinsic(width=640, height=480, fx=525, fy=525, cx=319.5, cy=239.5)
pcd = o3d.geometry.PointCloud.create_from_rgbd_image(
rgbd_image,
intrinsic=intrinsic,
extrinsic=np.eye(4))
# Flip it, otherwise the pointcloud will be upside down
pcd.transform([[1, 0, 0, 0], [0, -1, 0, 0], [0, 0, -1, 0], [0, 0, 0, 1]])
o3d.visualization.draw_geometries([pcd])

image-20230529203146624