PCL 系列 —— txt 格式点云读取并转 pcd 格式显示

一、核心函数:

默认设置分割符为空格,可以设置为逗号或分号。可以适当修改,读取坐标之外的反射强度、颜色等其他信息。

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

	//转换成pcd
	pointCloud->width = (int)myPoint.size();
	pointCloud->height = 1;
	pointCloud->is_dense = false;
	pointCloud->points.reserve(pointCloud->width * pointCloud->height);
	for (int i = 0; i < myPoint.size(); i++)
	{
		pointCloud->points[i].x = myPoint[i].x;
		pointCloud->points[i].y = myPoint[i].y;
		pointCloud->points[i].z = myPoint[i].z;
	}
	cout << "reading file finished! " << endl;
	cout << "There are " << pointCloud->points.size() << " points!" << endl;
	return true;
}

需要注意的是,下列写法存在问题,显示点云时没问题,但输出保存时会出现异常。猜测是点云没有设置宽高与有序无需属性导致,求大神解惑。

PointT p;
p.x = stod(strvec[0]);
p.y = stod(strvec[1]);
p.z = stod(strvec[2]);
pointCloud.push_back(p);

二、示例代码:

#include <iostream>
#include <fstream>
#include <strstream>
#include <vector>
#include <pcl/io/pcd_io.h>  //文件输入输出
#include <pcl/point_types.h>  //点类型相关定义
#include <pcl/visualization/cloud_viewer.h>  
#include <pcl/visualization/pcl_visualizer.h>

using namespace std;

typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;


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

	//转换成pcd
	pointCloud->width = (int)myPoint.size();
	pointCloud->height = 1;
	pointCloud->is_dense = false;
	pointCloud->points.resize(pointCloud->width * pointCloud->height);
	for (int i = 0; i < myPoint.size(); i++)
	{
		pointCloud->points[i].x = myPoint[i].x;
		pointCloud->points[i].y = myPoint[i].y;
		pointCloud->points[i].z = myPoint[i].z;
	}
	cout << "reading file finished! " << endl;
	cout << "There are " << pointCloud->points.size() << " points!" << endl;
	return true;
}


int main()
{
	//1.读取点云
	PointCloudT::Ptr cloud(new PointCloudT);
	readTxtFile("data1.txt",' ',cloud);
	
	//2.显示点云
	pcl::visualization::PCLVisualizer viewer("cloud viewer");
	viewer.addPointCloud<PointT>(cloud, "sample");
	

	while (!viewer.wasStopped())
	{
		viewer.spinOnce();
	}

	//3.点云输出
	pcl::PCDWriter writer;
	writer.writeASCII<PointT>("demo.pcd", *cloud); 
	

	system("pause");
	return 0;
}

三、运行结果:

四、备注:

当点云原始坐标精度较高时,转换为 pcd 格式容易丢失精度。从上图可以看出,点云显示效果已然失真,扫描线变成了斜线而不是直线!因此,当原始点云坐标数字有效位数过多时,应该进行平移,减少坐标有效位数。