【点云PCL入门】输入输出(IO)

1.PCD文件格式

# .PCD v.7 - Point Cloud Data file format
VERSION .7  //指定PCD文件版本
FIELDS x y z rgb  //指定一个点可以有的每一个维度和字段的名字
SIZE 4 4 4 4  //用字节数指定每一个维度的大小,1(unsigned char/char),2(unsigned short/short),4(unsinged int/int/float)
TYPE F F F F  //指定每一个维度的类型,I,U,F
COUNT 1 1 1 1  //指定每一个维度包含的元素数目
WIDTH 213   //点云数据集的宽度,无序点云的个数,有序点云一行中的点数目
HEIGHT 1  //有序点云数据集的行的总数,无序点云设置为1,用来检查数据集是有序还是无序
VIEWPOINT 0 0 0 1 0 0 0  //视点:平移+四元数
POINTS 213  //指定点云中点的总数
DATA ascii  //指定存储点云数据的数据类型,ASCII和二进制
0.93773 0.33763 0 4.2108e+06 //ASCII每一个点占据一个新行,用字符串“nan”表示NaN,表示该点的值不存在或非法。
0.90805 0.35641 0 4.2108e+06
0.81915 0.32 0 4.2108e+06
0.97192 0.278 0 4.2108e+06
0.944 0.29474 0 4.2108e+06
0.98111 0.24247 0 4.2108e+06
0.93655 0.26143 0 4.2108e+06
0.91631 0.27442 0 4.2108e+06

2.从PCD中读取点云数据

#include <iostream>
//PCD读写类相关的头文件
#include <pcl/io/pcd_io.h>
//PCL中支持的点类型头文件
#include <pcl/point_types.h>
int main(int argc, char** argv)
{
	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;
	}
	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;
}

3.向PCD中写入点云数据

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

using namespace std;
using namespace pcl;

int main(int argc, char* argv[])
{
	PointCloud<PointXYZ> cloud;
	cloud.width = 5;
	cloud.height = 1;
	cloud.is_dense = false;//如果点云中的点是否包含 Inf/NaN这种值,则为true
	cloud.points.resize(cloud.height*cloud.width);
	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;
	}
	pcl::io::savePCDFileASCII("test.pcd", cloud);
	std::cerr << "Saved " << cloud.points.size()
		<< " data points to test_pcd.pcd." << std::endl;
	for (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);
}

4.点云中的字段或数据连接

两片点云中的数据连接的约束是两个点云数据中的字段类型和维度必须相等,两片点云中的字段连接的约束是点的数量要相同。

#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;

  // Fill in the cloud data
  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)
  {
    cloud_b.width  = 3;
    cloud_b.points.resize (cloud_b.width * cloud_b.height);
  }
  else{
    n_cloud_b.width = 5;
    n_cloud_b.points.resize (n_cloud_b.width * n_cloud_b.height);
  }

  for (std::size_t i = 0; i < cloud_a.size (); ++i)
  {
    cloud_a[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
    cloud_a[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
    cloud_a[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
  }
  if (strcmp(argv[1], "-p") == 0)
    for (std::size_t i = 0; i < cloud_b.size (); ++i)
    {
      cloud_b[i].x = 1024 * rand () / (RAND_MAX + 1.0f);
      cloud_b[i].y = 1024 * rand () / (RAND_MAX + 1.0f);
      cloud_b[i].z = 1024 * rand () / (RAND_MAX + 1.0f);
    }
  else
    for (std::size_t i = 0; i < n_cloud_b.size (); ++i)
    {
      n_cloud_b[i].normal[0] = 1024 * rand () / (RAND_MAX + 1.0f);
      n_cloud_b[i].normal[1] = 1024 * rand () / (RAND_MAX + 1.0f);
      n_cloud_b[i].normal[2] = 1024 * rand () / (RAND_MAX + 1.0f);
    }
  std::cerr << "Cloud A: " << std::endl;
  for (std::size_t i = 0; i < cloud_a.size (); ++i)
    std::cerr << "    " << cloud_a[i].x << " " << cloud_a[i].y << " " << cloud_a[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.size (); ++i)
      std::cerr << "    " << cloud_b[i].x << " " << cloud_b[i].y << " " << cloud_b[i].z << std::endl;
  else
    for (std::size_t i = 0; i < n_cloud_b.size (); ++i)
      std::cerr << "    " << n_cloud_b[i].normal[0] << " " << n_cloud_b[i].normal[1] << " " << n_cloud_b[i].normal[2] << std::endl;

  // Copy the point cloud data
  if (strcmp(argv[1], "-p") == 0)
  {
    cloud_c  = cloud_a;
    cloud_c += cloud_b;
    std::cerr << "Cloud C: " << std::endl;
    for (std::size_t i = 0; i < cloud_c.size (); ++i)
      std::cerr << "    " << cloud_c[i].x << " " << cloud_c[i].y << " " << cloud_c[i].z << " " << std::endl;
  }
  else
  {
    pcl::concatenateFields (cloud_a, n_cloud_b, p_n_cloud_c);
    std::cerr << "Cloud C: " << std::endl;
    for (std::size_t i = 0; i < p_n_cloud_c.size (); ++i)
      std::cerr << "    " <<
        p_n_cloud_c[i].x << " " << p_n_cloud_c[i].y << " " << p_n_cloud_c[i].z << " " <<
        p_n_cloud_c[i].normal[0] << " " << p_n_cloud_c[i].normal[1] << " " << p_n_cloud_c[i].normal[2] << std::endl;
  }
  return (0);
}

5.PLY与PCD数据格式转换

#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>

using namespace pcl;
using namespace std;

int main(int argc, char** argv)
{
	std::string load_ply_file = "./test.ply";
	string save_pcd_file = "./test.pcd";
	pcl::PCLPointCloud2 cloud;
	std::string save_ply_file = "./pcd2ply.ply";
	string load_pcd_file = "./pcd2ply.pcd";
	
	/*pcd to ply */
	if (io::loadPCDFile(load_pcd_file, cloud) < 0)
		return false;

	PLYWriter writerPLY;
	writerPLY.write(save_pcd_file, cloud, Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), false, true);

	/*ply to pcd*/
	pcl::PLYReader reader;
	if (reader.read(load_ply_file, cloud) < 0)
		return false;

	// Convert to PLY and save
	PCDWriter writer;
	writer.write(save_pcd_file, cloud, Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), "ascii");
	return (0);
}

6.点云txt转pcd

在这里插入图片描述

6.1 ifstream

bool readTxtFile(const std::string &fileName, const char tag, const pcl::PointCloud<pcl::PointXYZ>::Ptr &pointCloud)
{
	cout << "reading file start..... " << endl;
	ifstream fin(fileName);
	std::string linestr;
	while (getline(fin, linestr))
	{
		std::vector<std::string> strvec;
		std::string s;
		std::stringstream ss(linestr);
		while (getline(ss, s, tag))//tag是分隔符
		{
			strvec.push_back(s);
		}
		if (strvec.size() < 3) {
			cout << "格式不支持" << endl;
			return false;
		}
		pcl::PointXYZ p;
		p.x = stod(strvec[0]);
		p.y = stod(strvec[1]);
		p.z = stod(strvec[2]);
		pointCloud->points.push_back(p);
	}
	fin.close();

	return true;
}

//readTxtFile("./1.txt", ' ', cloud);

6.2 fscanf()

format:直接设置存储点云格式,不用设置分割符

void txt2pcds(const char* readPath, const pcl::PointCloud<pcl::PointXYZ>::Ptr &pointCloud) 
{
	pcl::PointXYZ txtPoint;
	FILE *fp_txt = fopen(readPath, "r");
	double x, y, z;

	if (fp_txt) 
	{
		//format:存储点云格式
		//while(3 ==fscanf(fp_txt,"%lf,%lf,%lf\n",&x,&y,&z))
		while (fscanf(fp_txt, "%lf %lf %lf\n", &x, &y, &z) != EOF) 
		{
			txtPoint.x = x;
			txtPoint.y = y;
			txtPoint.z = z;
			pointCloud->points.push_back(txtPoint);
		}
	}

	fclose(fp_txt);
}

6.3 Qt的secession()

bool loadTxtFile(const std::string &fileName,  const pcl::PointCloud<pcl::PointXYZ>::Ptr &pointCloud)
{
	ifstream infile;
	infile.open(fileName.data());
	assert(infile.is_open());
	std::string s;
	pcl::PointXYZ current_point;
	while (getline(infile,s))
	{
		QString ss, s1, s2, s3;
		ss = QString::fromStdString(s);
		s1 = ss.section(" ", 0, 0);
		s2 = ss.section(" ", 1, 1);
		s3 = ss.section(" ", 2, 2);
		
		current_point.x = s1.toFloat();
		current_point.y = s2.toFloat();
		current_point.z = s3.toFloat();
		pointCloud->points.push_back(current_point);
	}
	infile.close();
	return true;
}

参考

1.https://pcl.readthedocs.io/projects/tutorials/en/latest/#i-o
2.https://blog.csdn.net/qq_22170875/article/details/90140851
3.https://blog.csdn.net/shengxiamei/article/details/71359033

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值