PCD文件解析
上一节中,我们获取的PCD格式点云文件,内容如下:
# .PCD v0.7 - Point Cloud Data file format
VERSION 0.7
FIELDS x y z
SIZE 4 4 4
TYPE F F F
COUNT 1 1 1
WIDTH 5
HEIGHT 1
VIEWPOINT 0 0 0 1 0 0 0
POINTS 5
DATA ascii
1.28125 577.09375 197.9375
828.125 599.03125 491.375
358.6875 917.4375 842.5625
764.5 178.28125 879.53125
727.53125 525.84375 311.28125
PCD文由 “头文件 + 点云数据” 构成,头文件声明了该点云数据集的基本特性。
第零行为注释:标明文件类型。
第一行:VERSION
- 指定PCD文件的版本,由0.7可知该点云数据集是0.7版本的。
第二行:FIELDS
- 指定本点云数据集中任意一个点可以有的维度信息和其他附加信息。如:FIELDS x y z 指每个点都有xyz三个维度信息,FIELDS x y z rgb 指每个点除了xyz维度信息外还有颜色信息等。
第三行:SIZE
- 储存每个维度信息占用的字节数(byte)。1指用char型数据存储维度信息,2指用short型数据存储维度信息,4指用int或float型数据存储维度信息,8指用double型数据存储维度信息。
第四行:TYPE
- 用字符指定每一个维度的数据类型。
- I表示有符号类型:int8(char),int16(short),int32(int);
- U表示无符号类型:uint8(unsigned char),uint 16(unsigned short),uint32(unsigned int);
- F表示浮点型float和double。
第五行:COUNT
- 每个维度包含的元素个数。
第六行:WIDTH
- 点云数据集可分为有序数据集和无序数据集两种。
- 有序数据集类似矩阵,有行列之分,无序数据集则无行列之分。
- 根据数据集是否有序,WIDTH由不同的含义。
- 对有序数据集而言:表示数据集的宽度(每行点的数目);
- 对于无序数据集而言:表示数据集中点的总数(和下面的POINTS一样)。
第七行:HEIGHT
- 对有序数据集而言:表示数据集的高度(行数);
- 对于无序数据集而言:被设置为1,用于声明一个数据集是否有序。
第八行:VIEWPOINTS
-
数据集中点云的获取视点。视点信息被指定为“平移(txtytz) + 四元数(qwqxqyqz)”,默认值是:VIEWPOINT 0 0 0 1 0 0 0
第九行:POINTS
- 点云中点的总数,从0.7版本就开始显得有点多余,可能会在后续版本中舍去这个参数。
第十行:DATA
- 指定存储点云数据的数据存储格式:ASCLL码或二进制数据。
后续是数据部分:
- 以ASCLL码存储的点云数据,每一个点占据一行,“nan”表示不存在或非法的数据。
PCD文件读取
#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/point_types.h>
using namespace std;
int main()
{
pcl::PointCloud < pcl::PointXYZ >::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);// 创建点云指针。
// 读入PCD格式文件,如果文件不存在,返回-1
if (pcl::io::loadPCDFile<pcl::PointXYZ>("test_pcd_file.pcd", *cloud) == -1)
{
PCL_ERROR("Couldn't read file test_pcd_file.pcd\n");
return -1;
}
cout << "Loaded "
<< cloud->points.size()
<< " data points from test_pcd_file.pcd with the following fields:"
<< endl;
// 显示前5个点:
for (size_t i = 0; i < 5; i++)
{
cout << cloud->points[i].x << "\t" << cloud->points[i].y << "\t" << cloud->points[i].z << endl;
}
system("pause");
return 0;
}
xyz文件转pcd文件
- xyz格式数据一般每行有6列数据,前3列分别为点的 x,y,z坐标,后3列为点的法向量,一般以空格分隔;
#include<iostream>
#include<pcl/io/pcd_io.h>
#include<pcl/console/print.h>
#include<pcl/console/parse.h>
#include <boost/algorithm/string.hpp>
using namespace std;
using namespace pcl;
using namespace pcl::io;
using namespace pcl::console;
bool loadCloud(const string& filename, PointCloud<PointNormal>& cloud)
{
ifstream fs;
fs.open(filename.c_str(), ios::binary);
if (!fs.is_open() || fs.fail())
{
PCL_ERROR("Could not open file '%s'! Error : %s\n", filename.c_str(), strerror(errno));
fs.close();
return(false);
}
string line;
vector<string> st;
while (!fs.eof())
{
getline(fs, line);
if (line.empty())
{
continue;
}
boost::trim(line);
// #include <boost/algorithm/string.hpp>包含头文件,才可以使用split分割。
boost::split(st, line, boost::is_any_of(" "), boost::token_compress_on);
// 分割符是空格。
//cout << "st.size() = " << st.size() << endl;
if (st.size() != 6)
continue;
pcl::PointNormal point;
point.x = float(atof(st[0].c_str()));
point.y = float(atof(st[1].c_str()));
point.z = float(atof(st[2].c_str()));
point.normal[0]= float(atof(st[3].c_str()));
point.normal[1]= float(atof(st[4].c_str()));
point.normal[2]= float(atof(st[5].c_str()));
cloud.push_back(point);
}
fs.close();
cloud.width = uint32_t(cloud.size());
cloud.height = 1;
cloud.is_dense = true;
return (true);
}
int main()
{
string XYZfileName = "camel.xyz";
string PCDfileName = "camel.pcd";
PointCloud<PointNormal> cloud;
if (!loadCloud(XYZfileName, cloud))
return (-1);
cout << cloud.size() << endl;
//system("pause");
pcl::io::savePCDFileASCII(PCDfileName, cloud);
system("pause");
return 0;
}
std::string input_file = "../testCloud.xyz";
// 读取txt文件中的点云数据
std::ifstream infile(input_file.c_str());
std::vector<float> data;
float value;
while (infile >> value)
{
data.push_back(value);
}
infile.close();
// 将数据转换为点云格式
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
int size = data.size() / 3;
cloud->points.resize(size);
for (int i = 0; i < size; ++i)
{
cloud->points[i].x = data[i * 3];
cloud->points[i].y = data[i * 3 + 1];
cloud->points[i].z = data[i * 3 + 2];
}