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("该点云包含法向量信息")
为什么要先看范围?因为滤波算法的参数(比如半径、阈值)都跟数据范围直接相关。不看数据就调参,那是瞎调。
本章知识体系
下面这张图,是我梳理的点云数据基础的核心脉络:
这张图把本章内容串起来了。从数据结构出发,到文件格式的选择,最后用 Open3D 做验证。这是每个点云项目都必须走的一步。
小技巧:拿到一个新数据集,我第一件事就是可视化看看。有时候数据本身就有问题(比如坐标单位不一致、存在异常点),看一眼就能发现。别急着跑算法,先「看」数据。
好了,点云数据基础就聊到这儿。下一节咱们会基于这些知识,开始动手做滤波实战。记住:地基打牢了,楼才能盖得高。
可可精品资料库