第一章:Open3D 基础入门


文档摘要

第一章:Open3D 基础入门 第一章:Open3D 基础入门 1.1 Open3D 简介:3D 数据处理的瑞士军刀 在 3D 数据处理领域,我们常常面临各种挑战:复杂的数据结构、繁琐的算法实现、以及对性能的苛刻要求。Open3D 的出现,正是为了解决这些痛点。它集成了多种功能,包括但不限于: 3D 数据结构: 高效地表示和操作点云 (Point Cloud)、网格 (Mesh)、图像 (Image)、RGBD 图像 (RGBD Image) 和体素网格 (Voxel Grid) 等。 几何处理: 提供丰富的几何算法,例如表面重建、点云配准、网格简化、特征提取等。 可视化: 内置强大的 3D 可视化工具,方便用户直观地观察和分析 3D 数据。

第一章:Open3D 基础入门

第一章:Open3D 基础入门

1.1 Open3D 简介:3D 数据处理的瑞士军刀

在 3D 数据处理领域,我们常常面临各种挑战:复杂的数据结构、繁琐的算法实现、以及对性能的苛刻要求。Open3D 的出现,正是为了解决这些痛点。它集成了多种功能,包括但不限于:

  • 3D 数据结构: 高效地表示和操作点云 (Point Cloud)、网格 (Mesh)、图像 (Image)、RGBD 图像 (RGBD Image) 和体素网格 (Voxel Grid) 等。

  • 几何处理: 提供丰富的几何算法,例如表面重建、点云配准、网格简化、特征提取等。

  • 可视化: 内置强大的 3D 可视化工具,方便用户直观地观察和分析 3D 数据。

  • 场景理解: 支持场景重建、语义分割、目标检测等高级功能。

  • 机器人学集成: 提供与机器人学相关的模块,例如运动规划、碰撞检测等。

Open3D 的设计哲学是 简洁、高效、易用。它提供了友好的 Python 接口和高性能的 C++ 后端,使得用户既能快速原型开发,又能兼顾性能需求。无论你是初学者还是经验丰富的专家,Open3D 都能成为你 3D 数据处理工具箱中的得力助手。

1.2 环境搭建:安装 Open3D

在开始 Open3D 的旅程之前,我们需要先安装好 Open3D 库。Open3D 支持多种操作系统,包括 Windows、macOS 和 Linux。推荐使用 Python 环境进行开发,因为 Open3D 提供了完善的 Python 接口,并且拥有丰富的示例代码和文档。

1.2.1 前提条件

  • Python: 建议使用 Python 3.7 或更高版本。你可以从 Python 官网 下载并安装。

  • pip: Python 的包管理器,通常在安装 Python 时会一同安装。

1.2.2 安装 Open3D (Python)

最简单快捷的安装方式是通过 pip 命令:

pip install open3d

在终端或命令提示符中执行上述命令,pip 会自动下载并安装 Open3D 及其依赖项。

1.2.3 验证安装

安装完成后,我们可以通过一个简单的 Python 脚本来验证 Open3D 是否安装成功:

import open3d as o3d import numpy as np # 创建一个简单的点云 points = np.random.rand(100, 3) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(points) # 可视化点云 o3d.visualization.draw_geometries([pcd])

运行这段代码,如果能够弹出一个窗口,显示一个由随机点组成的点云,则说明 Open3D 安装成功。

1.2.4 其他安装方式 (可选)

除了 pip 安装,Open3D 还提供了其他安装方式,例如:

  • conda: 如果你使用 conda 管理 Python 环境,可以使用 conda 命令安装: conda install -c open3d-admin open3d

  • 源码编译: 对于高级用户或需要定制化编译选项的情况,可以选择从源码编译安装。具体步骤可以参考 Open3D 官方文档。

本教程主要使用 pip 安装方式,因为它简单易用,适合初学者快速上手。

1.3 核心数据结构:Open3D 的积木

Open3D 提供了多种核心数据结构,用于表示不同类型的 3D 数据。理解这些数据结构是使用 Open3D 的基础。本节将介绍最常用的几种数据结构:点云 (PointCloud)、网格 (TriangleMesh) 和图像 (Image)。

1.3.1 点云 (PointCloud)

点云是 3D 空间中点的集合,是表示 3D 几何形状最基本的数据结构之一。它可以由激光扫描仪、深度相机等设备直接获取,也可以从其他 3D 模型转换而来。

在 Open3D 中,点云由 o3d.geometry.PointCloud 类表示。它主要包含以下几个关键属性:

  • points: 存储点云中所有点的坐标,类型为 o3d.utility.Vector3dVector,本质上是一个存储 (x, y, z) 坐标的 NumPy 数组。

  • colors: 可选属性,存储每个点的颜色信息,类型为 o3d.utility.Vector3dVector,存储 (r, g, b) 颜色值,范围通常在 [0, 1] 或 [0, 255]。

  • normals: 可选属性,存储每个点的法向量,类型为 o3d.utility.Vector3dVector,表示点云表面的局部方向。

代码实践 1:创建和可视化点云

import open3d as o3d import numpy as np # 1. 创建一个空的点云对象 pcd = o3d.geometry.PointCloud() # 2. 生成随机点坐标 (NumPy 数组) points = np.random.rand(1000, 3) # 1000 个点,每个点 3 个坐标 (x, y, z) # 3. 将 NumPy 数组转换为 Open3D 的 Vector3dVector pcd.points = o3d.utility.Vector3dVector(points) # 4. 生成随机颜色 (NumPy 数组) colors = np.random.rand(1000, 3) # 5. 将 NumPy 数组转换为 Open3D 的 Vector3dVector pcd.colors = o3d.utility.Vector3dVector(colors) # 6. 可视化点云 o3d.visualization.draw_geometries([pcd])

代码详解 1:

  1. pcd = o3d.geometry.PointCloud(): 创建一个空的 PointCloud 对象。

  2. points = np.random.rand(1000, 3): 使用 NumPy 生成一个 1000x3 的随机数组,作为点的坐标。np.random.rand() 生成 [0, 1) 之间的均匀分布随机数。

  3. pcd.points = o3d.utility.Vector3dVector(points): 将 NumPy 数组 points 转换为 Open3D 的 Vector3dVector 类型,并赋值给 pcd.points 属性。这是将 NumPy 数据导入 Open3D 数据结构的关键步骤。

  4. colors = np.random.rand(1000, 3): 类似地,生成随机颜色。

  5. pcd.colors = o3d.utility.Vector3dVector(colors): 将颜色数据赋值给 pcd.colors 属性。

  6. o3d.visualization.draw_geometries([pcd]): 使用 draw_geometries 函数可视化点云。该函数接受一个几何对象列表作为输入,并将其显示在一个窗口中。

mermaid 图 1:点云创建与可视化流程

代码实践 2:从文件加载点云

Open3D 支持多种点云文件格式,例如 PLY, PCD, XYZ 等。这里以 PLY 文件为例:

import open3d as o3d # 文件路径 (请替换为你的 PLY 文件路径) file_path = "path/to/your/point_cloud.ply" # 从文件加载点云 pcd_load = o3d.io.read_point_cloud(file_path) # 可视化加载的点云 o3d.visualization.draw_geometries([pcd_load])

代码详解 2:

  • file_path = "path/to/your/point_cloud.ply": 你需要将 "path/to/your/point_cloud.ply" 替换为你实际的点云文件路径。

  • pcd_load = o3d.io.read_point_cloud(file_path): 使用 o3d.io.read_point_cloud() 函数从指定路径加载点云数据,返回一个 PointCloud 对象。

  • o3d.visualization.draw_geometries([pcd_load]): 可视化加载的点云。

1.3.2 网格 (TriangleMesh)

网格是由三角形面片组成的 3D 模型,常用于表示物体的表面形状。网格比点云更紧凑,并且包含了拓扑信息(面片之间的连接关系)。

在 Open3D 中,网格由 o3d.geometry.TriangleMesh 类表示。它主要包含以下关键属性:

  • vertices: 存储网格顶点的坐标,类型为 o3d.utility.Vector3dVector

  • triangles: 存储网格三角形面片的顶点索引,类型为 o3d.utility.Vector3iVector。每个三角形由三个顶点索引组成,索引指向 vertices 中的顶点。

  • vertex_normals: 可选属性,存储每个顶点的法向量,类型为 o3d.utility.Vector3dVector

  • vertex_colors: 可选属性,存储每个顶点的颜色信息,类型为 o3d.utility.Vector3dVector

  • triangle_normals: 可选属性,存储每个三角形面片的法向量,类型为 o3d.utility.Vector3dVector

  • triangle_material_ids: 可选属性,存储每个三角形面片的材质 ID,类型为 o3d.utility.IntVector

代码实践 3:创建和可视化网格

import open3d as o3d import numpy as np # 1. 创建一个空的网格对象 mesh = o3d.geometry.TriangleMesh() # 2. 定义顶点坐标 (立方体的 8 个顶点) vertices = np.array([ [0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1] ]) # 3. 定义三角形面片 (立方体的 12 个三角形) triangles = np.array([ [0, 1, 2], [1, 3, 2], # 底面 [4, 5, 6], [5, 7, 6], # 顶面 [0, 4, 1], [1, 5, 4], # 前面 [2, 6, 3], [3, 7, 6], # 后面 [0, 2, 4], [2, 6, 4], # 左面 [1, 3, 5], [3, 7, 5] # 右面 ]) # 4. 将 NumPy 数组转换为 Open3D 的 Vector 类型 mesh.vertices = o3d.utility.Vector3dVector(vertices) mesh.triangles = o3d.utility.Vector3iVector(triangles) # 5. 计算顶点法向量 (用于平滑着色) mesh.compute_vertex_normals() # 6. 可视化网格 o3d.visualization.draw_geometries([mesh])

代码详解 3:

  1. mesh = o3d.geometry.TriangleMesh(): 创建一个空的 TriangleMesh 对象。

  2. vertices = ...: 定义立方体的 8 个顶点坐标。

  3. triangles = ...: 定义立方体的 12 个三角形面片,每个三角形由三个顶点索引组成,索引对应 vertices 数组中的顶点。例如 [0, 1, 2] 表示第一个三角形由 vertices 中索引为 0, 1, 2 的顶点组成。

  4. mesh.vertices = ...mesh.triangles = ...: 将顶点坐标和三角形索引赋值给网格对象。

  5. mesh.compute_vertex_normals(): 计算网格的顶点法向量。法向量对于光照和着色效果非常重要,尤其是在进行平滑着色时。

  6. o3d.visualization.draw_geometries([mesh]): 可视化网格。

代码实践 4:从文件加载网格

Open3D 支持多种网格文件格式,例如 OBJ, STL, OFF 等。这里以 OBJ 文件为例:

import open3d as o3d # 文件路径 (请替换为你的 OBJ 文件路径) file_path = "path/to/your/mesh.obj" # 从文件加载网格 mesh_load = o3d.io.read_triangle_mesh(file_path) # 可视化加载的网格 o3d.visualization.draw_geometries([mesh_load])

代码详解 4:

  • file_path = "path/to/your/mesh.obj": 你需要将 "path/to/your/mesh.obj" 替换为你实际的网格文件路径。

  • mesh_load = o3d.io.read_triangle_mesh(file_path): 使用 o3d.io.read_triangle_mesh() 函数从指定路径加载网格数据,返回一个 TriangleMesh 对象。

  • o3d.visualization.draw_geometries([mesh_load]): 可视化加载的网格。

1.3.3 图像 (Image)

Open3D 也支持处理图像数据,例如 RGB 图像、灰度图像和深度图像。图像数据可以用于纹理映射、图像处理等任务。

在 Open3D 中,图像由 o3d.geometry.Image 类表示。它主要包含以下属性:

  • data: 存储图像像素数据,类型为 NumPy 数组。

  • width: 图像宽度 (像素)。

  • height: 图像高度 (像素)。

  • bytes_per_channel: 每个通道的字节数 (例如,1 表示 8 位图像,2 表示 16 位图像)。

  • channels: 图像通道数 (例如,1 表示灰度图像,3 表示 RGB 图像)。

代码实践 5:创建和可视化图像

import open3d as o3d import numpy as np # 1. 创建一个空的图像对象 image = o3d.geometry.Image() # 2. 生成随机灰度图像数据 (NumPy 数组) image_data = np.random.randint(0, 256, size=(200, 300), dtype=np.uint8) # 200x300 灰度图像 # 3. 将 NumPy 数组设置为图像数据 image.set_data(image_data) # 4. 可视化图像 o3d.visualization.draw_geometries([image])

代码详解 5:

  1. image = o3d.geometry.Image(): 创建一个空的 Image 对象。

  2. image_data = np.random.randint(0, 256, size=(200, 300), dtype=np.uint8): 生成一个 200x300 的 NumPy 数组,作为灰度图像数据。np.random.randint(0, 256) 生成 [0, 255] 之间的随机整数,dtype=np.uint8 指定数据类型为 8 位无符号整数,适合表示灰度图像。

  3. image.set_data(image_data): 将 NumPy 数组 image_data 设置为图像数据。

  4. o3d.visualization.draw_geometries([image]): 可视化图像。

代码实践 6:从文件加载图像

Open3D 支持多种图像文件格式,例如 PNG, JPG, JPEG 等。这里以 PNG 文件为例:

import open3d as o3d # 文件路径 (请替换为你的 PNG 文件路径) file_path = "path/to/your/image.png" # 从文件加载图像 image_load = o3d.io.read_image(file_path) # 可视化加载的图像 o3d.visualization.draw_geometries([image_load])

代码详解 6:

  • file_path = "path/to/your/image.png": 你需要将 "path/to/your/image.png" 替换为你实际的图像文件路径。

  • image_load = o3d.io.read_image(file_path): 使用 o3d.io.read_image() 函数从指定路径加载图像数据,返回一个 Image 对象。

  • o3d.visualization.draw_geometries([image_load]): 可视化加载的图像。

1.3.4 RGBD 图像 (RGBDImage)

RGBD 图像是指同时包含彩色图像 (RGB) 和深度图像 (Depth) 的图像数据。深度图像记录了场景中每个像素到相机的距离信息。RGBD 图像常用于 3D 重建、场景理解等应用。

在 Open3D 中,RGBD 图像由 o3d.geometry.RGBDImage 类表示。它由两个 Image 对象组成:

  • color: 存储彩色图像,类型为 o3d.geometry.Image

  • depth: 存储深度图像,类型为 o3d.geometry.Image

代码实践 7:创建 RGBD 图像

import open3d as o3d import numpy as np # 1. 创建随机 RGB 图像数据 color_data = np.random.randint(0, 256, size=(200, 300, 3), dtype=np.uint8) # 200x300 RGB 图像 # 2. 创建随机深度图像数据 (假设深度值范围为 0-10 米) depth_data = np.random.rand(200, 300).astype(np.float32) * 10 # 200x300 深度图像 # 3. 创建 Open3D Image 对象 color_image = o3d.geometry.Image(color_data) depth_image = o3d.geometry.Image(depth_data) # 4. 创建 RGBDImage 对象 rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth( color_image, depth_image ) # 5. 可视化 RGBD 图像 (默认显示彩色图像) o3d.visualization.draw_geometries([rgbd_image]) # 6. 可视化深度图像 (单独显示深度图像) o3d.visualization.draw_geometries([depth_image])

代码详解 7:

  1. color_data = ...depth_data = ...: 分别生成随机 RGB 图像数据和深度图像数据。深度图像数据通常使用浮点数类型 np.float32 表示。

  2. color_image = ...depth_image = ...: 将 NumPy 数组转换为 Open3D Image 对象。

  3. rgbd_image = o3d.geometry.RGBDImage.create_from_color_and_depth(...): 使用静态方法 create_from_color_and_depth() 从彩色图像和深度图像创建 RGBDImage 对象。

  4. o3d.visualization.draw_geometries([rgbd_image]): 可视化 RGBD 图像,默认显示彩色图像。

  5. o3d.visualization.draw_geometries([depth_image]): 单独可视化深度图像。

1.3.5 体素网格 (VoxelGrid)

体素网格是一种将 3D 空间划分为规则网格的数据结构,每个网格单元称为体素 (Voxel)。体素网格常用于空间离散化、占用栅格地图、3D 体积渲染等应用。

在 Open3D 中,体素网格由 o3d.geometry.VoxelGrid 类表示。它主要包含以下属性:

  • voxels: 存储体素信息,类型为 std::unordered_map<Eigen::Vector3i, Voxel>,使用哈希表存储体素索引和体素对象。

  • voxel_size: 体素大小 (立方体边长)。

  • origin: 体素网格的原点坐标。

代码实践 8:从点云创建体素网格

import open3d as o3d import numpy as np # 1. 创建一个随机点云 points = np.random.rand(2000, 3) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(points) # 2. 设置体素大小 voxel_size = 0.1 # 3. 从点云创建体素网格 voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(pcd, voxel_size=voxel_size) # 4. 可视化体素网格 o3d.visualization.draw_geometries([voxel_grid])

代码详解 8:

  1. points = ...pcd = ...: 创建一个随机点云。

  2. voxel_size = 0.1: 设置体素大小为 0.1。

  3. voxel_grid = o3d.geometry.VoxelGrid.create_from_point_cloud(...): 使用静态方法 create_from_point_cloud() 从点云创建体素网格。该方法会将点云中的点离散化到体素网格中。

  4. o3d.visualization.draw_geometries([voxel_grid]): 可视化体素网格。

1.4 基本操作:文件 I/O 和数据转换

掌握了 Open3D 的核心数据结构之后,我们需要学习如何进行基本的操作,例如文件 I/O 和数据转换。

1.4.1 文件 I/O

Open3D 提供了方便的文件 I/O 接口,可以加载和保存各种 3D 数据文件格式。我们在前面的代码实践中已经接触了 o3d.io.read_point_cloud(), o3d.io.read_triangle_mesh(), o3d.io.read_image() 等读取函数。

代码实践 9:保存点云和网格到文件

import open3d as o3d import numpy as np # 创建一个点云 points = np.random.rand(100, 3) pcd = o3d.geometry.PointCloud() pcd.points = o3d.utility.Vector3dVector(points) # 创建一个网格 (这里使用立方体网格) mesh = o3d.geometry.TriangleMesh() vertices = np.array([ [0, 0, 0], [1, 0, 0], [0, 1, 0], [1, 1, 0], [0, 0, 1], [1, 0, 1], [0, 1, 1], [1, 1, 1] ]) triangles = np.array([ [0, 1, 2], [1, 3, 2], [4, 5, 6], [5, 7, 6], [0, 4, 1], [1, 5, 4], [2, 6, 3], [3, 7, 6], [0, 2, 4], [2, 6, 4], [1, 3, 5], [3, 7, 5] ]) mesh.vertices = o3d.utility.Vector3dVector(vertices) mesh.triangles = o3d.utility.Vector3iVector(triangles) # 保存点云到 PLY 文件 o3d.io.write_point_cloud("output_point_cloud.ply", pcd) # 保存网格到 OBJ 文件 o3d.io.write_triangle_mesh("output_mesh.obj", mesh) print("点云和网格已保存到 output_point_cloud.ply 和 output_mesh.obj 文件")

代码详解 9:

  • o3d.io.write_point_cloud("output_point_cloud.ply", pcd): 使用 o3d.io.write_point_cloud() 函数将点云 pcd 保存到名为 "output_point_cloud.ply" 的 PLY 文件中。

  • o3d.io.write_triangle_mesh("output_mesh.obj", mesh): 使用 o3d.io.write_triangle_mesh() 函数将网格 mesh 保存到名为 "output_mesh.obj" 的 OBJ 文件中。

Open3D 还提供了 o3d.io.write_image() 函数用于保存图像到文件。

1.4.2 数据转换

Open3D 允许在不同的数据结构之间进行转换,例如点云和网格之间的转换。

代码实践 10:点云转换为网格 (Ball Pivoting 算法)

import open3d as o3d import numpy as np # 1. 加载点云 (例如,从 bunny.ply 文件加载) pcd = o3d.io.read_point_cloud("path/to/bunny.ply") # 请替换为你的 bunny.ply 文件路径 # 2. 使用 Ball Pivoting 算法进行表面重建,将点云转换为网格 radii = [0.01, 0.02, 0.04, 0.08] # 多尺度半径 bp_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting( pcd, o3d.utility.DoubleVector(radii) ) # 3. 可视化重建的网格 o3d.visualization.draw_geometries([bp_mesh])

代码详解 10:

  1. pcd = o3d.io.read_point_cloud("path/to/bunny.ply"): 加载点云数据。你需要将 "path/to/bunny.ply" 替换为你实际的 bunny.ply 文件路径 (Open3D 示例数据中通常包含 bunny.ply)。

  2. bp_mesh = o3d.geometry.TriangleMesh.create_from_point_cloud_ball_pivoting(...): 使用 create_from_point_cloud_ball_pivoting() 静态方法,基于 Ball Pivoting 算法将点云 pcd 转换为网格 bp_meshradii 参数指定了多尺度球的半径,用于控制重建的细节程度。

  3. o3d.visualization.draw_geometries([bp_mesh]): 可视化重建的网格。


作者与出处
原作者: 灏天文库
来源:灏天文库
整理: 灏天文库整理
由灏天文库平台收录,内容或由平台用户上传,仅供学习交流
发布者: 作者: 灏天文库 转发
评论区 (0)
U