2、点云数据基础:激光雷达工作原理与数据格式
大家好,我是你们的讲师。今天我们来聊聊点云数据的“根”——激光雷达到底是怎么工作的,以及它吐出来的数据长什么样。
说实话,我刚入行那会儿,也踩过不少坑。比如拿到一份.bin格式的点云,直接当文本打开,结果全是乱码。后来才明白,这玩意儿是二进制,得用专门的解析方式。嗯,咱们今天就把它彻底讲透。
2.1 激光雷达工作原理
激光雷达,英文叫LiDAR(Light Detection And Ranging)。说白了,就是“激光探测与测距”。它的核心任务就一个:测量目标物体的距离。
2.1.1 TOF(飞行时间法)—— 最主流的测距方式
TOF,全称Time of Flight。原理其实很简单:
- 激光器发射一束激光脉冲
- 激光打到目标物体上,反射回来
- 接收器捕获反射光
- 计算发射和接收的时间差 Δt
- 距离 = c × Δt / 2(c是光速)
为什么除以2?因为光走了个来回。你想想看,从雷达到物体,再从物体回雷达,路程是两倍距离。
核心公式:
距离 d = (c × Δt) / 2
其中 c ≈ 3.0 × 10⁸ m/s
我在项目中遇到过一个问题:TOF雷达在强阳光下容易“饱和”。因为太阳光里也有近红外成分,会干扰接收器。后来我们加了窄带滤光片,只让激光雷达自己的波长通过,这才解决了。
2.1.2 机械式 vs 固态 —— 两种主流架构
这里我给大家画个对比,一目了然。
我个人习惯把机械式叫做“老大哥”,固态叫做“新秀”。机械式虽然成熟,但那个旋转电机一旦坏了,整个雷达就废了。我曾经拆过一个坏掉的机械式雷达,里面那个滑环磨得都快断了。
固态雷达呢,没有旋转部件,靠的是光学相控阵或者微振镜来改变激光方向。好处是寿命长、体积小。但视场角目前还做不到360°,一般需要多个拼接。
我的建议:
如果你做自动驾驶测试车,前期用机械式(数据全,好调试)。
如果做量产产品,果断上固态(可靠性高,成本可控)。
2.2 点云数据结构
雷达把距离测出来了,但怎么存成数据呢?这就涉及到点云的数据结构了。
2.2.1 XYZI —— 最基础的点云格式
每个点,至少包含四个信息:
- X:水平方向坐标(米)
- Y:垂直方向坐标(米)
- Z:深度方向坐标(米)
- I:反射强度(Intensity,通常0-255)
为什么要有强度?你想想看,黑色车和白色车,距离一样,但反射回来的光强不一样。强度信息可以用来区分路面标线、车道线等。
一个点的数据结构(C语言表示):
struct PointXYZI {
float x; // 4字节
float y; // 4字节
float z; // 4字节
float intensity; // 4字节
}; // 总共16字节
我在项目中遇到过一个问题:有些雷达会输出额外的信息,比如时间戳、环号(第几根激光束)。这时候就需要自定义结构体了。但最通用的还是XYZI。
2.2.2 PCD格式 —— 点云库的标准格式
PCD(Point Cloud Data)是PCL(Point Cloud Library)定义的格式。它分为两种:
| 类型 | 特点 | 文件大小 | 适用场景 |
|---|---|---|---|
| ASCII PCD | 纯文本,可读性强 | 大 | 调试、小数据量 |
| Binary PCD | 二进制,读写快 | 小(约为ASCII的1/3) | 大规模数据、工程部署 |
一个典型的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 100000
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 100000
DATA ascii
x1 y1 z1 intensity1
x2 y2 z2 intensity2
...
注意:
我曾经犯过一个低级错误——用ASCII格式存了10GB的点云,结果加载花了半小时。后来全部改成Binary格式,加载时间缩短到30秒。所以,生产环境千万别用ASCII。
2.2.3 BIN格式 —— 最原始的二进制格式
BIN格式没有标准头文件,就是纯粹的二进制数据。每个点按固定字节数排列。
以XYZI为例,每个点16字节,那么:
- 第0-3字节:x坐标(float)
- 第4-7字节:y坐标(float)
- 第8-11字节:z坐标(float)
- 第12-15字节:intensity(float)
读取BIN文件的Python代码:
import numpy as np
def read_bin_pointcloud(file_path):
"""读取KITTI格式的.bin点云文件"""
points = np.fromfile(file_path, dtype=np.float32)
points = points.reshape(-1, 4) # 每行4个值: x, y, z, intensity
return points
# 使用示例
pc = read_bin_pointcloud('000001.bin')
print(f"点云点数: {pc.shape[0]}")
print(f"前5个点:\n{pc[:5]}")
避坑指南:
我曾经遇到过一个问题:用np.fromfile读取.bin文件,结果数据全乱了。后来发现是字节序问题——有些雷达用大端序,有些用小端序。解决办法是加一个参数:dtype='<f4'(小端)或dtype='>f4'(大端)。
2.3 三种格式的对比与选择
我把三种格式的优缺点整理成了一张表,方便你快速决策:
| 格式 | 可读性 | 存储效率 | 读取速度 | 标准程度 | 推荐场景 |
|---|---|---|---|---|---|
| XYZI(裸数据) | 低 | 高 | 极快 | 低(自定义) | 嵌入式、实时系统 |
| PCD | 高(ASCII)/ 中(Binary) | 中 | 中 | 高(PCL标准) | 算法开发、可视化 |
| BIN | 极低 | 极高 | 极快 | 低(需约定格式) | 大规模数据集(如KITTI) |
我个人习惯是:开发阶段用PCD(方便可视化),部署阶段用BIN(速度快、体积小)。至于XYZI裸数据,一般只有雷达驱动层才会用到,做上层感知的很少直接接触。
本章小结:
激光雷达的核心是TOF测距,机械式适合研发,固态适合量产。
点云数据最基础的是XYZI,PCD适合开发调试,BIN适合大规模存储。
记住:格式选不对,后面全白费。