使用 PCL 库将点云数据保存为 PCD 格式文件
PCD 全称 Point Cloud Data,是一种存储三维点云数据的文件格式,本教程将介绍如何使用 PCL 点云库将点云数据写入 PCD 文件。由于 PCD 是一种开放数据格式,因此你可以使用各种点云处理工具来读取和写入 PCD 文件,并进一步对点云数据进行处理。本教程的示例代码和点云数据可在下载。
PCD 全称 Point Cloud Data,是一种存储三维点云数据的文件格式,本教程将介绍如何使用 PCL 点云库将点云数据写入 PCD 文件。由于 PCD 是一种开放数据格式,因此你可以使用各种点云处理工具来读取和写入 PCD 文件,并进一步对点云数据进行处理。
本教程的示例代码和点云数据可在 GitHub 下载。
PCD 格式
PCD 格式是由 PCL 点云库使用的文件格式,用于存储三维点云数据。PCD 文件格式有两种主要的存储方式:ASCII(文本)格式和二进制格式。其中,ASCII 格式易于阅读和编辑,但文件较大;而二进制格式通常更紧凑,适用于大型点云数据。
PCD 文件由一个头部(header)和数据体(data body)组成。头部包含元数据和格式信息,数据体包含实际的点云数据。
头部信息
头部(Header)信息一般包括以下字段:
序号 | 字段名称 | 字段描述 |
---|---|---|
1 | VERSION |
文件格式的版本信息。 |
2 | FIELDS |
点云数据的字段名称,例如 x, y, z, intensity。 |
3 | SIZE |
每个字段的大小(以字节为单位)。 |
4 | TYPE |
每个字段的数据类型,例如 F(浮点型)、U(无符号整型)。 |
5 | COUNT |
每个字段的元素个数,通常是 1。 |
6 | WIDTH |
点云数据的宽度,如果是 1 则表示无序点云。 |
7 | HEIGHT |
点云数据的高度,如果是 1 则表示无序点云。 |
8 | VIEWPOINT |
相机视点信息(通常用于三维重建)。 |
9 | POINTS |
点云中的点的总数。 |
10 | DATA |
数据存储的格式,可能是 ascii、binary、binary_compressed。 |
下面是一个典型的 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 1000
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 1000
DATA ascii
数据体
数据体(Data Body)包含实际的点云数据,根据头部的描述以 ASCII 或二进制格式存储。
在 ASCII 格式下,点云数据以文本形式存储,每个点的数据在一行中按字段顺序排列,字段之间以空格分隔。例如,下面数据中的每一行对应一个三维点坐标(XYZ)和强度(Intensity)信息。
4.1249428 7.1494288 5.167275 6.0977383
3.532496 2.1198421 8.2864342 0.50844169
0.10034604 9.304101 9.876545 68.85511
6.0308199 1.1348503 9.8444204 63.933022
...
而在二进制格式下,数据按字段顺序紧凑地存储在文件中,没有任何分隔符,所有数据以二进制形式直接写入文件。这种格式更节省存储空间和读取时间。
示例程序
PCL 的 io 模块提供了读取和写入 PCD 文件的功能,下面我们通过三个简单的示例,演示如何将点云数据输出为 ASCII 格式和二进制格式的 PCD 文件,以及如何读取 PCD 文件并将其可视化出来。
以 ASCII 格式输出 PCD 文件
下面示例程序演示如何使用 PCL 库将随机生成的一组点云数据保存为一个文本格式的 PCD 文件。
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
int main()
{
// 创建点云对象
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>);
// 随机生成点云数据
srand(static_cast<unsigned int>(time(NULL)));
for (int i = 0; i < 1000; ++i)
{
pcl::PointXYZI point;
point.x = 10.0f * rand() / RAND_MAX; // 在 x 方向上随机生成坐标
point.y = 10.0f * rand() / RAND_MAX; // 在 y 方向上随机生成坐标
point.z = 10.0f * rand() / RAND_MAX; // 在 z 方向上随机生成坐标
point.intensity = 255.0f * rand() / RAND_MAX; // 生成随机强度值
cloud->push_back(point);
}
// 保存点云数据到 PCD 文件
pcl::io::savePCDFileASCII("output_ascii.pcd", *cloud);
std::cout << "Saved " << cloud->points.size() << " data points to output_ascii.pcd in ASCII format." << std::endl;
return 0;
}
这个程序将生成一个包含 1000 个随机点的点云数据,并将其保存为名为 output_ascii.pcd
的 PCD 文件。
代码重点:
- 使用
pcl::PointCloud<pcl::PointXYZI>::Ptr
创建一个指向点云对象的智能指针。 - 使用
rand()
函数生成随机点,并填充到点云对象中。 - 使用
pcl::io::savePCDFileASCII
函数将点云数据保存到 PCD 文件中。
以二进制格式输出 PCD 文件
下面示例程序演示如何使用 PCL 库将随机生成的一组点云数据保存为一个二进制格式的 PCD 文件。
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
int main()
{
// 创建点云对象
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>);
// 随机生成点云数据
srand(static_cast<unsigned int>(time(NULL)));
for (int i = 0; i < 1000; ++i)
{
pcl::PointXYZI point;
point.x = 10.0f * rand() / RAND_MAX; // 在 x 方向上随机生成坐标
point.y = 10.0f * rand() / RAND_MAX; // 在 y 方向上随机生成坐标
point.z = 10.0f * rand() / RAND_MAX; // 在 z 方向上随机生成坐标
point.intensity = 255.0f * rand() / RAND_MAX; // 生成随机强度值
cloud->push_back(point);
}
// 保存点云数据到二进制 PCD 文件
pcl::io::savePCDFileBinary("output_binary.pcd", *cloud);
std::cout << "Saved " << cloud->points.size() << " data points to output_binary.pcd in binary format." << std::endl;
return 0;
}
这个程序将生成一个包含 1000 个随机点的点云数据,并将其保存为名为 output_binary.pcd
的 PCD 文件。
代码和前面的示例类似,不同的是这里使用 pcl::io::savePCDFileBinary
函数将点云数据保存到 PCD 文件中。
读取 PCD 文件并可视化
下面示例程序从命令行参数读取一个 PCD 文件(可以是 ASCII 格式或二进制格式),并使用 PCL 的可视化工具将其显示出来。
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
int main(int argc, char** argv)
{
// 检查命令行参数
if (argc != 2)
{
std::cerr << "Usage: " << argv[0] << " <path-to-pcd-file>" << std::endl;
return -1;
}
// 创建点云对象
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>);
// 从文件中读取点云数据
if (pcl::io::loadPCDFile<pcl::PointXYZI>(argv[1], *cloud) == -1)
{
PCL_ERROR("Couldn't read file %s \n", argv[1]);
return -1;
}
std::cout << "Loaded " << cloud->width * cloud->height << " data points from " << argv[1] << std::endl;
// 创建可视化窗口对象
pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("PCD Viewer"));
// 创建颜色处理对象
pcl::visualization::PointCloudColorHandlerGenericField<pcl::PointXYZI> fildColor(cloud, "intensity");
// 将点云添加到可视化窗口中
viewer->addPointCloud<pcl::PointXYZI>(cloud, fildColor, "sample cloud");
// 设置点云大小
viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "sample cloud");
// 显示可视化窗口,直到用户关闭窗口为止
while (!viewer->wasStopped())
{
viewer->spinOnce(100); // 每隔100毫秒渲染一次
}
return 0;
}
编译运行
为了编译这三个示例程序,你可以使用以下 CMakeLists.txt
文件:
cmake_minimum_required(VERSION 3.0)
project(pcd_example)
find_package(PCL REQUIRED)
find_package(VTK REQUIRED)
include_directories(${PCL_INCLUDE_DIRS})
add_executable(save_pcd_ascii save_pcd_ascii.cpp)
add_executable(save_pcd_binary save_pcd_binary.cpp)
add_executable(pcd_viewer pcd_viewer.cpp)
target_link_libraries(save_pcd_ascii ${PCL_LIBRARIES})
target_link_libraries(save_pcd_binary ${PCL_LIBRARIES})
target_link_libraries(pcd_viewer ${PCL_LIBRARIES} ${VTK_LIBRARIES})
依次执行以下命令编译程序:
mkdir build
cd build
cmake ..
make
在 build 目录下可以看到生成了三个可执行文件:save_pcd_ascii
、save_pcd_binary
和 pcd_viewer
。
- 执行
./save_pcd_ascii
,将生成一个output_ascii.pcd
文件; - 执行
./save_pcd_binary
,将生成一个output_binary.pcd
文件。
对比两个文件的大小,可以发现:同样存储 1000 个点的数据,二进制格式比 ASCII 格式小得多。
$ ls -lh output_*
-rw-rw-r-- 1 rudy rudy 40K 5月 27 18:11 output_ascii.pcd
-rw-r--r-- 1 rudy rudy 16K 5月 27 16:31 output_binary.pcd
现在,可以执行 pcd_viewer
程序将点云显示出来:
$ ./pcd_viewer output_ascii.pcd
# 或者
$ ./pcd_viewer output_binary.pcd
可以看到类似如下窗口:

DAMO开发者矩阵,由阿里巴巴达摩院和中国互联网协会联合发起,致力于探讨最前沿的技术趋势与应用成果,搭建高质量的交流与分享平台,推动技术创新与产业应用链接,围绕“人工智能与新型计算”构建开放共享的开发者生态。
更多推荐
所有评论(0)