FiftyOne 3D Visual AI 实战指南:点云、网格与 3D 标注的完整数据工作流
【免费下载链接】fiftyoneRefine high-quality datasets and visual AI models项目地址: https://gitcode.com/GitHub_Trending/fi/fiftyone
本指南基于 FiftyOne 官方 3D Visual AI Guide(见 docs/source/getting_started/threed_visual_ai/index.rst),系统讲解如何在 FiftyOne 中完成从原始 3D 数据(LiDAR 点云、GLTF/OBJ/PLY/STL/FBX 网格)的加载与可视化,到 3D 边界框、3D 折线等标注的叠加、查询与校验的完整工作流。读完本文,你将掌握fo.Scene()场景构建、FO3D 文件格式、3D 查看器交互导航,以及 2D/3D 标注类自动切换的核心用法,可直接应用于自动驾驶、机器人、AR/VR 等空间计算场景的数据整理与模型训练准备。
指南概述:一条完整的 3D 数据处理链路
官方指南将整个 3D 工作流拆解为两个循序渐进的步骤(对应两个 Jupyter Notebook):
- 入门 3D 数据集(Getting Started with 3D Datasets)——学习如何在 FiftyOne 中加载和可视化原始 3D 数据(含点云),在 3D 查看器中完成基本导航,并围绕空间任务组织数据集。对应文件:01_getting_started_3d.ipynb。
- 加载 3D 标注(Loading 3D Annotations)——为点云添加边界框与标签等标注,学习如何引入标注并使其无缝叠加到场景中,用于检查与验证。对应文件:02_loading_annotations.ipynb。
两个 Notebook 均可独立运行——每个文件开头都包含必要的pip install命令,无需预先配置任何环境。
前置条件
目标读者:面向希望在 FiftyOne 中处理 3D 数据集的开发者与计算机视觉工程师。无论你面对的是 LiDAR 点云、体素网格还是 3D 边界框,本系列都会介绍所需的工具与工作流。
所需知识:熟悉 FiftyOne 的数据集结构(Dataset/Sample/ 标签字段体系)与基础计算机视觉概念即可;有 2D 检测标注经验会更快上手,点云或 3D 标注经验非必需。
主要依赖包:
| 包 | 用途 |
|---|---|
fiftyone | 核心库:数据集管理、场景构建与 3D 可视化 |
open3d | 3D 数据处理与点云操作(可选辅助) |
numpy | 数值运算与数组操作 |
matplotlib | 可视化与绘图 |
系统要求(按官方指南):
- 操作系统:Linux(Ubuntu 24.04)、macOS
- Python:3.10、3.11、3.12
- 内存:3D 操作建议 8GB RAM
- 存储:预留 5GB 可用空间存放 3D 数据集
- 显卡:大型点云可视化建议配备 GPU
- Notebook 环境:Jupyter、Google Colab、VS Code Notebook 均已验证
3D 数据格式全景
点云(Point Clouds)
- LiDAR 数据——来自自动驾驶车辆与机器人的原始传感器数据
- PLY 格式——带颜色与法线信息的标准点云格式(亦可表示网格)
- PCD 格式——面向高效存储的点云数据格式,是 FiftyOne
PointCloud对象直接支持的类型 - XYZ 格式——基于简单坐标系的点云表示
3D 网格(3D Meshes)
- GLTF/GLB——现代 3D 格式,支持材质与动画
- OBJ——Wavefront Object 格式,常用于 3D 几何建模
- PLY——Stanford Triangle 格式,可表示网格或点云
- STL——用于 3D 打印的立体光刻格式
- FBX——Autodesk 3D 内容交换格式(支持 FBX 7.x+)
3D 标注(3D Annotations)
- 3D 边界框(3D Bounding Boxes)——目标检测,包含位置、尺寸与旋转
- 3D 折线(3D Polylines)——3D 空间中的路径与车道线标注
- 3D 分割(3D Segmentation)——面向语义理解的点级标注
核心工作流:加载 → 场景管理 → 可视化 → 标注集成
官方指南演示的完整 3D 数据工作流由四步组成:
- 数据加载(Data Loading)——以正确的坐标系与变换加载不同 3D 格式(点云、网格)
- 场景管理(Scene Management)——使用 FiftyOne 的
Scene类与 FO3D 文件格式创建、组织 3D 场景 - 3D 可视化(3D Visualization)——在 FiftyOne 交互式 3D 查看器中导航与交互
- 标注集成(Annotation Integration)——添加 3D 边界框、折线等标注,支撑综合分析
这套集成式方案不仅让你"能加载"3D 数据,更能理解空间关系、管理复杂 3D 场景,并面向 3D 计算机视觉应用准备数据集。
Step 1:入门 3D 数据集
理解 FiftyOne Scene 与 FO3D 文件
FiftyOne 通过fo.Scene()管理 3D 样本,其序列化产物即FO3D 文件(.fo3d后缀)。从源码看,Scene本质是一个场景图:内部以 n 叉树结构组织 3D 对象,每个对象是树中的一个节点(参见 fiftyone/core/threed/scene_3d.py 中Scene类定义)。一个 3D 对象可以是:
- 3D 网格(Mesh)——
ObjMesh、GltfMesh、PlyMesh、StlMesh、FbxMesh - 点云(Point Cloud)——
PointCloud - 3D 形状几何(Shape Geometry)——
BoxGeometry、SphereGeometry等(参见 fiftyone/core/threed/shape_3d.py)
Scene还可显式初始化camera、lights、background等附加属性。默认情况下,场景使用中性光照(一个环境光加六个不同角度的方向光),并使用右手坐标系、up 轴为 Y 轴的透视相机——可通过PerspectiveCamera(up="Z")等参数覆盖(相机类定义见 fiftyone/core/threed/camera.py,支持up/fov/near/far参数,默认 fov=50、near=0.1、far=2000)。
场景构建完成后,必须调用scene.write()将其序列化为轻量级 FO3D 文件写入磁盘。从源码(scene_3d.py)可以看到,write()会校验输出路径必须以.fo3d结尾、检查节点重名,并支持resolve_relative_paths(将资源相对路径解析为绝对路径)与pprint(JSON 美化输出)两个选项。
如何加载一个 3D 样本
任何 filepath 以.fo3d结尾的 Sample 都会被识别为 3D 样本,由 3D 样本组成的数据集其media_type为3d。你可以在一个.fo3d场景内存储多个 3D 对象,用单个样本封装整个待覆盖的场景。
import fiftyone as fo # 1. 构建场景:设置相机 up 轴为 Z scene = fo.Scene() scene.camera = fo.PerspectiveCamera(up="Z") # 2. 添加自定义网格对象 mesh = fo.GltfMesh("mesh", "mesh.glb") mesh.rotation = fo.Euler(90, 0, 0, degrees=True) # 3. 添加两个几何球体并自定义颜色与位置 sphere1 = fo.SphereGeometry("sphere1", radius=2.0) sphere1.position = [-1, 0, 0] sphere1.default_material.color = "red" sphere2 = fo.SphereGeometry("sphere2", radius=2.0) sphere2.position = [1, 0, 0] sphere2.default_material.color = "blue" scene.add(mesh, sphere1, sphere2) # 4. 写入 FO3D 文件 scene.write("/path/to/scene.fo3d") # 5. 作为样本加入数据集 sample = fo.Sample(filepath="/path/to/scene.fo3d") dataset = fo.Dataset() dataset.add_sample(sample) print(dataset.media_type) # 3d上面这段代码中,mesh.glb与两个球体被一并加入场景:通过position校正各对象位置,通过default_material.color定制颜色,最后整体写出为 FO3D 文件。这正是 FiftyOne 的核心思路——一个.fo3d文件 = 一个完整 3D 场景 = 一个 Sample。
修改既有场景
若要修改已存在的场景,使用Scene.from_fo3d()加载,执行必要的更新后再写回磁盘:
scene = fo.Scene.from_fo3d("/path/to/scene.fo3d") for node in scene.traverse(): if isinstance(node, fo.SphereGeometry): node.visible = False scene.write("/path/to/scene.fo3d")其中traverse()是场景图的深度遍历接口(源码见 scene_3d.py),它递归产出场景中的所有Object3D节点,是批量操作场景内对象的统一入口。与此配套的还有get_scene_summary()(统计各类对象数量)、get_asset_paths()(列出全部资源路径)与update_asset_paths()(按映射批量改写资源路径)等实用方法,均有对应单元测试覆盖(见 tests/unittests/threed/scene_3d_tests.py)。
3D 网格:格式支持与材质处理
3D 网格由顶点、边与面组成,定义对象的几何形状。部分格式只存几何,另一些则同时包含材质属性与纹理——若网格文件含材质与纹理,FiftyOne 会自动加载并显示。你也可以通过设置网格的default_material属性来指定默认材质;当文件不含任何材质信息时,网格会被赋予一个默认的MeshStandardMaterial(含color、roughness、metalness、opacity、emissive_color等参数,见 fiftyone/core/threed/material_3d.py),且可在 App 中动态调整。
FiftyOne 当前支持GLTF、OBJ、PLY、STL、FBX 7.x+网格格式,对应类(见 fiftyone/core/threed/mesh.py):
import fiftyone as fo scene = fo.Scene() mesh1 = fo.GltfMesh("mesh1", "mesh.glb") mesh1.rotation = fo.Euler(90, 0, 0, degrees=True) mesh2 = fo.ObjMesh("mesh2", "mesh.obj") # 可选 mtl_path 参数加载 .mtl 材质 mesh3 = fo.PlyMesh("mesh3", "mesh.ply") # 可选 is_point_cloud / center_geometry mesh4 = fo.StlMesh("mesh4", "mesh.stl") mesh5 = fo.FbxMesh("mesh5", "mesh.fbx") scene.add(mesh1, mesh2, mesh3, mesh4, mesh5) scene.write("/path/to/scene.fo3d")几个值得注意的实现细节(均可在 mesh.py 中验证):
- 路径校验:
ObjMesh要求obj_path以.obj结尾、mtl_path以.mtl结尾,FbxMesh/PlyMesh/StlMesh分别要求.fbx/.ply/.stl,GltfMesh要求.gltf或.glb,否则抛出ValueError;资源路径既可以是绝对路径,也可以相对于.fo3d文件所在目录。 - PLY 的双重身份:
PlyMesh通过is_point_cloud参数区分"网格"与"点云"两种形态,并默认center_geometry=True自动居中几何体。 - OBJ 材质:
ObjMesh支持mtl_path显式关联.mtl材质文件;若未提供或文件中找不到材质,则回退到默认MeshStandardMaterial。
3D 点云:PCD 格式与材质控制
FiftyOne 直接支持PCD 点云格式。创建一个可加入 3D 场景的 PCD 对象:
import fiftyone as fo pcd = fo.PointCloud("my-pcd", "point-cloud.pcd") pcd.default_material.shading_mode = "custom" pcd.default_material.custom_color = "red" pcd.default_material.point_size = 2 scene = fo.Scene() scene.add(pcd) scene.write("/path/to/scene.fo3d")PointCloud类(见 fiftyone/core/threed/pointcloud.py)要求pcd_path以.pcd结尾,并支持center_geometry(默认False)与flag_for_projection(标记用于正交投影,每个场景最多一个)等参数。其默认材质PointCloudMaterial提供以下可调项(见 material_3d.py):
| 参数 | 默认值 | 说明 |
|---|---|---|
shading_mode | "height" | 着色模式,支持height(按高度)、intensity(按强度)、rgb(按颜色)、custom(自定义色) |
custom_color | "#ffffff" | 自定义颜色,仅当shading_mode="custom"时生效 |
point_size | 1.0 | 点的大小 |
opacity | 1.0 | 不透明度,范围[0, 1] |
多传感器点云叠加
3D 场景与点云的一大优势在于:可以在同一场景中堆叠多个点云,以镜像不同传感器的输出。例如,一个 LiDAR 传感器与多个按相同时间间隔触发的 RADAR 传感器——用 FiftyOne 可同时可视化全部点云,也可按需逐个开关。这一设计思路来自Scene的 n 叉树场景图结构:任意数量的网格、点云与形状都可以作为独立节点挂载在同一场景下,通过visible属性控制显示状态。
Step 2:加载 3D 标注
3D 样本上的标注字段
3D 样本可以包含任意类型与数量的自定义字段,包括3D 检测与3D 折线,它们可被 App 的 3D 可视化器原生显示。与几何数据不同的是,3D 标注存储在数据集专门的字段中,而非嵌入 FO3D 文件——因此它们可以像其他原始/标签字段一样,通过数据集视图(dataset views)在 App 中进行查询与过滤。典型用法如下:
import fiftyone as fo scene = fo.Scene() scene.add(fo.GltfMesh("mesh", "mesh.gltf")) scene.write("/path/to/scene.fo3d") detection = fo.Detection( label="vehicle", location=[0.47, 1.49, 69.44], dimensions=[2.85, 2.63, 12.34], rotation=[0, -1.56, 0], ) sample = fo.Sample( filepath="/path/to/scene.fo3d", ground_truth=fo.Detections(detections=[detection]), )3D 边界框参数详解:location / dimensions / rotation
下面逐个拆解location、dimensions、rotation的含义(这些参数在源码 fiftyone/core/labels.py 的Detection类文档中有明确定义):
import fiftyone as fo # 对象标签 label = "vehicle" # 对象中心 [x, y, z],使用场景坐标 location = [0.47, 1.49, 69.44] # 对象尺寸 [x, y, z],使用场景单位 dimensions = [2.85, 2.63, 12.34] # 对象绕其中心的旋转 [x, y, z],取值范围 [-pi, pi] rotation = [0, -1.56, 0] # 一个 3D 目标检测 detection = fo.Detection( label=label, location=location, dimensions=dimensions, rotation=rotation, )关于坐标系的注意点:这里的场景坐标从[0, 0, 0]开始,该原点几乎总是自车(ego)位置,即传感器开始采集的位置;它并不映射到任何已知的全局坐标(如 GPS/UTM)。在做多帧数据融合或跨传感器标注对齐时,务必确认各数据的坐标系约定一致。
3D 折线(Polylines)
3D 折线的用法与 3D 检测高度相似:它同样作为数据集上的专用字段存储,需要label与points3d两个参数:
# 对象标签 label = "lane" # 一个列表的列表,每个元素为场景坐标下的 [x, y, z] 顶点, # 描述折线中每条形状的顶点 points3d = [[[-5, -99, -2], [-8, 99, -2]], [[4, -99, -2], [1, 99, -2]]] # 一组语义相关的 3D 折线 polyline = fo.Polyline(label=label, points3d=points3d)即points3d是一个嵌套结构:外层列表对应多条形状,内层列表对应每条形状的顶点序列,每个顶点是[x, y, z]三元组。这与 2DPolyline的points参数([0,1]×[0,1]归一化坐标)在结构上类似,但坐标语义从归一化平面坐标切换为场景三维坐标。
自动的 2D / 3D 标注类型切换
注意一个关键设计:3D 场景下你并不使用Detection3D或Polyline3D类。FiftyOne 的Detection与Polyline标签类会根据输入参数自动适配 2D 或 3D 形态:
Detection:提供bounding_box(2D)时按 2D 目标检测处理;提供location+dimensions+rotation(3D)时按 3D 目标检测处理(参见 labels.py 的类文档)。Polyline:提供points(2D)或points3d(3D)时分别对应 2D/3D 折线。
这意味着你可以在同一数据集内混用 2D 与 3D 标注,FiftyOne 自动完成区分与可视化,无需维护两套标签体系。
总结:你已经掌握了什么
完成上述两步后,你已具备:
- Step 1(入门 3D 数据集):加载并可视化原始 3D 数据(含点云);理解
Scene类与 FO3D 文件格式;处理 GLTF、OBJ、PLY、STL、FBX 等不同网格格式;在 3D 查看器中完成基本导航;围绕空间任务组织 3D 数据集并理解坐标系。 - Step 2(加载 3D 标注):为点云添加边界框与标签等标注;理解 3D 边界框的
location(位置)、dimensions(尺寸)、rotation(旋转)参数;用 3D 折线做路径标注;掌握 FiftyOne 如何自动处理 2D 与 3D 标注类型。
建议练习
- 多格式 3D 数据:分别用 GLTF、OBJ、PLY、STL 加载同一对象,对比其在 FiftyOne 中的加载与显示差异,评估哪种格式最适合你的场景。
- 3D 场景合成:组合多个网格、点云与几何形状构建复杂 3D 场景,观察场景组织方式对可视化效果的影响。
- 3D 标注分析:混用边界框、折线与分割等不同类型 3D 标注,分析其空间关系。
- 坐标系理解:实验不同的坐标系与变换(如
Euler旋转、相机up轴设置),观察它们如何影响 3D 可视化与标注精度。 - 性能优化:使用大型点云并调节不同可视化设置(如
point_size、着色模式),观察数据规模对性能的影响。
进一步方向
- 评估 3D 目标检测模型:引入预测结果与真值,对 3D 边界框运行性能评估。
- 可视化多模态传感器数据:将点云与 2D 图像、分割掩码等结合,获得全场景理解。
- 构建自定义 3D 工作流:针对自动驾驶、机器人、AR/VR 等具体领域创建专属工作流。
延伸阅读(仓库内资源)
- 指南索引页:docs/source/getting_started/threed_visual_ai/index.rst
- 配套 Notebook ①(场景、网格、点云):01_getting_started_3d.ipynb
- 配套 Notebook ②(3D 标注):02_loading_annotations.ipynb
- 指南总结与练习:summary.rst
- 核心源码:场景与 FO3D 序列化见 fiftyone/core/threed/scene_3d.py,网格类见 fiftyone/core/threed/mesh.py,点云见 fiftyone/core/threed/pointcloud.py,材质见 fiftyone/core/threed/material_3d.py,相机见 fiftyone/core/threed/camera.py,3D 标注定义见 fiftyone/core/labels.py
- 单元测试:tests/unittests/threed/scene_3d_tests.py(覆盖 FO3D 写入/读取、资源路径解析、场景摘要、高斯溅射等)、tests/unittests/threed/transformation_tests.py、tests/unittests/threed/material_3d_tests.py
【免费下载链接】fiftyoneRefine high-quality datasets and visual AI models项目地址: https://gitcode.com/GitHub_Trending/fi/fiftyone
创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考