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}
\]
其中extrinsic给numpy,intrinsic可以由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