LiDAR障碍物检测与道路感知工程 - 第2节

2. 点云数据格式解析

做激光雷达感知,第一关就是跟数据格式打交道。我记得刚入行那会儿,拿到一份点云数据,打开一看全是乱码,折腾了半天才发现是字节序搞反了。今天我就把几种常见的点云格式掰开揉碎了讲清楚。

1. PCD 格式——点云库的亲儿子

PCD 是 Point Cloud Library 的标准格式。说白了,它就是为点云处理量身定做的。我个人的习惯是,只要用 PCL 库,数据就存成 PCD,省心。

PCD 文件分两部分:头部和数据体。头部是纯文本,告诉你点云有多少点、每个点有哪些字段。数据体可以是 ASCII 或二进制。

# .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 123456
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 123456
DATA ascii

你看这个头部,FIELDS 定义了每个点的属性。我遇到过最坑的事:有人把 intensity 写成了 intensitiy,结果 PCL 直接报错。嗯,拼写错误要小心。

关键点:PCD 支持多种数据类型——F 是浮点,I 是整型,U 是无符号整型。选错了类型,数据就全乱了。

2. BIN 格式——裸奔的二进制

BIN 格式没有头部,没有元数据,就是纯二进制数据。你想想看,一个文件里全是 01 串,不告诉你每个字节代表什么。这就像给你一把钥匙,但不告诉你哪把锁能开。

为什么还有人用?因为快。自动驾驶场景下,每秒要处理几十万点,BIN 格式读写速度最快。我曾在项目中用 BIN 格式做实时数据流,延迟比 PCD 低了将近 30%。

解析 BIN 文件时,你必须提前知道数据结构。比如 Velodyne 的 BIN 文件,每个点占 16 字节:

struct VelodynePoint {
    float x;      // 4 bytes
    float y;      // 4 bytes
    float z;      // 4 bytes
    float intensity; // 4 bytes
};
避坑指南:我曾经在解析 BIN 文件时,忘了考虑字节序(大端/小端)。结果点云全飞到天上了。后来我养成了习惯:先检查 CPU 的字节序,再决定要不要做转换。

3. LAS 格式——测绘界的标准

LAS 是 ASPRS 制定的标准格式,主要用于测绘和地理信息系统。它比 PCD 复杂得多,除了点坐标和强度,还能存分类信息(比如地面、建筑、植被)。

LAS 文件结构分三块:公共头、变长记录、点数据。公共头固定 227 字节,告诉你点数量、坐标范围、格式类型。变长记录可以存投影信息、元数据。点数据就是每个点的具体值。

字段 偏移量 大小 说明
文件签名 0 4 bytes "LASF"
文件源 ID 4 2 bytes 项目编号
全局编码 6 2 bytes GPS 时间类型等
点数 107 4 bytes 总点数

说实话,LAS 格式在自动驾驶里用得不多,主要是测绘那边在用。但如果你做高精地图,就绕不开它。

点云数据结构:XYZI 与 XYZRGB

点云数据说到底就是一堆点,每个点带几个属性。最常见的两种结构是 XYZI 和 XYZRGB。

XYZI——最常用的结构

XYZI 就是坐标加强度。强度值反映了激光回波的信号强度,对目标识别很有用。比如,路面的强度通常比植被低,金属护栏的强度特别高。

我习惯把 XYZI 存成 pcl::PointXYZI 类型。在代码里是这样:

#include <pcl/point_types.h>

pcl::PointXYZI point;
point.x = 1.23;
point.y = 4.56;
point.z = 7.89;
point.intensity = 128;  // 0-255 范围
小技巧:强度值受距离影响很大。同样一个物体,近处强度高,远处强度低。我一般会做距离归一化,把强度值除以距离的平方,这样不同距离的物体才有可比性。

XYZRGB——带颜色的点云

XYZRGB 就是坐标加颜色。颜色信息通常来自相机图像,通过标定把像素颜色映射到点云上。这样点云就有了视觉信息,做语义分割时特别好用。

颜色在 PCL 里用 uint32_t 存储,RGB 各占 8 位。我见过新手直接赋值 255,结果颜色全乱了。正确的做法是用 pcl::RGB 结构体:

pcl::PointXYZRGB point;
point.x = 1.23;
point.y = 4.56;
point.z = 7.89;

// 正确设置颜色
uint8_t r = 255, g = 128, b = 64;
uint32_t rgb = ((uint32_t)r << 16 | (uint32_t)g << 8 | (uint32_t)b);
point.rgb = *reinterpret_cast<float*>(&rgb);

你想想看,为什么要把 RGB 塞进一个 float 里?因为 PCL 的 PointXYZRGB 结构体里,rgb 字段就是 float 类型。这是一种取巧的做法,用浮点数来存整型数据。

点云可视化工具:CloudCompare 与 rviz

光有数据不行,你得能看见它。我调试算法时,90% 的时间都在看可视化结果。这里介绍两个我常用的工具。

CloudCompare——点云分析利器

CloudCompare 是开源的点云处理软件,功能非常强大。它支持 PCD、LAS、PLY 等多种格式,还能做点云配准、分割、测量。

我个人最喜欢它的两个功能:

  • 颜色编码:按高度、强度、分类等字段给点云上色,一眼就能看出数据分布
  • 剖面工具:切一刀看截面,检查点云质量特别方便

我记得有一次,算法检测出的障碍物位置总偏。用 CloudCompare 打开原始点云,切了个剖面,才发现是标定参数错了,激光雷达装歪了 0.5 度。嗯,这种问题光看代码是看不出来的。

rviz——ROS 生态的标配

如果你用 ROS,rviz 就是标配。它专门用来可视化机器人数据,点云、图像、路径、TF 变换都能显示。

在 rviz 里显示点云很简单:

  1. 启动 rviz:rosrun rviz rviz
  2. 添加 PointCloud2 显示插件
  3. 选择话题名,比如 /velodyne_points
  4. 设置颜色编码方式:XYZ、Intensity、RGB 都行
实用技巧:rviz 的 Decay Time 参数很有用。设成 0.5 秒,点云会保留半秒,这样能看到运动轨迹。我调试目标跟踪时,经常用这个功能看检测框是否稳定。

说实话,CloudCompare 和 rviz 各有千秋。CloudCompare 适合离线分析,功能全、精度高。rviz 适合在线调试,实时性好、与 ROS 无缝集成。我一般两个都用:白天用 rviz 调算法,晚上用 CloudCompare 做深度分析。

注意:rviz 对点云数量有限制。超过 100 万点,帧率会明显下降。我遇到过有人直接加载 500 万点的 PCD 文件,rviz 直接卡死。解决办法是降采样,或者用 VoxelGrid 滤波器减少点数。

好了,关于点云数据格式和可视化,我就讲这么多。这些内容看着简单,但都是基本功。我见过太多人因为格式问题浪费大量时间。记住一句话:数据格式搞不清楚,后面的算法全是空中楼阁。