IO输入输入模块
一、概述
PCL 库提供了一个模块用来对3D数据进行读写操作,这个库提供了一个模块:pcl_io库包含用于读取和写入文件以及从各种传感设备捕获点云的类和函数。每一个版本的函数接口可能有些差异,具体还是得去看官网的参考文档才能正确的使用。
我这里的环境
PCL版本: PCL 1.14.0-dev
编程语言:C++
二、点云数据格式
1. PCD 格式
参考链接:《太阳风暴》点云格式-PCD格式介绍
2. PLY 格式
3. OBJ 格式
4. STL 格式
5. OFF 格式
三、读取3D文件
1. API 总览
第一列是文件格式类型;第一行表头代表文件中的数据是什么内容、可以是点云、多边形mesh、材质。
PCL 为我们提供了针对于专门文件格式的读写API,就想 loadPCDFile、loadPLYFile等。也有提供了不区分格式的文件读取API,就像 load 函数一样。
pcl::PointCloud | pcl::PCLPointCloud2 | pcl::PolygonMesh | pcl::TextureMesh | |
---|---|---|---|---|
PCD (ASCII/BINARY/COMPRESSED) | loadPCDFile | loadPCDFile | ||
PLY (ASCII/BINARY) | loadPLYFile | loadPLYFile | loadPLYFile | |
OBJ (ASCII) | loadOBJFile | loadOBJFile | loadOBJFile | loadOBJFile |
IFS | loadIFSFile | loadIFSFile | loadIFSFile | |
STL (ASCII/BINARY) | loadPolygonFileSTL | |||
VTK | loadPolygonFileVTK | |||
CSV/ASCII | via pcl::ASCIIReader | via pcl::ASCIIReader | ||
Automatic format detection | load | load | load | load |
这个就需要看这个PCL的源代码怎么写的,一般我只用 load 函数,我们看看PCL load 函数的实现就明白了。其实 load 函数就是对 load**File函数的一些列的封装,暂时支持的格式也只有上面提到的pcd、ply等格式之类的。
namespace pcl
{
namespace io
{
template<typename PointT> int
load (const std::string& file_name, pcl::PointCloud<PointT>& cloud)
{
pcl_fs::path p (file_name.c_str ());
std::string extension = p.extension ().string ();
int result = -1;
if (extension == ".pcd")
result = pcl::io::loadPCDFile (file_name, cloud);
else if (extension == ".ply")
result = pcl::io::loadPLYFile (file_name, cloud);
else if (extension == ".ifs")
result = pcl::io::loadIFSFile (file_name, cloud);
else if (extension == ".obj")
result = pcl::io::loadOBJFile (file_name, cloud);
else
{
PCL_ERROR ("[pcl::io::load] Don't know how to handle file with extension %s\n", extension.c_str ());
result = -1;
}
return (result);
}
}
}
2. 示例
最常用的格式就是 ply、obj、pcd格式的文件格式。下面简单看一下部分常用函数的定义:
#include <pcl/io/pcd_io.h>
template<typename PointT >
int pcl::io::loadPCDFile(const std::string & file_name, pcl::PointCloud< PointT > & cloud)
#include <pcl/io/ply_io.h>
template<typename PointT >
int pcl::io::loadPLYFile(const std::string & file_name, pcl::PointCloud< PointT > & cloud)
我主要用作读取点云数据。我也只会介绍点云相关的数据。
实例
#include <pcl/io/io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_cloud.h>
// 闭合写法
pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud (new pcl::PointCloud<pcl::PointXYZ>); // 输入点云的指针
pcl::io::loadPLYFile("pointcloud.ply", *input_cloud); // 读取数据
// 分离写法
pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud;
input_cloud = pcl::PointCloud<pcl::PointXYZ>::Ptr(new pcl::PointCloud<pcl::PointXYZ>); // 输入点云的指针
pcl::io::loadPLYFile("pointcloud.ply", *input_cloud); // 读取数据
上面的 pcl::PointCloud<pcl::PointXYZ>::Ptr 其实就是宏定义的一个 share_ptr,我们其实也可以自己去管理这个类型的指针。
pcl::PointCloud<pcl::PointXYZ>::Ptr input_cloud;
// 宏定义
#include <pcl/point_cloud.h>
using Ptr = shared_ptr<PointCloud<PointT> >;
using ConstPtr = shared_ptr<const PointCloud<PointT> >;
官网完整的读取PCD文件
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
int main ()
{
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
if (pcl::io::loadPCDFile<pcl::PointXYZ> ("test_pcd.pcd", *cloud) == -1) //* load the file
{
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 (const auto& point: *cloud)
std::cout << " " << point.x
<< " " << point.y
<< " " << point.z << std::endl;
return (0);
}
四、保存3D文件
1. API 总览
第一列是文件格式类型;第一行表头代表文件中的数据是什么内容、可以是点云、多边形mesh、材质。
这里面的 PCD ASCII 和 PCD BINARY 只是保存的数据格式不一样,内容是一样的,ASCII是用文本保存、BINARY则是以二进制保存数据。其他带这些也是以这个为原则保存的。
pcl::PointCloud | pcl::PCLPointCloud2 | pcl::PolygonMesh | pcl::TextureMesh | |
---|---|---|---|---|
PCD ASCII | savePCDFile | savePCDFile | ||
PCD BINARY | savePCDFile | savePCDFile | ||
PCD COMPRESSED | savePCDFileBinaryCompressed | via pcl::PCDWriter | ||
PLY ASCII | savePLYFile | savePLYFile | savePLYFile | |
PLY BINARY | savePLYFile | savePLYFile | savePLYFileBinary | |
OBJ (ASCII) | saveOBJFile | saveOBJFile | ||
IFS | saveIFSFile | saveIFSFile | ||
STL (ASCII/BINARY) | savePolygonFileSTL | |||
VTK | saveVTKFile | saveVTKFile or savePolygonFileVTK | ||
Automatic format detection | save | save | save | save |
和 读取 文件的接口类似,save也是封装了以上的这些格式。
namespace pcl
{
namespace io
{
template<typename PointT> int
save (const std::string& file_name, const pcl::PointCloud<PointT>& cloud)
{
pcl_fs::path p (file_name.c_str ());
std::string extension = p.extension ().string ();
int result = -1;
if (extension == ".pcd")
result = pcl::io::savePCDFile (file_name, cloud, true);
else if (extension == ".ply")
result = pcl::io::savePLYFile (file_name, cloud, true);
else if (extension == ".ifs")
result = pcl::io::saveIFSFile (file_name, cloud);
else
{
PCL_ERROR ("[pcl::io::save] Don't know how to handle file with extension %s\n", extension.c_str ());
result = -1;
}
return (result);
}
}
}
2. 示例
部分的接口如下,参数也是非常的明了,最后一个参数:是否以二进制保持数据,默认是以ASCII,也就是人看得到的数据保存。
#include <pcl/io/ply_io.h>
template<typename PointT >
int pcl::io::savePLYFile(const std::string &file_name, const pcl::PointCloud<PointT> &cloud,bool binary_mode = false)
#include <pcl/io/ply_io.h>
template<typename PointT >
int pcl::io::savePCDFile(const std::string &file_name, const pcl::PointCloud<PointT> &cloud, bool binary_mode = false)
知道这些API就可以去保持啦
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
int main ()
{
pcl::PointCloud<pcl::PointXYZ> cloud;
// Fill in the cloud data
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::savePCDFile ("test_pcd.pcd", cloud);
std::cerr << "Saved " << cloud.size () << " data points to test_pcd.pcd." << std::endl;
for (const auto& point: cloud)
std::cerr << " " << point.x << " " << point.y << " " << point.z << std::endl;
return (0);
}