【C++】 pcl库的输入输出(IO)

PCD文件格式

在这里插入图片描述
这是用gedit打开的.pcd文件的文件头

  • VERSION:指定PCD文件版本
  • FIELDS:指定一个点可以有的每一个维度和字段的名字
  • SIZE:用字节数指定每一个维度的大小

unsigned char/char 1 byte
unsigned short/short 2 bytes
unsigned int/int/float 4 bytes
double 8 bytes

  • TYPE:用一个字符指定一个维度的类型

I:int8(char)、int16(short)、int32(int)
U:uint8(unsigned char)、uint16(unsigned short)、uint32(unsigned int)
F:浮点类型

  • COUNT:指定每一个维度包含的元素数目。
  • WIDTH:如果是有序点云,用点的数量表示点云数据集的宽度(一行中点的数目)。如果是无序点云,表示点云中点的个数(等于POINTS)
  • HEIGHT:如果是有序点云,用点的数量表示点云数据集的高度(行的总数)。如果是无序点云,被设置为1
  • VIEWPOINT:指定数据集中点云的获取视点。VIEWPOINT有可能在不同坐标系之间转换的时候应用。视点信息被指定为平移(txtytz)+四元数(qwqxqyqz),默认值为VIEPOINT 0 0 0 1 0 0 0
  • POINTS:指定点云中点的总数
  • DATA:指定储存点云数据的数据类型。从0.7版本开始,支持两种数据类型:ASCII和二进制。

PCD文件IO操作

pcl::PCLPointCloud2与pcl::PointCloud的区别

PCLPointCloud2 v.s. PointCloud

PCL has replaced the “sensor_msgs::PointCloud2” type to “pcl::PCLPointCloud2”.
PointCLoud2 is a ROS message type.
=> So you had to use the PCLPointCloud2 type in PCL when you want to have interactions with ROS.

从.pcd里读取

#include <iostream>
#include <pcl/io/pcd_io.h> // PCD读写类相关的头文件
#include <pcl/point_types.h> // PCL中支持的点类型头文件

int main(int argc, char** argv)
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); // 创建一个PointCloud<PointXYZ> boost共享指针,并进行实例化为cloud
    if(pcl::io::loadPCDFile<pcl::PointXYZ>("test_pcd.pcd", *cloud) == -1)// 调用函数loadPCDFile,如果返回-1,则是打开点云文件失败
    {
        PCL_ERROR("Couldn't read file test_pcd.pcd\n");
        return(-1);
    }
    std::cout << "Loaded " << cloud -> width * cloud -> height << " data points from test_pcd.pcd with the following fields: " << std::endl;
    for(size_t i=0; i<cloud->points.size(); ++i)
    {
        std::cout << "    " << cloud->points[i].x << " " << cloud->points[i].y << " " << cloud->points[i].z << std::endl;
    }
    return(0);
}

其中函数loadPCDFile定义在pcl/io/pcd_io.h中,内容如下:

/** \brief Load any PCD file into a templated PointCloud type
  * \param[in] file_name the name of the file to load
  * \param[out] cloud the resultant templated point cloud
  * \ingroup io
  */
template<typename PointT> inline int
loadPCDFile (const std::string &file_name, pcl::PointCloud<PointT> &cloud)
{
  pcl::PCDReader p;
  return (p.read (file_name, cloud));
}

用cmake编译:
CMakeLists.txt中内容如下:

cmake_minimum_required(VERSION 2.8 FATAL_ERROR)
// 指定cmake的最小版本

set(CMAKE_CXX_STANDARD 11)
set(CMAKE_CXX_STANDARD_REQUIRED TRUE)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS}-std=c++11")
// Enable C++11

project(pcd_read)
// 指定项目名

find_package(PCL 1.2 REQUIRED)
// 找到PCL包

include_directories(${PCL_INCLUDE_DIRS})
// 用于设定目录,这些设定的目录将被编译器用来查找 include 文件
link_directories(${PCL_LIBRARY_DIRS})
// 动态链接库或静态链接库的搜索路径
add_definitions(${PCL_DEFINITIONS})
// 用于添加编译器命令行标志(选项),通常的情况下我们使用其来添加预处理器定义

add_executable(pcd_read pcd_read.cpp)
// 将指定文件source编译成可执行文件,相当于g++的-o pcd_read pcd_read.cpp

target_link_libraries(pcd_read ${PCL_LIBRARIES})
// 用于指定 target 需要链接 item1 item2 …。这里 target 必须已经被创建,链接的 item 可以是已经存在的 target(依赖关系会自动添加)

运行结果:
在这里插入图片描述

向.pcd里写入

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

int main(int argc,char**argv)
{
    pcl::PointCloud<pcl::PointXYZ> cloud; // 创建点云
    cloud.width=5; // 设置点云width
    cloud.height=1; // 设置点云height
    cloud.is_dense=false; // 设置是否是密集点云
    cloud.points.resize(cloud.width * cloud.height);
    for(size_t i=0; i<cloud.points.size(); ++i)
    {
        cloud.points[i].x = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud.points[i].y = 1024 * rand() / (RAND_MAX + 1.0f);
        cloud.points[i].z = 1024 * rand() / (RAND_MAX + 1.0f);
        // rand()是随机产生一个从0到无限大的任意整数
        // RAND_MAX是宏定义的一个字符常量
        // 1.0f,f代表数字类型是浮点型
    }
    pcl::io::savePCDFileASCII("test_pcd.pcd", cloud); // 按ASCII码写入test_pcd.pcd
    std::cout << "Saved " << cloud.points.size() << " data points to test_pcd.pcd." << std::endl;
    for(size_t i=0; i<cloud.points.size(); ++i)
    {
        std::cout << "    " << cloud.points[i].x << " " << cloud.points[i].y << " " << cloud.points[i].z << std::endl;
    }
    return(0);
}

运行结果:
在这里插入图片描述

两个点云中的数据或字段连接

连接两个.pcd文件成一个.pcd文件:进行连接操作前要确保两个数据集中的类型相同维度相同
连接两个不同点云的字段:两个数据集中点的数目必需一样(例如:点云A是N点的xyz点,点云B是N点的rgb点,则连接两个字段形成的点云C是N点的xyzrgb)。
NormalPointNormal在point_types.h中的定义如下:

/** \brief Members: float normal[3], curvature
  * \ingroup common
  */
struct Normal;

/** \brief Members: float x, y, z; float normal[3], curvature
  * \ingroup common
  */
struct PointNormal;

可知,Normal是一个三维浮点型数组,这一个数组代表一个点的法线方向

#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>

int main(int argc, char** argv)
{
    if(argc!=2) // 如果参数数量(包括可执行文件名称)不是2
    {
        std::cerr << "please specify command line arg '-f' or '-p'" << std::endl; // std::cerr专门用作输出错误信息
        exit(0);
    }

    pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c; // 新建三个点云cloud_a、cloud_b、cloud_c
    pcl::PointCloud<pcl::Normal> n_cloud_b;
    pcl::PointCloud<pcl::PointNormal> p_n_cloud_c;
    
    cloud_a.width = 5; // cloud_a的宽度是5
    cloud_a.height = cloud_b.height = n_cloud_b.height = 1; // a、b、c都是无序点云
    cloud_a.points.resize(cloud_a.width * cloud_a.height);
    
    // 如果参数是-p,则连接数据,需要相同的数据类型和维度,cloud_b也是PointXYZ
    if(strcmp(argv[1], "-p")==0) // strcmp:如果两个字符串相等,返回0
    {
        cloud_b.width=3; // 都是width和height,width不需要一定相等
        cloud_b.points.resize(cloud_b.width * cloud_b.height);
    }
    // 如果参数是-f,则连接字段,需要相同的数据数目,cloud_b是Normal
    else
    {
        n_cloud_b.width=5; // 此时width必需相等
        n_cloud_b.points.resize(n_cloud_b.width * n_cloud_b.height);
    }
    
    for(size_t i=0; i<cloud_a.points.size(); ++i) // cloud_a随机初始化
    {
        cloud_a.points[i].x=1024 * rand()/(RAND_MAX+1.0f);
        cloud_a.points[i].y=1024 * rand()/(RAND_MAX+1.0f);
        cloud_a.points[i].z=1024 * rand()/(RAND_MAX+1.0f);
    }
    
    if(strcmp(argv[1],"-p")==0) // cloud_b随机初始化
    {
        for(size_t i=0; i<cloud_b.points.size(); ++i)
        {
            cloud_b.points[i].x=1024 * rand()/(RAND_MAX+1.0f);
            cloud_b.points[i].y=1024 * rand()/(RAND_MAX+1.0f);
            cloud_b.points[i].z=1024 * rand()/(RAND_MAX+1.0f);
        }
    }
    else
    {
        for(size_t i=0; i<n_cloud_b.points.size(); ++i)
        {
            n_cloud_b.points[i].normal[0]=1024 * rand()/(RAND_MAX+1.0f);
            n_cloud_b.points[i].normal[1]=1024 * rand()/(RAND_MAX+1.0f);
            n_cloud_b.points[i].normal[2]=1024 * rand()/(RAND_MAX+1.0f);
        }
    }
    
    std::cout << "Cloud A: " << std::endl;
    for(size_t i=0; i<cloud_a.points.size(); ++i)
    {
        std::cout << "    " << cloud_a.points[i].x << " " << cloud_a.points[i].y << " "<<cloud_a.points[i].z << std::endl;
    }

    std::cout << "Cloud B: " << std::endl;
    if(strcmp(argv[1],"-p")==0)
    {
        for(size_t i=0; i<cloud_b.points.size(); ++i)
        {
            std::cout<<"    "<<cloud_b.points[i].x<<" "<<cloud_b.points[i].y<<" "<<cloud_b.points[i].z<<std::endl;
        }
    }
    else
    {
        for(size_t i=0; i<n_cloud_b.points.size(); ++i)
        {
            std::cout<<"    "<<n_cloud_b.points[i].normal[0]<<" "<<n_cloud_b.points[i].normal[1]<<" "<<n_cloud_b.points[i].normal[2]<<std::endl;
        }
    }

    // 如果是连接数据
    if(strcmp(argv[1],"-p")==0)
    {
        cloud_c=cloud_a;
        cloud_c+=cloud_b;
        // 就直接相加就好了
        std::cout << "Cloud C: " << std::endl;
        for(size_t i=0; i<cloud_c.points.size(); ++i)
            std::cout<<"    "<<cloud_c.points[i].x<<" "<<cloud_c.points[i].y<<" "<<cloud_c.points[i].z<<" "<<std::endl;
    }
    // 如果是连接字段
    else
    {
        pcl::concatenateFields(cloud_a, n_cloud_b, p_n_cloud_c); // 调用函数concatenateFields
        std::cout << "Cloud C: " << std::endl;
        for(size_t i=0; i<p_n_cloud_c.points.size(); ++i)
            std::cout<<"    "<< p_n_cloud_c.points[i].x<<" "<<p_n_cloud_c.points[i].y<<" "<<p_n_cloud_c.points[i].z<<" "<<p_n_cloud_c.points[i].normal[0]<<" "<<p_n_cloud_c.points[i].normal[1]<<" "<<p_n_cloud_c.points[i].normal[2]<<std::endl;
    }
    return(0);
}

-p执行结果如下:
在这里插入图片描述-f执行结果如下:
在这里插入图片描述

结语

如果您有修改意见或问题,欢迎留言或者通过邮箱和我联系。
手打很辛苦,如果我的文章对您有帮助,转载请注明出处。

发布了57 篇原创文章 · 获赞 19 · 访问量 2万+

猜你喜欢

转载自blog.csdn.net/Zhang_Chen_/article/details/100919371