一、常见点云数据格式
-
LAS/LAZ格式
-
LAS是点云数据的行业标准格式
-
LAZ是LAS的压缩版本
-
支持地理参考信息、颜色、强度等属性
-
-
PCD格式(Point Cloud Data)
-
PCL(Point Cloud Library)开发的格式
-
支持ASCII和二进制存储
-
包含头部信息和数据部分
-
-
PLY格式(Polygon File Format)
-
最初为存储3D扫描仪数据设计
-
支持点云和网格数据
-
可包含颜色、法线等属性
-
-
OBJ格式
-
简单文本格式
-
主要用于3D模型但也可存储点云
-
二、读写工具和库
-
PDAL(Point Data Abstraction Library)
-
开源点云数据处理库
-
支持多种格式转换和处理
-
-
PCL(Point Cloud Library)
-
强大的点云处理库
-
提供多种点云格式的读写接口
-
-
LASlib/LASzip
-
专门用于LAS/LAZ格式的读写
-
-
CloudCompare
-
开源点云处理软件
-
支持多种格式的导入导出
-
三、PCL读写点云数据
PCL(Point Cloud Library)是处理点云数据的强大开源库,提供了多种点云数据格式的读写功能。以下是使用PCL进行点云数据读写的主要方法。
1. 基本点云数据结构
pcl::PointCloud 类
主要属性:
-
width
- 点云的宽度(对于无组织点云表示点数,对于有组织点云表示每行点数) -
height
- 点云的高度(对于无组织点云通常为1,对于有组织点云表示行数) -
points
- 存储所有点的向量 -
is_dense
- 布尔值,表示点云是否包含无限/NaN值 -
sensor_origin_
- 传感器原点坐标(Eigen::Vector4f) -
sensor_orientation_
- 传感器方向(Eigen::Quaternionf)
2. 常用点类型
点类型 | 描述 | 包含数据 |
---|---|---|
pcl::PointXYZ | 基本XYZ点 | float x, y, z |
pcl::PointXYZI | 带强度的XYZ点 | float x, y, z, intensity |
pcl::PointXYZRGB | 带RGB颜色的XYZ点 | float x, y, z; uint32_t rgb |
pcl::PointXYZRGBA | 带RGBA颜色的XYZ点 | float x, y, z; uint32_t rgba |
pcl::PointNormal | 带法线的XYZ点 | float x, y, z, normal_x, normal_y, normal_z, curvature |
3. 读写点云数据方法
读取点云文件
cpp
#include <pcl/io/pcd_io.h>// 读取PCD文件
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ>("input.pcd", *cloud) == -1) {PCL_ERROR("Couldn't read file input.pcd\n");return -1;
}// 读取PLY文件
#include <pcl/io/ply_io.h>
pcl::PLYReader reader;
reader.read("input.ply", *cloud);
写入点云文件
cpp
// 写入PCD文件(二进制格式)
pcl::io::savePCDFileBinary("output.pcd", *cloud);// 写入PCD文件(ASCII格式)
pcl::io::savePCDFileASCII("output_ascii.pcd", *cloud);// 写入PLY文件
pcl::PLYWriter writer;
writer.write("output.ply", *cloud, false); // false表示不保存二进制格式
4. 常用方法参数表
方法 | 参数 | 返回值 | 描述 |
---|---|---|---|
loadPCDFile | (const std::string &file_name, PointCloud &cloud) | int | 加载PCD文件 |
savePCDFile | (const std::string &file_name, const PointCloud &cloud, bool binary_mode=false) | int | 保存PCD文件 |
loadPLYFile | (const std::string &file_name, PointCloud &cloud) | int | 加载PLY文件 |
savePLYFile | (const std::string &file_name, const PointCloud &cloud, bool binary_mode=false) | int | 保存PLY文件 |
fromROSMsg | (const sensor_msgs::PointCloud2 &msg, PointCloud &cloud) | void | 从ROS消息转换 |
toROSMsg | (const PointCloud &cloud, sensor_msgs::PointCloud2 &msg) | void | 转换为ROS消息 |
其他格式支持
1. PLY格式读写
cpp
#include <pcl/io/ply_io.h>// 读取PLY文件
pcl::PLYReader reader;
reader.read("input.ply", *cloud);// 写入PLY文件
pcl::PLYWriter writer;
writer.write("output.ply", *cloud);
2. OBJ格式读写
cpp
#include <pcl/io/obj_io.h>// 读取OBJ文件
pcl::OBJReader reader;
reader.read("input.obj", *cloud);// 写入OBJ文件
pcl::OBJWriter writer;
writer.write("output.obj", *cloud);
二进制与ASCII格式
PCD文件可以保存为二进制或ASCII格式:
cpp
// 保存为二进制格式(更小更快)
pcl::io::savePCDFileBinary("output_binary.pcd", *cloud);// 保存为压缩二进制格式(更小)
pcl::io::savePCDFileBinaryCompressed("output_compressed.pcd", *cloud);// 保存为ASCII格式(可读)
pcl::io::savePCDFileASCII("output_ascii.pcd", *cloud);
5. 点云基本操作
添加点
cpp
pcl::PointXYZ point;
point.x = 1.0; point.y = 2.0; point.z = 3.0;
cloud->points.push_back(point);
访问点
cpp
// 随机访问
float x = cloud->points[10].x;// 遍历所有点
for (const auto& point : *cloud) {std::cout << "x: " << point.x << " y: " << point.y << " z: " << point.z << std::endl;
}
点云属性
cpp
std::cout << "点云大小: " << cloud->size() << std::endl;
std::cout << "宽度: " << cloud->width << std::endl;
std::cout << "高度: " << cloud->height << std::endl;
std::cout << "是否为有组织点云: " << cloud->isOrganized() << std::endl;
6. 常用信号(ROS相关)
在PCL与ROS结合使用时,常用的信号包括:
信号 | 参数 | 描述 |
---|---|---|
pcl::visualization::PointPickingEvent | const pcl::visualization::PointPickingEvent &event | 当用户选择点时触发 |
pcl::visualization::KeyboardEvent | const pcl::visualization::KeyboardEvent &event | 键盘事件 |
pcl::visualization::MouseEvent | const pcl::visualization::MouseEvent &event | 鼠标事件 |
7. 示例代码:完整读写流程
cpp
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>int main() {// 创建一个点云对象pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// 填充点云数据cloud->width = 5;cloud->height = 1;cloud->is_dense = false;cloud->points.resize(cloud->width * cloud->height);for (auto& point : *cloud) {point.x = 1024 * rand() / (RAND_MAX + 1.0f);point.y = 1024 * rand() / (RAND_MAX + 1.0f);point.z = 1024 * rand() / (RAND_MAX + 1.0f);}// 保存到文件pcl::io::savePCDFileASCII("test_pcd.pcd", *cloud);std::cout << "保存了 " << cloud->size() << " 个点到 test_pcd.pcd" << std::endl;// 从文件读取pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_from_file(new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile<pcl::PointXYZ>("test_pcd.pcd", *cloud_from_file);// 显示读取的点云for (const auto& point : *cloud_from_file)std::cout << " " << point.x << " " << point.y << " " << point.z << std::endl;return 0;
}
8. 注意事项
-
内存管理:使用智能指针(如
boost::shared_ptr
或pcl::PointCloud::Ptr
)管理点云对象 -
文件格式:PCD文件有ASCII和二进制格式,二进制格式更节省空间
-
点云类型:读写时要确保点云类型匹配
-
ROS集成:PCL与ROS紧密集成,可以方便地与
sensor_msgs::PointCloud2
相互转换