2. 点云数据基础
大家好,我是你们的老朋友。今天咱们正式开讲《激光雷达点云滤波全流程解析》的第一章。说实话,每次带新人入门,我都要先跟他们聊聊点云数据的基础。为啥?因为很多坑,都是基础不牢导致的。
我记得刚入行那会儿,拿到一个PCD文件就直接开干,结果程序跑起来各种报错。后来才发现,连点云里存的是啥都没搞清楚。嗯,咱们今天就把这块地基打扎实。
1.1 PCL库简介
PCL,全称Point Cloud Library,是点云处理领域最常用的开源库。我个人习惯把它比作「点云界的OpenCV」。你想想看,从点云滤波、配准、分割到识别,几乎你能想到的点云操作,它都给你封装好了。
PCL的核心优势在于:
- 模块化设计:每个功能模块独立,按需引入
- 算法丰富:滤波、特征估计、配准、分割等一应俱全
- 社区活跃:遇到问题基本都能搜到解决方案
- 跨平台:Windows、Linux、macOS都能跑
重要提示:PCL的版本兼容性是个老生常谈的问题。我建议你统一使用1.8.x或1.9.x系列,这两个版本最稳定,坑最少。
我在项目中遇到过最头疼的事,就是不同版本的PCL编译出来的库文件不兼容。所以,团队内部一定要统一版本号,不然联调的时候有你受的。
1.2 点云数据结构
点云数据,说白了就是一堆三维点的集合。但PCL里把这些点组织得很有讲究。咱们重点看两种最常用的:PointXYZ和PointXYZRGB。
1.2.1 PointXYZ
这是最基础的点类型。只存三个坐标值:x、y、z。结构体定义大概长这样:
struct PointXYZ {
float x;
float y;
float z;
};
简单吧?但别小看它。我刚开始做项目时,以为点云就是一堆(x,y,z)堆在一起。后来才发现,PCL里每个点还带了一个padding字节,用来对齐内存。这个细节不注意,直接memcpy拷贝数据就会出问题。
避坑指南:我曾经因为直接按结构体大小去解析二进制PCD文件,结果数据全乱了。后来才意识到,PCL的PointXYZ实际占用16字节(4个float),而不是12字节。切记!
1.2.2 PointXYZRGB
这个类型在PointXYZ基础上,增加了RGB颜色信息。结构体定义:
struct PointXYZRGB {
float x;
float y;
float z;
uint32_t rgba; // 颜色信息打包成一个32位整数
};
这里有个小技巧:RGB三个通道各占8位,打包成一个32位整数。你想想看,如果每个通道用一个float存,那内存占用直接翻4倍。PCL这么设计,说白了就是为了省内存。
我在做三维重建项目时,经常用PointXYZRGB来保存带有纹理信息的点云。这样后续做可视化时,直接就能看到彩色效果,调试起来特别直观。
1.3 点云文件的读写
点云数据存成文件,最常用的格式就是PCD和PLY。咱们一个一个说。
1.3.1 PCD格式
PCD是PCL自家的格式,也是我用得最多的。它的文件结构分为两部分:头部和数据区。
头部包含:
- 版本号
- 字段名(如x y z rgb)
- 每个字段的大小
- 点云总点数
- 数据存储类型(ASCII或二进制)
一个典型的PCD文件头部长这样:
# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z rgb
SIZE 4 4 4 4
TYPE F F F F
COUNT 1 1 1 1
WIDTH 12345
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 12345
DATA ascii
读写PCD文件的代码也很简单:
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
// 读取PCD文件
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
pcl::io::loadPCDFile("input.pcd", *cloud);
// 写入PCD文件
pcl::io::savePCDFileASCII("output.pcd", *cloud);
个人经验:我建议你平时调试用ASCII格式,方便用文本编辑器查看。但正式处理大规模数据时,一定要用二进制格式。我测过,同样100万点的数据,二进制读写速度比ASCII快10倍以上。
1.3.2 PLY格式
PLY格式比PCD更通用,很多三维建模软件都支持。它的头部信息更丰富,可以定义顶点、面片、颜色等多种属性。
PLY文件的头部示例:
ply
format ascii 1.0
element vertex 12345
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
end_header
读写PLY文件的代码:
#include <pcl/io/ply_io.h>
// 读取PLY文件
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
pcl::io::loadPLYFile("input.ply", *cloud);
// 写入PLY文件
pcl::io::savePLYFileBinary("output.ply", *cloud);
注意:PLY格式的二进制存储方式有两种:little endian和big endian。不同系统之间传输文件时,一定要确认字节序。我曾经在ARM板子上读x86机器生成的PLY文件,颜色数据全反了,排查了半天才发现是字节序的问题。
1.4 知识体系总览
为了让你对整个章节有个直观认识,我画了一张结构图:
这张图把本章的核心内容串起来了。你仔细看看,PCL库是工具,数据结构是核心,文件读写是基本功。三者缺一不可。
1.5 本章小结
咱们这一章聊了三个重点:
- PCL库:点云处理的瑞士军刀,版本统一很重要
- 点云数据结构:PointXYZ和PointXYZRGB,内存对齐别忽略
- 文件读写:PCD和PLY格式,调试用ASCII,生产用二进制
说实话,这些内容看起来简单,但我在实际项目中见过太多人在这上面栽跟头。你把这些基础打牢了,后面学滤波算法的时候,会轻松很多。
我的建议:学完这一章,你最好动手写几行代码。随便找个PCD文件,读进来,打印一下点数,再写出去。这个过程走一遍,比看十遍文档都管用。
好了,第一章就到这里。记住,点云处理没有捷径,但基础扎实了,后面的路就好走了。