第3章:点云数据基础:PCL库安装、点云数据结构、PCD/PLY文件格式解析与读写
点云数据,说白了就是三维空间里一堆点的集合。每个点带着XYZ坐标,有时候还带着颜色、法向量、强度这些附加信息。做3D视觉,点云就是我们的原材料。这一章,咱们就把点云的基础打牢。
3.1 PCL库的安装——别让环境配置卡住你
PCL(Point Cloud Library)是点云处理的事实标准。我入行那会儿,PCL还只有1.6版本,编译一次能折腾一整天。现在好多了,但该踩的坑一个不少。
Windows下的安装
我个人习惯用vcpkg来管理C++库,省心。
# 安装PCL核心库
vcpkg install pcl
# 如果需要可视化模块
vcpkg install pcl[visualization]
# 集成到CMake项目
cmake -B build -S . -DCMAKE_TOOLCHAIN_FILE=[vcpkg-root]/scripts/buildsystems/vcpkg.cmake
如果你不想折腾编译,直接去PCL官网下载All-in-One Installer也行。嗯,这里要注意:安装路径不要带中文和空格,否则链接时会报一些莫名其妙的错误。
Linux下的安装
Ubuntu下最简单,一条命令搞定:
sudo apt-get install libpcl-dev pcl-tools
但有个坑——apt源里的PCL版本通常比较老。我曾经在Ubuntu 18.04上装1.8.1版本,结果有个新算法接口找不到,最后只能从源码编译。如果你需要最新特性,建议源码编译:
git clone https://github.com/PointCloudLibrary/pcl.git
cd pcl && mkdir build && cd build
cmake -DCMAKE_BUILD_TYPE=Release ..
make -j$(nproc)
sudo make install
sudo apt-get install libvtk7-dev 再编译PCL。
3.2 点云数据结构——理解PCL的核心
PCL里最基础的数据结构是 pcl::PointCloud<T>。T是点类型,决定了每个点携带什么信息。
常用点类型
| 点类型 | 包含字段 | 典型应用场景 |
|---|---|---|
| pcl::PointXYZ | x, y, z | 纯几何位置,最常用 |
| pcl::PointXYZRGB | x, y, z, r, g, b | 带颜色的点云,RGB-D相机输出 |
| pcl::PointXYZRGBA | x, y, z, r, g, b, a | 带透明通道的颜色点云 |
| pcl::PointNormal | x, y, z, normal_x, normal_y, normal_z | 带法向量的点云,用于曲面重建 |
| pcl::PointXYZRGBANormal | 以上所有字段 | 全功能点,内存占用大 |
你想想看,一个点云文件动辄几百万个点,选对点类型能省不少内存。我在做仓储机器人项目时,一开始用了PointXYZRGB,后来发现颜色信息根本用不上,改成PointXYZ后内存占用直接降了三分之一。
点云的内存布局
PCL的点云数据是连续存储的,这一点很重要。底层其实就是一个vector,每个元素是一个点结构体。所以访问第i个点就是O(1)的复杂度。
pcl::PointCloud<pcl::PointXYZ> cloud;
cloud.width = 640; // 如果是有序点云,width是每行点数
cloud.height = 480; // height是行数,有序点云height > 1
cloud.is_dense = false; // 是否包含无效点(NaN)
// 访问点
float x = cloud.points[100].x;
float y = cloud.points[100].y;
float z = cloud.points[100].z;
// 遍历所有点
for (const auto& point : cloud.points) {
// 处理每个点
}
3.3 PCD文件格式解析——PCL的亲儿子
PCD(Point Cloud Data)是PCL的原生格式。说白了,就是PCL团队自己定义的,读写效率最高。
文件结构
一个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 640
HEIGHT 480
VIEWPOINT 0 0 0 1 0 0 0
POINTS 307200
DATA ascii
0.123 0.456 0.789 4294967295
0.234 0.567 0.890 4278190335
...
头部字段说明:
- VERSION:PCD版本,目前主流是0.7
- FIELDS:每个点的字段名,空格分隔
- SIZE:每个字段占用的字节数
- TYPE:数据类型,F=float, I=int, U=unsigned int
- COUNT:每个字段的元素个数,比如rgb是1个uint32
- WIDTH/HEIGHT:点云尺寸,无序点云HEIGHT=1
- VIEWPOINT:采集时的传感器位姿,用于坐标变换
- POINTS:总点数
- DATA:数据存储方式,ascii或binary
pcl::PCDReader 和 pcl::PCDWriter 会自动识别格式。
读写PCD文件
#include <pcl/io/pcd_io.h>
// 读取PCD文件
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("scene.pcd", *cloud) == -1) {
PCL_ERROR("读取PCD文件失败\n");
return -1;
}
// 写入PCD文件
pcl::io::savePCDFileASCII("output.pcd", *cloud); // ASCII格式
pcl::io::savePCDFileBinary("output.pcd", *cloud); // 二进制格式
3.4 PLY文件格式解析——通用性更强的选择
PLY(Polygon File Format)是斯坦福大学开发的格式,比PCD更通用。很多3D扫描仪和建模软件都支持PLY。说白了,如果你要和别的软件交换数据,PLY是更好的选择。
文件结构
PLY文件分ASCII和二进制两种,头部结构类似:
ply
format ascii 1.0
comment Created by PCL
element vertex 307200
property float x
property float y
property float z
property uchar red
property uchar green
property uchar blue
element face 0
property list uchar int vertex_indices
end_header
0.123 0.456 0.789 255 0 0
0.234 0.567 0.890 0 255 0
...
PLY支持两种元素:vertex(顶点)和 face(面片)。如果你只存点云,face可以设为0。如果要存三角网格,就需要定义face元素。
读写PLY文件
#include <pcl/io/ply_io.h>
// 读取PLY文件
pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
if (pcl::io::loadPLYFile<pcl::PointXYZRGB>("model.ply", *cloud) == -1) {
PCL_ERROR("读取PLY文件失败\n");
return -1;
}
// 写入PLY文件
pcl::io::savePLYFileASCII("output.ply", *cloud);
pcl::io::savePLYFileBinary("output.ply", *cloud);
3.5 格式对比与选型建议
| 特性 | PCD | PLY |
|---|---|---|
| 读写速度 | 快(原生支持) | 中等 |
| 文件大小 | 较小(binary) | 中等 |
| 通用性 | PCL专用 | 广泛支持 |
| 支持网格 | 不支持 | 支持 |
| 元数据 | 支持VIEWPOINT等 | 支持comment |
我个人习惯:内部处理用PCD,对外输出用PLY。你想想看,PCL读写PCD是零拷贝的,性能最好。但如果你要把点云发给客户或者导入Blender、MeshLab,PLY更友好。
3.6 本章知识体系
下面这张图帮你理清本章的核心逻辑:
嗯,这一章的内容就这些。PCL安装、点云数据结构、PCD和PLY格式的读写,都是后面所有章节的基础。你把这些搞定了,后面做滤波、配准、分割就顺手多了。
公众号:蓝海资料掘金营,微信deep3321