基于Win系统下PCL库入门到实践:IO模块之PCD文件的读写(附详细代码)

I/O(Input/Output) 是计算机系统里最基础的功能模块,负责数据的输入与输出。在 PCL 里,I/O 模块主要用于:点云数据的读写 (如 PCD、PLY、OBJ、PNG 等格式)、与其他系统交互 (ROS、OpenNI、RealSense、Velodyne 激光雷达等)、点云与图像的互相转换(如点云转 PNG,RGB-D 图像转点云)。

所有点云处理流程(滤波、分割、配准、重建等)都要从数据读取开始。IO 模块提供了统一的接口 ,**I/O 模块是点云处理的"桥梁",**没有 IO,就没有数据输入与结果输出,整个点云处理流程就无法闭环。

PCD文件读取

PCD文件的读取有两种,第一种是最基础的:实例化读取变量,调用read方法:

复制代码
pcl::PCDReader reader;
reader.read("C:\\Users\\admin\\Desktop\\code\\pcl_type.pcd", Cloud);

PCD文件的读取第二种:

复制代码
pcl::io::loadPCDFile("C:\\Users\\admin\\Desktop\\code\\pcl_type.pcd", Cloud);

直接调用loadPCDFile就可以读取了,再进这个函数的定义去看,其实就是用最基础的读取方式写的:

下面是读取并可视化的代码。

复制代码
#include <thread>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization//cloud_viewer.h>

using namespace std;

int main()
{
    pcl::PCLPointCloud2 Cloud;
    pcl::PCDReader reader;
    reader.read("C:\\Users\\admin\\Desktop\\code\\pcl_type.pcd", Cloud);
    //pcl::io::loadPCDFile("C:\\Users\\admin\\Desktop\\code\\pcl_type.pcd", Cloud);
    for(auto &f : Cloud.fields)cout <<f.name<<endl;

    PointCloud<PointXYZRGB >::Ptr Cloud2(new PointCloud<PointXYZRGB>);
    pcl::fromPCLPointCloud2(Cloud,*Cloud2);
    pcl::visualization::CloudViewer viewer("Viewer"); // 创建 CloudViewer
    viewer.showCloud(Cloud2);

    while (!viewer.wasStopped())// 保持显示
    std::this_thread::sleep_for(std::chrono::milliseconds(100));
    return 0;
}

这里定义为PCLPointCloud2的点的原因:

这里是不知道要读取得点云到底是什么格式得,PCLPointCloud2通用性强。无论是 PointXYZ、PointXYZRGB、PointXYZRGBA 还是自定义点,都能先读进来。后续在使用fromPCLPointCloud2函数去转换点的类型。

怎么知道该转换什么类型的点云数据:

复制代码
for(auto &f : Cloud.fields)cout <<f.name<<endl;

这一步就是在输出口打印其格式,fields 就是点云 每个点包含哪些字段 的列表

而 pcl::PCLPointField 结构大致是这样的:

复制代码
struct PCLPointField {
    std::string name;   // 字段名,比如 x,y,z,rgb,intensity等
    uint32_t offset;    // 在每个点的字节数据中的偏移量
    uint8_t datatype;   // 数据类型(FLOAT32, UINT32, UINT8 等)
    uint32_t count;     // 该字段包含多少个数(比如 x,y,z 都是 1;如果是 normal[3] 就是 3)
};

那么这样就直接可以打印出对应PCD文件的点云类型。后续直接定义相应类型的点。如结果图,打印字段为xyzrgb,定义PointXYZRGB就可以不丢失信息了。

复制代码
 PointCloud<PointXYZRGB >::Ptr Cloud2(new PointCloud<PointXYZRGB>);
 pcl::fromPCLPointCloud2(Cloud,*Cloud2);

这里就是定义指针类的点云,并用fromPCLPointCloud2将其转换给Cloud2,由于Cloud2定义为指针类型,而这个函数只接受值变量,所以直接给*Cloud2,同时也方便后面的可视化。

PCD文件保存

同样的保存也是两种方法:第一种就是

复制代码
pcl::PCDWriter writer;
writer.writeASCII("C:\\Users\\Desktop\\code\\pcl_ASCII.pcd",*Cloud2);

这里的write方法有多个,其实就是保存格式,上述的为ASCII格式,也可以是二进制格式,或者压缩二进制,如下所示:

复制代码
writer.write("C:\\Users\\Desktop\\code\\pcl_ASCII.pcd",*Cloud2);
writer.writeASCII("C:\\Users\\Desktop\\code\\pcl_ASCII.pcd",*Cloud2);
writer.writeBinary("C:\\Users\\Desktop\\code\\pcl_Binary.pcd",*Cloud2);
writer.writeBinaryCompressed("C:\\Users\\Desktop\\code\\pcl_Binary_zip.pcd",*Cloud2);

在上述的例程的基础上,显示结束后可以加上保存;发现保存成功了。在上述的例程的基础上,显示结束后可以加上保存;发现保存成功了。

第二种同样类似于读取,也是第一种封装的。

第二种的保存方式仍然是有多种格式的保存,如下:

复制代码
pcl::io::savePCDFile("C:\\Users\\Desktop\\code\\pcl.pcd",*Cloud2);
pcl::io::savePCDFileASCII("C:\\Users\\Desktop\\code\\pcl_Binary.pcd",*Cloud2);
pcl::io::savePCDFileBinary("C:\\Users\\Desktop\\code\\pcl_Binary.pcd",*Cloud2);
pcl::io::savePCDFileBinaryCompressed("C:\\Users\\Desktop\\code\\pcl_Binary_zip.pcd.pcd",*Cloud2);

完整代码:

复制代码
#include <thread>
#include <pcl/point_cloud.h>
#include <pcl/io/pcd_io.h>
#include <pcl/visualization//cloud_viewer.h>

using namespace std;

int main()
{

    pcl::PCLPointCloud2 Cloud;//这里是不知道要读取得点云到底是什么格式得,所以使用PCLPointCloud2可以读取更多得格式
#if 0
    pcl::PCDReader reader;
    reader.read("C:\\Users\\admin\\Desktop\\code\\pcl_type.pcd", Cloud);
#else
    pcl::io::loadPCDFile("C:\\Users\\admin\\Desktop\\code\\pcl_type.pcd", Cloud);
#endif
    for(auto &f : Cloud.fields)cout <<f.name<<endl;//这一步就是在输出口打印其格式

    pcl::PointCloud<pcl::PointXYZRGB >::Ptr Cloud2(new  pcl::PointCloud<pcl::PointXYZRGB>);
    pcl::fromPCLPointCloud2(Cloud,*Cloud2);

    // 创建 CloudViewer
    pcl::visualization::CloudViewer viewer("Viewer");
    viewer.showCloud(Cloud2);

    // 保持显示
    while (!viewer.wasStopped())std::this_thread::sleep_for(std::chrono::milliseconds(100));
#if 0
    pcl::PCDWriter writer;
    writer.writeASCII("C:\\Users\\admin\\Desktop\\code\\pcl_ASCII.pcd",*Cloud2);
    writer.writeBinary("C:\\Users\\admin\\Desktop\\code\\pcl_Binary.pcd",*Cloud2);
    writer.writeBinaryCompressed("C:\\Users\\admin\\Desktop\\code\\pcl_Binary_zip.pcd",*Cloud2);
#else
    pcl::io::savePCDFileBinaryCompressed("C:\\Users\\admin\\Desktop\\code\\pcl_Binary_zip.pcd.pcd",*Cloud2);
    pcl::io::savePCDFileBinary("C:\\Users\\admin\\Desktop\\code\\pcl_Binary.pcd",*Cloud2);
    pcl::io::savePCDFile("C:\\Users\\admin\\Desktop\\code\\pcl.pcd",*Cloud2);
    pcl::io::savePCDFileASCII("C:\\Users\\admin\\Desktop\\code\\pcl.pcd",*Cloud2);
#endif


    return 0;
}
相关推荐
爱和冰阔落4 小时前
【C++STL详解】带头双向循环结构 + 双向迭代器,核心接口 + 排序效率 + 避坑指南
开发语言·c++·经验分享
今天也好累4 小时前
贪心算法之分数背包问题
c++·笔记·学习·算法·贪心算法
carver w4 小时前
c++,数据结构,unordermap哈希表基本操作
数据结构·c++·散列表
Incredibuild4 小时前
CI/CD Pipeline:完整指南
c++·ci/cd·devsecops
深思慎考4 小时前
LinuxC++项目开发日志——基于正倒排索引的boost搜索引擎(4——通过jsoncpp库建立搜索模块)
linux·c++·搜索引擎
青草地溪水旁5 小时前
设计模式(C++)详解——职责链模式 (Chain of Responsibility)(2)
c++·设计模式·责任链模式
青草地溪水旁5 小时前
设计模式(C++)详解——职责链模式 (Chain of Responsibility)(1)
c++·设计模式·责任链模式
不沾一点因果5 小时前
基于C++的分布式RPC框架(一)
c++
usabcd26 小时前
如何重新编译HyperLPR原生库以消除16k对齐警告
android·c++·cmake·ndk·mnn·16k对齐·hyperlpr