第148篇 3D激光雷达数据处理——点云结构、格式和处理流程
上篇把2D激光雷达的数据处理讲了一遍,从极坐标序列到笛卡尔坐标,再到滤波、聚类、避障。但现在的机器人和自动驾驶项目,用的基本都是3D激光雷达了。3D雷达的数据量比2D大了不止一个数量级,处理方式也完全不同。
之前面试一家做自动驾驶的公司,面试官问我:"你处理过多大的点云?一帧多少点?处理延迟多少?"我当时只说了个大概数字,具体的处理流程和优化手段没讲清楚,面试官明显不太满意。
今天就把3D激光雷达数据处理这件事从头到尾捋一遍。从点云的数据结构、主流文件格式、PCL和Open3D两大工具库,到完整的处理流程,一次讲明白。
点云的数据结构
3D激光雷达每一帧输出的是一组三维空间中的点集合,叫做点云(Point Cloud)。每个点最基本的信息就是三维坐标(x, y, z)。除此之外,很多雷达还会附带反射强度intensity、回波次数echo、时间戳timestamp等附加信息。
用ROS2的消息类型来描述,就是sensor_msgs/PointCloud2:
# PointCloud2消息的核心字段
header # 时间戳 + 坐标系ID
height # 有序点云的行数(无序时为1)
width # 有序点云的列数(无序时为点数)
fields[] # 每个字段的描述(x/y/z/intensity等)
is_bigendian # 字节序
point_step # 每个点的字节数
row_step # 每行的字节数
data[] # 原始二进制数据
is_dense # 是否无无效点
PointCloud2的设计比较底层,直接操作二进制数据效率最高但很不方便。实际开发中一般会把它转换成更容易处理的结构。
PCL(Point Cloud Library)里的pcl::PointCloud<T>是最经典的点云结构:
#include <pcl/point_cloud.h>
#include <pcl/point_types.h>
// 最常用的点类型
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(
new pcl::PointCloud<pcl::PointXYZ>);
// 带颜色和反射强度的
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_i(
new pcl::PointCloud<pcl::PointXYZI>);
// 带RGB颜色的
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud_rgb(
new pcl::PointCloud<pcl::PointXYZRGB>);
Python生态里用的是Open3D:
import open3d as o3d
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(xyz_array)
pcd.colors = o3d.utility.Vector3dVector(rgb_array)
PCL和Open3D的选型是个常见问题。PCL是C++库,功能最全,性能最好,工业项目首选。Open3D是Python库,API更友好,可视化能力强,适合快速原型和算法验证。很多团队的 workflow 是:用Open3D做算法验证,确认效果后用PCL的C++接口重写到生产代码里。
一帧3D点云有多少点?这取决于雷达型号。Velodyne VLP-16是16线,每帧大约30000个点。Velodyne HDL-64是64线,每帧大约130000个点。Livox Mid-40用的是非重复扫描模式,每帧可以达到240000个点。到了RoboSense的128线雷达,单帧点数更多。
点数直接决定了后续算法的计算量。30000个点的处理时间可能在10毫秒以内,但130000个点就可能到50毫秒。如果你的系统要求实时处理(比如自动驾驶要求10Hz以上),就必须在算法层面做优化。
主流点云文件格式
开发过程中经常需要保存和加载点云数据。了解主流文件格式很重要。
PCD格式是PCL的原生格式,分ASCII和二进制两种。ASCII方便调试但文件大,二进制文件小但不可读。实际项目都用二进制:
# PCL保存和读取PCD
import pcl
cloud = pcl.load("scan.pcd")
pcl.save(cloud, "filtered.pcd", format="pcd")
PLY格式是一种通用的3D数据格式,支持点云和网格。它的特点是可以用ASCII模式方便地查看内容,也支持二进制模式。很多三维重建工具输出PLY格式。
LAS/LAZ格式是测绘行业的标准格式。LAZ是LAS的压缩版,文件体积能缩小到原来的10%-20%。如果你的机器人项目涉及室外大场景建图,可能会遇到这种格式。
二进制自定义格式在很多公司的内部项目中很常见。通常是直接内存dump,读写速度最快,但没有通用工具能查看。好处是零解析开销,坏处是换了平台可能要处理字节序问题。
面试时候被问到"你用过什么点云格式",不要只说PCD。把PLY、LAS也提一下,说明你了解不同场景下的选型,这比只认识一种格式加分不少。
点云的读取和可视化
拿到点云数据之后,第一步通常是可视化看看效果。
Open3D的可视化非常简单:
import open3d as o3d
pcd = o3d.io.read_point_cloud("scan.pcd")
print(f"点数: {len(pcd.points)}")
print(f"包围盒: {pcd.get_axis_aligned_bounding_box()}")
# 交互式可视化
o3d.visualization.draw_geometries(
[pcd],
window_name="Point Cloud Viewer",
width=1280, height=720
)
PCL的可视化稍微复杂一点,但功能更强:
#include <pcl/visualization/cloud_viewer.h>
pcl::visualization::CloudViewer viewer("Simple Viewer");
viewer.showCloud(cloud);
while (!viewer.wasStopped()) {
// 主循环
}
在ROS2里,直接把PointCloud2消息发布到一个topic上,Rviz2就能显示。这是调试时最常用的方式,因为可以实时看到传感器数据。
可视化时候有个容易忽略的问题:坐标系。点云数据是在雷达坐标系下的,直接显示可能方向不对。你需要确认坐标系的定义——ROS2里用的是REP-103标准,X前Y左Z上。如果你的雷达坐标系不是这个约定,显示出来的点云方向会跟你预期的不一样。
面试中怎么聊
面试官问3D点云处理,你可以按这个框架回答:先说数据结构(PointCloud2消息、PCL和Open3D的点云类型),再说文件格式(PCD、PLY、LAS的应用场景),然后讲处理流程(降采样→滤波→坐标变换→特征提取),最后结合项目说你在哪个环节踩过坑。
如果面试官追问性能优化,你可以提:体素降采样减少点数、用PCL的OpenMP并行加速、用KD树代替暴力搜索、用SSE/AVX指令集加速向量运算。这些关键词说明你不只是会调API,还理解底层性能瓶颈。面试时候如果能举一个具体的优化案例,比如"我把点云处理从50ms优化到了15ms",会比泛泛而谈有说服力得多。这种用数据说话的面试技巧,适用于所有技术面试。
下一篇讲点云滤波的具体算法。体素降采样、统计滤波、直通滤波、半径滤波,每种滤波的原理、参数选择和适用场景都会展开讲。
如果这篇文章对你有帮助,欢迎点赞、在看、转发三连。 你的支持是我持续更新的最大动力。
「机器人软件开发面试·从入门到精通」连载系列
上一篇:第147篇 2D激光雷达数据处理——扫描数据解析和基本应用
下一篇预告:第149篇 激光雷达点云滤波——体素降采样、统计滤波和直通滤波
有任何问题欢迎评论区留言,我会尽量回复。
DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐



所有评论(0)