PCL点云库学习笔记(输入输出)

输入输出(I\O)

一、概述

IO库包含用于读写点云数据(PCD)文件的类和函数,以及从各种传感设备捕获点云。

二、PCD 点云格式

1.为什么用一种新的文件格式?
PCD文件格式的出现,是因为现有的文件结构不支持由PCL库引进n维点类型机制处理过程中的某些扩展。PCD不是第一个支持3D点云数据的文件类型,尤其是计算机图形学和计算几何学领域,已经创建了很多格式来描述任意多边形和激光扫描仪获取的点云。
2.文件头
每个PCD文件都包含一个头,用于标识和声明文件中存储的点云数据的某些属性。PCD的头必须用ASCII编码。

·VERSION –指定PCD文件版本
·FIELDS –指定一个点可以有的每一个维度和字段的名字。

FIELDS x y z                                # XYZ data
FIELDS x y z rgb                            # XYZ + colors
FIELDS x y z normal_x normal_y normal_z     # XYZ + surface normals
FIELDS j1 j2 j3                             # moment invariants

·SIZE –用字节数指定每一个维度的大小。

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

·TYPE –用一个字符指定每一个维度的类型。

I –表示有符号类型int8(char)、int16(short)和int32(int);
U – 表示无符号类型uint8(unsigned char)、uint16(unsigned short)和uint32(unsigned int);
F –表示浮点类型。

·COUNT –指定每一个维度包含的元素数目。

例如,x这个数据通常有一个元素,但是像VFH这样的特征描述子就有308个。实际上这是在给每一点引入n维直方图描述符的方法,把它们当做单个的连续存储块。默认情况下,如果没有COUNT,所有维度的数目被设置成1。

·WIDTH –用点的数量表示点云数据集的宽度。

它能确定无序的点云中点的个数;也能确定有序点云一行中点的数目。有序点云数据集,意味着点云是类似于图像(或者矩阵)的结构,数据分为行和列。
WIDTH 640       # 每行有640个点

·HEIGHT –用点的数目表示点云数据集的高度。

它表示有序点云数据集的高度(行的总数);对于无序数据集它被设置成1(被用来检查一个数据集是有序还是无序)。
有序点云例子:
WIDTH 640       # 像图像一样的有序结构,有640行和480列,
HEIGHT 480      # 这样该数据集中共有640*480=307200个点
无序点云例子:
WIDTH 307200
HEIGHT 1        # 有307200个点的无序点云数据集

·VIEWPOINT–指定数据集中点云的获取视点。

VIEWPOINT有可能在不同坐标系之间转换的时候应用,在辅助获取其他特征时也比较有用,例如曲面法线,在判断方向一致性时,需要知道视点的方位,
视点信息被指定为平移(tx ty tz)+四元数(qw qx qy qz)。默认值是:
VIEWPOINT 0 0 0 1 0 0 0

·POINTS–指定点云中点的总数。从0.7版本开始,该字段就有点多余了,因此有可能在将来的版本中将它移除。
·DATA –指定存储点云数据的数据类型。从0.7版本开始,支持两种数据类型:ascii和二进制。

注意:文件头最后一行(DATA)的下一个字节就被看成是点云的数据部分了,它会被解释为点云数据。PCD文件的文件头部分必须以上面的顺序精确指定,之间用换行隔开。

3.数据存储类型
在0.7版本中,.PCD文件格式用两种模式存储数据:
如果以ASCII形式,每一点占据一个新行.从PCL 1.0.1版本开始,用字符串“nan”表示NaN,此字符表示该点的值不存在或非法等。

p_1
p_2
...
p_n

如果以二进制形式,这里数据是数组(向量)pcl::PointCloud.points的一份完整拷贝,
4.例子

# .PCD v.7 - Point Cloud Data file format
VERSION .7
FIELDS x y z rgb
SIZE 4 4 4 4
TYPE F FFF
COUNT 1 1 1 1
WIDTH 213
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 213
DATA ascii
0.93773 0.33763 0 4.2108e+06
0.90805 0.35641 0 4.2108e+06

三、从PCD文件读取点云数据

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

int main (int argc, char** argv)
{
  //创建一个PointCloud <PointXYZ> Boost共享指针并对其进行初始化。
  //从堆中分配了一个PointCloud<pcl::PointXYZ>对象,把这个对象的指针赋值给了cloud
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);

  if (pcl::io::loadPCDFile<pcl::PointXYZ> ("test_pcd.pcd", *cloud) == -1) //* load the file
  {
    PCL_ERROR ("Couldn't read file test_pcd.pcd \n");
    return (-1);
  }
  
  //Loaded 个数 data points from 文件 with the following fields: x y z
  std::cout << "Loaded "
            << cloud->width * cloud->height   //点的个数
            << " data points from test_pcd.pcd with the following fields: "
            << std::endl;
            
  for (std::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);
}

编译中遇到的问题

error C4996: 'std::copy::_Unchecked_iterators::_Deprecate': Call to 'std::copy' with parameters that may be unsafe - this call relies on the caller to check that the passed values are correct. To disable this warning, use -D_SCL_SECURE_NO_WARNINGS. See documentation on how to use Visual C++ 'Checked Iterators'

解决办法:
在工程属性—>C/C++—>命令行—>其他选项 中添加: -D_SCL_SECURE_NO_WARNINGS

四、从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;
  cloud.height   = 1;
  cloud.is_dense = false;
  cloud.points.resize (cloud.width * cloud.height);

  for (std::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);
  }

  pcl::io::savePCDFileASCII ("test_pcd.pcd", cloud);//储存在pcd文件中
  std::cerr << "Saved " << cloud.points.size () << " data points to test_pcd.pcd." << std::endl;

  for (std::size_t i = 0; i < cloud.points.size (); ++i)
    std::cerr << "    " << cloud.points[i].x << " " << cloud.points[i].y << " " << cloud.points[i].z << std::endl;

  return (0);
}

五、连接两个点云中的点

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

int main (int argc, char** argv)
{
  if (argc != 2)
  {
    std::cerr << "please specify command line arg '-f' or '-p'" << std::endl;
    exit(0);
  }
  pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c;//三个输入点云
  pcl::PointCloud<pcl::Normal> n_cloud_b;//两个输出点云,储存法线的点云
  pcl::PointCloud<pcl::PointNormal> p_n_cloud_c;//储存xyz和法线的点云

  // 为两个点云写入数据,points cloud_a 和cloud_b,或者cloud_a 和n_cloud_b
  cloud_a.width  = 5;//点个数
  cloud_a.height = cloud_b.height = n_cloud_b.height = 1;//都为无序点云
    cloud_a.points.resize (cloud_a.width * cloud_a.height);
    
  if (strcmp(argv[1], "-p") == 0)//比较字符串,判断是否为连接xyz和法线,如果不是,创建cloud_b
  {
    cloud_b.width  = 3;
    cloud_b.points.resize (cloud_b.width * cloud_b.height);
  }
  else
  {
    n_cloud_b.width = 5;//如果是创建n_cloud_b
    n_cloud_b.points.resize (n_cloud_b.width * n_cloud_b.height);
  }

//写入cloud_a的点
  for (std::size_t i = 0; i < cloud_a.points.size (); ++i)
  {
    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);
  }
  
  //写入cloud_b或者n_cloud_b的点
  if (strcmp(argv[1], "-p") == 0)
    for (std::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 (std::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::cerr << "Cloud A: " << std::endl;
  for (std::size_t i = 0; i < cloud_a.points.size (); ++i)
    std::cerr << "    " << cloud_a.points[i].x << " " << cloud_a.points[i].y << " " << cloud_a.points[i].z << std::endl;

  std::cerr << "Cloud B: " << std::endl;
  if (strcmp(argv[1], "-p") == 0)
    for (std::size_t i = 0; i < cloud_b.points.size (); ++i)
      std::cerr << "    " << cloud_b.points[i].x << " " << cloud_b.points[i].y << " " << cloud_b.points[i].z << std::endl;
  else
    for (std::size_t i = 0; i < n_cloud_b.points.size (); ++i)//输出法线点的方式不一样
      std::cerr << "    " << n_cloud_b.points[i].normal[0] << " " << n_cloud_b.points[i].normal[1] << " " << n_cloud_b.points[i].normal[2] << std::endl;

  // Copy the point cloud data
  if (strcmp(argv[1], "-p") == 0)
  {
    cloud_c  = cloud_a;//连接点云到c
    cloud_c += cloud_b;
    std::cerr << "Cloud C: " << std::endl;
    for (std::size_t i = 0; i < cloud_c.points.size (); ++i)
      std::cerr << "    " << 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);//连接字段到p_n_cloud_c
    std::cerr << "Cloud C: " << std::endl;
    for (std::size_t i = 0; i < p_n_cloud_c.points.size (); ++i)
      std::cerr << "    " <<
        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);
}

编译遇到的问题,生成exe文件后,进入cmd进行操作
在这里插入图片描述

  • 1
    点赞
  • 9
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值