PCL 输出 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_asciisave_pcd_binarypcd_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 527 18:11 output_ascii.pcd
-rw-r--r-- 1 rudy rudy 16K 527 16:31 output_binary.pcd

现在,可以执行 pcd_viewer 程序将点云显示出来:

$ ./pcd_viewer output_ascii.pcd
# 或者
$ ./pcd_viewer output_binary.pcd

可以看到类似如下窗口:


Logo

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

更多推荐