2. 点云数据基础

做点云处理,第一步不是调算法,而是搞懂数据本身。

我见过不少新手,上来就怼滤波算法,结果连点云长什么样都没看过。说实话,这就像你还没摸清方向盘,就想上赛道漂移。今天咱们就踏踏实实,把点云数据的基础打牢。

点云数据结构解析

点云是什么?说白了,就是一堆三维点的集合。

每个点通常包含 X、Y、Z 三个坐标值。但光有坐标还不够,很多时候我们还需要额外的属性信息。比如:

  • 强度(Intensity):激光雷达返回信号的强度,对地物分类很有用
  • 颜色(RGB):如果融合了相机数据,每个点可以带上颜色
  • 法向量(Normal):描述点所在表面的朝向,常用于分割和识别
  • 时间戳(Timestamp):对于动态场景,记录每个点的时间信息

我个人习惯把点云理解成一张「三维表格」。每一行是一个点,每一列是一种属性。你想想看,这不就是咱们熟悉的二维表格加了一维吗?

核心要点:点云数据本质上是 N × D 的矩阵,N 是点数,D 是维度(至少3维)。

PCD 与 PLY 文件格式

市面上点云格式很多,但最常用的就两个:PCD 和 PLY。

PCD 格式

这是 Point Cloud Library(PCL)的原生格式。我最早接触点云时用的就是它。PCD 文件结构很清晰:

# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z intensity
SIZE 4 4 4 4
TYPE F F F F
COUNT 1 1 1 1
WIDTH 1000
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 1000
DATA ascii
1.0 2.0 3.0 150
2.0 3.0 4.0 200
...

注意看,头部信息里定义了每个字段的类型和大小。我记得有一次项目里,同事把 intensity 字段的 SIZE 写成了 2 字节,结果读出来的数据全是乱的。嗯,这里要注意:字段定义必须和实际数据严格一致。

PLY 格式

PLY(Polygon File Format)更通用一些,支持网格和点云。它的结构分两部分:

  • 头部:定义元素类型和属性
  • 数据体:可以是 ASCII 或二进制
ply
format ascii 1.0
element vertex 1000
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
end_header
1.0 2.0 3.0 255 0 0
2.0 3.0 4.0 0 255 0
...

我的建议:如果只是存点云,PCD 更轻量;如果需要带颜色或网格信息,PLY 更合适。项目里我一般混着用,看下游工具支持哪个。

使用 Open3D 读取与可视化

工具选对了,事半功倍。Open3D 是我目前最顺手的点云处理库,没有之一。

安装

一行命令搞定:

pip install open3d

读取点云

Open3D 支持 PCD、PLY、XYZ 等多种格式。读取代码极其简洁:

import open3d as o3d

# 读取 PCD 文件
pcd = o3d.io.read_point_cloud("example.pcd")

# 读取 PLY 文件
pcd = o3d.io.read_point_cloud("example.ply")

# 查看基本信息
print(pcd)  # 输出:PointCloud with 1000 points.
print("点的坐标:\n", pcd.points[:5])  # 前5个点

你看,三行代码就搞定了。我曾经用 C++ 的 PCL 库写过同样的功能,代码量至少翻三倍。所以现在教学和快速原型,我首选 Open3D。

可视化

可视化是理解点云最直观的方式。Open3D 的可视化器功能很强大:

# 简单可视化
o3d.visualization.draw_geometries([pcd])

# 带参数的可视化
o3d.visualization.draw_geometries(
    [pcd],
    window_name="我的第一个点云",
    width=800,
    height=600,
    point_show_normal=False
)

运行后你会看到一个 3D 窗口,可以用鼠标拖拽旋转、滚轮缩放。我第一次看到自己加载的点云在屏幕上旋转时,说实话,挺震撼的。

避坑指南:我曾经在服务器上跑可视化,结果报错说没有显示器。Open3D 的可视化需要图形界面支持。如果是在无 GUI 的环境,可以用 o3d.visualization.draw_geometries() 的 non_blocking 模式,或者直接保存截图。

点云的基本属性

拿到点云后,我通常会先检查几个关键属性:

# 获取点数
num_points = len(pcd.points)
print(f"点数:{num_points}")

# 获取坐标范围
import numpy as np
points = np.asarray(pcd.points)
print(f"X范围:{points[:, 0].min():.2f} ~ {points[:, 0].max():.2f}")
print(f"Y范围:{points[:, 1].min():.2f} ~ {points[:, 1].max():.2f}")
print(f"Z范围:{points[:, 2].min():.2f} ~ {points[:, 2].max():.2f}")

# 检查是否有颜色
if pcd.has_colors():
    print("该点云包含颜色信息")
    
# 检查是否有法向量
if pcd.has_normals():
    print("该点云包含法向量信息")

为什么要先看范围?因为滤波算法的参数(比如半径、阈值)都跟数据范围直接相关。不看数据就调参,那是瞎调。

本章知识体系

下面这张图,是我梳理的点云数据基础的核心脉络:

点云数据基础知识体系 数据结构 文件格式 读取与可视化 坐标 (X, Y, Z) 强度 / 颜色 / 法向量 N × D 矩阵 PCD:PCL原生格式 PLY:通用格式 ASCII / 二进制 Open3D 读取 3D 可视化 属性检查 理解数据结构 → 选择合适格式 → 用工具验证

这张图把本章内容串起来了。从数据结构出发,到文件格式的选择,最后用 Open3D 做验证。这是每个点云项目都必须走的一步。

小技巧:拿到一个新数据集,我第一件事就是可视化看看。有时候数据本身就有问题(比如坐标单位不一致、存在异常点),看一眼就能发现。别急着跑算法,先「看」数据。

好了,点云数据基础就聊到这儿。下一节咱们会基于这些知识,开始动手做滤波实战。记住:地基打牢了,楼才能盖得高。

可可精品资料库