前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【PCL】输入输出(I/O)

【PCL】输入输出(I/O)

作者头像
DevFrank
发布2024-07-24 15:02:43
720
发布2024-07-24 15:02:43
举报
文章被收录于专栏:C++开发学习交流

学习资料

最重要的参考资料是官网:https://pointclouds.org/,Docs是函数手册,Tutorials是代码示例,两者结合学习(shiyong)。

在这里插入图片描述
在这里插入图片描述

另外,有位大佬总结了PCL的相关资料,在这里,太感谢了,有学习方法和demo演示等等,跟着学就完事了。

总的来说,PCL主要是对16个模块的函数进行学习,掌握基础后,重点是要做相关项目,积累实战经验。大家都建议在Ubuntu学习,但对我而言,我却觉得在Windows下更能理解PCL相关第三方库和头文件、库目录等的配置,而且用VS调试也比较方便,因人而异吧,我是在Windows学习,然后工程化再转到Ubuntu。

点云文件格式

点云IO相关函数如下:https://pointclouds.org/documentation/group__io.html

在PCD格式出现之前,描述3D物体的格式有PLY、STL、OBJ、X3D等,但这些格式都无法满足点云在感知领域的数据处理要求,因此PCD格式诞生。

PCD文件的入口定义一般有:

代码语言:javascript
复制
VERSION
FIELDS
SIZE
TYPE
COUNT
WIDTH
HEIGHT
VIEWPOINT
POINTS
DATA

例如,对比这个例子:

代码语言:javascript
复制
# .PCD v.7 - Point Cloud Data file format
VERSION .7
FIELDS x y z rgb
SIZE 4 4 4 4
TYPE F F F F
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
0.81915 0.32 0 4.2108e+06
0.97192 0.278 0 4.2108e+06

写入点云数据到PCD文件

创建write_pcd.cpp

代码语言:javascript
复制
#include <iostream>
#include <pcl/io/pcd_io.h>	//pcd输入输出头
#include <pcl/point_types.h>	//pcd点云类型头

using namespace std;

int main()
{
	pcl::PointCloud<pcl::PointXYZ> cloud;	//实例化模板类PointCloud,类型为PointXYZ

	//写入点云数据,用随机数填充
	cloud.width = 5;
	cloud.height = 1;
	cloud.is_dense = false;	//是否是稠密型
	cloud.resize(cloud.width * cloud.height);

	for (auto& point : cloud)
	{
		point.x = 1024 * rand() / (RAND_MAX + 1.0f);
		point.y = 1024 * rand() / (RAND_MAX + 1.0f);
		point.z = 1024 * rand() / (RAND_MAX + 1.0f);
	}

	pcl::io::savePCDFileASCII("test_pcd.pcd", cloud);
	cerr << "Saved " << cloud.size() << " data points to test_pcd.pcd." << endl;
	//cerr:输出到标准错误的ostream对象,常用于程序错误信息;

	for(const auto& point: cloud)
		cerr << "    " << point.x << " " << point.y << " " << point.z << endl;

	return 0;
}

运行结果如下:

在这里插入图片描述
在这里插入图片描述

从PCD文件读取点云数据

创建pcd_read.cpp

代码语言:javascript
复制
#include <iostream>
#include <pcl/io/pcd_io.h>		//pcd输入输出头
#include <pcl/point_types.h>	//pcd点云类型头

using namespace std;

int main()
{
	//创建一个PointCloud<pcl::PointXYZ>  boost共享指针并进行实例化
	pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

	//判断点云文件是否存在
	if (pcl::io::loadPCDFile<pcl::PointXYZ>("test_pcd.pcd", *cloud) == -1)
	{
		PCL_ERROR("Couldn't read file test_pcd.pcd \n");
		return (-1);
	}
	//转为PCD点云类型并输出
	cout << "Loaded "
		<< cloud->width * cloud->height // 宽*高
		<< " data points from test_pcd.pcd with the following fields: "
		<< endl;
	for (size_t i = 0; i < cloud->points.size(); ++i)
		cout << "    " << cloud->points[i].x
		<< " " << cloud->points[i].y
		<< " " << cloud->points[i].z << endl;

	return (0);
}

运行结果如下:

点云拼接

点云拼接有点云连接concatenate points(纵向连接) 和字段连接concatenate fields(横向连接) 两种。 创建concatenate_clouds.cpp

代码语言:javascript
复制
#include <iostream>
#include <pcl/io/pcd_io.h>		//pcd输入输出头
#include <pcl/point_types.h>	//pcd点云类型头

using namespace std;

int main(int argc, char** argv)
{
	cout << "argc: " << argc << endl;
	cout << "argv: " << argv[1] << endl;
	if (argc != 2) //提示如果执行可执行文件输入两个参数 -f 或者-p
	{
		cerr << "please specify command line arg '-f' or '-p'" << endl;
		exit(0);
	}
	//申明三个pcl::PointXYZ点云数据类型,分别为cloud_a, cloud_b, cloud_c
	pcl::PointCloud<pcl::PointXYZ> cloud_a, cloud_b, cloud_c;
	//存储进行连接时需要的Normal点云,Normal (float n_x, float n_y, float n_z)
	pcl::PointCloud<pcl::Normal> n_cloud_b;
	//存储连接XYZ与normal后的点云
	pcl::PointCloud<pcl::PointNormal> p_n_cloud_c;

	// 创建点云数据
	//设置cloud_a的个数为5
	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)                         //判断是否为连接a+b=c(点云连接)
	{
		cloud_b.width = 3;
		cloud_b.points.resize(cloud_b.width * cloud_b.height);
	}
	else
	{
		n_cloud_b.width = 5; //如果是连接XYZ与normal则生成5个法线(字段间连接)
		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产生三个点(每个点都有X Y Z 三个随机填充的值)
		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)
		for (size_t i = 0; i < cloud_b.points.size(); ++i)
		{ //如果连接a+b=c,则cloud_b用三个点作为xyz的数据
			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)
		{ //如果连接xyz+normal=xyznormal则n_cloud_b用5个点作为normal数据
			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);
		}
	/*******************************************************************
	定义了连接点云会用到的5个点云对象:3个输入(cloud_a cloud_b 和n_cloud_b)
	两个输出(cloud_c  n_cloud_c)然后为两个输入点云cloud_a和 cloud_b或者cloud_a 和n_cloud_b填充数据
	********************************************************************/
	//输出Cloud A
	cerr << "Cloud A: " << endl;
	for (size_t i = 0; i < cloud_a.points.size(); ++i)
		cerr << "    " << cloud_a.points[i].x << " " << cloud_a.points[i].y << " " << cloud_a.points[i].z << endl;
	//输出Cloud B
	cerr << "Cloud B: " << endl;
	if (strcmp(argv[1], "-p") == 0)
		for (size_t i = 0; i < cloud_b.points.size(); ++i)
			cerr << "    " << cloud_b.points[i].x << " " << cloud_b.points[i].y << " " << cloud_b.points[i].z << endl;
	else //输出n_Cloud_b
		for (size_t i = 0; i < n_cloud_b.points.size(); ++i)
			cerr << "    " << n_cloud_b.points[i].normal[0] << " " << n_cloud_b.points[i].normal[1] << " " << n_cloud_b.points[i].normal[2] << endl;

	// 两种方式
	if (strcmp(argv[1], "-p") == 0)
	{
		cloud_c = cloud_a;
		cloud_c += cloud_b; //连接点云 (把cloud_a和cloud_b连接一起创建cloud_c后输出)
		cerr << "Cloud C: " << endl;
		for (size_t i = 0; i < cloud_c.points.size(); ++i)
			cerr << "    " << cloud_c.points[i].x << " " << cloud_c.points[i].y << " " << cloud_c.points[i].z << " " << endl;
	}
	else
	{ //连接字段  (把cloud_a和 n_cloud_b字段连接 一起创建 p_n_cloud_c)
		pcl::concatenateFields(cloud_a, n_cloud_b, p_n_cloud_c);
		cerr << "Cloud C: " << endl;
		for (size_t i = 0; i < p_n_cloud_c.points.size(); ++i)
			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] << endl;
	}
	return (0);
}

运行点云连接-p:

在这里插入图片描述
在这里插入图片描述

运行字段连接-f:

在这里插入图片描述
在这里插入图片描述

以上。

本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2024-07-24,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体同步曝光计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 学习资料
  • 点云文件格式
  • 写入点云数据到PCD文件
  • 从PCD文件读取点云数据
  • 点云拼接
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档