索引
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