现有的点云格式繁杂多样,如stl、ply、obj、txt等都是常见的点云格式,这些不同类型的点云格式是在不同的时间阶段为了不同的目的而创建的,各有优点也均有不足,为了统一内部的点云格式,减少点云转换的额外花销,同时也为了解决现有文件结构不支持PCL中某些补充拓展的问题,PCL设计了内部独有的pcd文件格式,因此如果想利用PCL库,第一步就是需要将待研究的点云转换为pcd格式。
代码如下:
void ply2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr & cloud)
{
pcl::PLYReader reader;
reader.read<PointT>(filename, *cloud);
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
}
void stl2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
//读取STL格式模型
vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
reader->SetFileName(filename.c_str());
reader->Update();
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata = reader->GetOutput();
polydata->GetNumberOfPoints();
//从poly转pcd
pcl::io::vtkPolyDataToPointCloud(polydata, *cloud);
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
代码如下(示例):
//导入文件
bool
loadCloud(const std::string& filename, pcl::PointCloud<PointT>& cloud)
{
std::ifstream fs;
fs.open(filename.c_str(), std::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);
}
std::string line;
std::vector<std::string> st;
while (!fs.eof())
{
std::getline(fs, line);
//忽略空行
if (line.empty())
continue;
// 标记线
boost::trim(line);
boost::split(st, line, boost::is_any_of("\t\r "), boost::token_compress_on);
if (st.size() != 3)
continue;
//将数据写入pcd文件
cloud.push_back(PointT(float(atof(st[0].c_str())), float(atof(st[1].c_str())), float(atof(st[2].c_str()))));
}
fs.close();
//设置pcd文件属性
cloud.width = cloud.size(); cloud.height = 1; cloud.is_dense = true;
return (true);
}
void xyz2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
//读取xyz格式模型
if (!loadCloud(filename, *cloud))
cout << filename << "读取失败" << endl;
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
void obj2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
//读取STL格式模型
vtkSmartPointer<vtkPolyData> polydata;
vtkSmartPointer<vtkOBJReader> reader = vtkSmartPointer<vtkOBJReader>::New();
reader->SetFileName(filename.c_str());
reader->Update();
polydata = reader->GetOutput();
pcl::io::vtkPolyDataToPointCloud(polydata, *cloud);
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
struct tagPOINT_3D
{
float x;
float y;
float z;
float I;
};
void txt2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
int number_Txt;
string line;
tagPOINT_3D TxtPoint;
vector<tagPOINT_3D> m_vTxtPoints;
//输入txt文件
ifstream input(filename);
//读取文件中的有效值
while (getline(input, line)) {
tagPOINT_3D TxtPoint;
replace(line.begin(), line.end(), ',', ' ');//将逗号替换为空格
istringstream record(line);
record >> TxtPoint.x;
record >> TxtPoint.y;
record >> TxtPoint.z;
//record >> TxtPoint.I;
//先将数据写入m_vTxtPoints
m_vTxtPoints.push_back(TxtPoint);
}
number_Txt = m_vTxtPoints.size();
// 设置pcd文件属性
cloud->width = number_Txt;
cloud->height = 1;
cloud->is_dense = false;
cloud->points.resize(cloud->width * cloud->height);
//将m_vTxtPoints数据写入pcd文件
for (size_t i = 0; i < cloud->points.size(); ++i)
{
cloud->points[i].x = m_vTxtPoints[i].x;
cloud->points[i].y = m_vTxtPoints[i].y;
cloud->points[i].z = m_vTxtPoints[i].z;
//cloud->points[i].intensity = m_vTxtPoints[i].I;
}
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
void las2pcd(const std::string filename, pcl::PointCloud<PointTI>::Ptr& cloud) {
//中文可能会有乱码
cout << "读取" << filename << "..." << endl;
pdal::Option las_opt("filename", filename);
pdal::Options las_opts;
las_opts.add(las_opt);
pdal::PointTable table;
pdal::LasReader las_reader;
las_reader.setOptions(las_opts);
las_reader.prepare(table);
pdal::PointViewSet point_view_set = las_reader.execute(table);
pdal::PointViewPtr point_view = *point_view_set.begin();
pdal::Dimension::IdList dims = point_view->dims();
pdal::LasHeader las_header = las_reader.header();
//头文件信息
unsigned int PointCount = las_header.pointCount();
double scale_x = las_header.scaleX();
double scale_y = las_header.scaleY();
double scale_z = las_header.scaleZ();
double offset_x = las_header.offsetX();
double offset_y = las_header.offsetY();
double offset_z = las_header.offsetZ();
//读点
unsigned int n_features = las_header.pointCount();
int count = 0;
for (pdal::PointId id = 0; id < point_view->size(); ++id)
{
double x = point_view->getFieldAs<double>(pdal::Dimension::Id::X, id);
double y = point_view->getFieldAs<double>(pdal::Dimension::Id::Y, id);
double z = point_view->getFieldAs<double>(pdal::Dimension::Id::Z, id);
double intensity = point_view->getFieldAs<double>(pdal::Dimension::Id::Intensity, id);
PointTI point(x, y, z, intensity);
cloud->push_back(point);
}
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
void bin2pcd(std::string filename, pcl::PointCloud<PointTI>::Ptr& cloud)
{
// load point cloud
fstream input(filename.c_str(), ios::in | ios::binary);
if (!input.good()) {
cerr << "Could not read file: " << filename << endl;
exit(EXIT_FAILURE);
}
input.seekg(0, ios::beg);
//pcl::PointCloud::Ptr points(new pcl::PointCloud);
int i;
for (i = 0; input.good() && !input.eof(); i++) {
pcl::PointXYZI point;
input.read((char*)&point.x, 3 * sizeof(float));
input.read((char*)&point.intensity, sizeof(float));
cloud->push_back(point);
}
input.close();
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
//#pragma execution_character_set("utf-8")//解决中文
#include
#include
//pcd
#include
//ply
#include
//stl
#include
//mesh
#include
#include
#include
#include
#include
#include
#include
#include
using namespace std;
typedef pcl::PointXYZ PointT;
typedef pcl::PointXYZI PointTI;
void ply2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr & cloud)
{
pcl::PLYReader reader;
reader.read<PointT>(filename, *cloud);
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
void stl2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
//读取STL格式模型
vtkSmartPointer<vtkSTLReader> reader = vtkSmartPointer<vtkSTLReader>::New();
reader->SetFileName(filename.c_str());
reader->Update();
vtkSmartPointer<vtkPolyData> polydata = vtkSmartPointer<vtkPolyData>::New();
polydata = reader->GetOutput();
polydata->GetNumberOfPoints();
//从poly转pcd
pcl::io::vtkPolyDataToPointCloud(polydata, *cloud);
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
void obj2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
//读取STL格式模型
vtkSmartPointer<vtkPolyData> polydata;
vtkSmartPointer<vtkOBJReader> reader = vtkSmartPointer<vtkOBJReader>::New();
reader->SetFileName(filename.c_str());
reader->Update();
polydata = reader->GetOutput();
pcl::io::vtkPolyDataToPointCloud(polydata, *cloud);
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
struct tagPOINT_3D
{
float x;
float y;
float z;
float I;
};
void txt2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
int number_Txt;
string line;
tagPOINT_3D TxtPoint;
vector<tagPOINT_3D> m_vTxtPoints;
//输入txt文件
ifstream input(filename);
//读取文件中的有效值
while (getline(input, line)) {
tagPOINT_3D TxtPoint;
replace(line.begin(), line.end(), ',', ' ');//将逗号替换为空格
istringstream record(line);
record >> TxtPoint.x;
record >> TxtPoint.y;
record >> TxtPoint.z;
//record >> TxtPoint.I;
//先将数据写入m_vTxtPoints
m_vTxtPoints.push_back(TxtPoint);
}
number_Txt = m_vTxtPoints.size();
// 设置pcd文件属性
cloud->width = number_Txt;
cloud->height = 1;
cloud->is_dense = false;
cloud->points.resize(cloud->width * cloud->height);
//将m_vTxtPoints数据写入pcd文件
for (size_t i = 0; i < cloud->points.size(); ++i)
{
cloud->points[i].x = m_vTxtPoints[i].x;
cloud->points[i].y = m_vTxtPoints[i].y;
cloud->points[i].z = m_vTxtPoints[i].z;
//cloud->points[i].intensity = m_vTxtPoints[i].I;
}
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
//导入文件
bool
loadCloud(const std::string& filename, pcl::PointCloud<PointT>& cloud)
{
std::ifstream fs;
fs.open(filename.c_str(), std::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);
}
std::string line;
std::vector<std::string> st;
while (!fs.eof())
{
std::getline(fs, line);
//忽略空行
if (line.empty())
continue;
// 标记线
boost::trim(line);
boost::split(st, line, boost::is_any_of("\t\r "), boost::token_compress_on);
if (st.size() != 3)
continue;
//将数据写入pcd文件
cloud.push_back(PointT(float(atof(st[0].c_str())), float(atof(st[1].c_str())), float(atof(st[2].c_str()))));
}
fs.close();
//设置pcd文件属性
cloud.width = cloud.size(); cloud.height = 1; cloud.is_dense = true;
return (true);
}
void xyz2pcd(std::string filename, pcl::PointCloud<PointT>::Ptr& cloud)
{
//读取xyz格式模型
if (!loadCloud(filename, *cloud))
cout << filename << "读取失败" << endl;
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
void bin2pcd(std::string filename, pcl::PointCloud<PointTI>::Ptr& cloud)
{
// load point cloud
fstream input(filename.c_str(), ios::in | ios::binary);
if (!input.good()) {
cerr << "Could not read file: " << filename << endl;
exit(EXIT_FAILURE);
}
input.seekg(0, ios::beg);
//pcl::PointCloud::Ptr points(new pcl::PointCloud);
int i;
for (i = 0; input.good() && !input.eof(); i++) {
pcl::PointXYZI point;
input.read((char*)&point.x, 3 * sizeof(float));
input.read((char*)&point.intensity, sizeof(float));
cloud->push_back(point);
}
input.close();
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
void las2pcd(const std::string filename, pcl::PointCloud<PointTI>::Ptr& cloud) {
//中文可能会有乱码
cout << "读取" << filename << "..." << endl;
pdal::Option las_opt("filename", filename);
pdal::Options las_opts;
las_opts.add(las_opt);
pdal::PointTable table;
pdal::LasReader las_reader;
las_reader.setOptions(las_opts);
las_reader.prepare(table);
pdal::PointViewSet point_view_set = las_reader.execute(table);
pdal::PointViewPtr point_view = *point_view_set.begin();
pdal::Dimension::IdList dims = point_view->dims();
pdal::LasHeader las_header = las_reader.header();
//头文件信息
unsigned int PointCount = las_header.pointCount();
double scale_x = las_header.scaleX();
double scale_y = las_header.scaleY();
double scale_z = las_header.scaleZ();
double offset_x = las_header.offsetX();
double offset_y = las_header.offsetY();
double offset_z = las_header.offsetZ();
//读点
unsigned int n_features = las_header.pointCount();
int count = 0;
for (pdal::PointId id = 0; id < point_view->size(); ++id)
{
double x = point_view->getFieldAs<double>(pdal::Dimension::Id::X, id);
double y = point_view->getFieldAs<double>(pdal::Dimension::Id::Y, id);
double z = point_view->getFieldAs<double>(pdal::Dimension::Id::Z, id);
double intensity = point_view->getFieldAs<double>(pdal::Dimension::Id::Intensity, id);
PointTI point(x, y, z, intensity);
cloud->push_back(point);
}
//用对应的文件名保存pcd文件
std::string pp = boost::filesystem::path(filename).filename().string();
string name = pp.substr(0, pp.rfind("."));
std::string pcdfilename = name.append(".pcd");
cout << pcdfilename << endl;
pcl::io::savePCDFileASCII(pcdfilename, *cloud);
//依据需要选择保存的格式
//pcl::io::savePCDFileBinary(pcdfilename, *cloud);
if (!cloud->empty())
{
cout << filename << "转换完成" << endl;
}
}
int
main(int argc, char* argv[]) {
pcl::PointCloud<pcl::PointXYZI>::Ptr lascloud(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);
string file0 = "E:\\VS2019Projects\\PCL\\2pcd\\Data1\\bunny.ply";
//ply2pcd(file0, cloud);
string file1 = "E:\\VS2019Projects\\PCL\\2pcd\\Data1\\AfricanAnimals.stl";
//stl2pcd(file1, cloud);
string file2 = "E:\\VS2019Projects\\PCL\\2pcd\\Data1\\mode.obj";
//obj2pcd(file2, cloud);
string file3 = "E:\\VS2019Projects\\PCL\\2pcd\\Data1\\dragon.txt";
//txt2pcd(file3, cloud);
string file4 = "E:\\VS2019Projects\\PCL\\2pcd\\Data1\\目标1.asc";
//txt2pcd(file4, cloud);
string file5 = "E:\\VS2019Projects\\PCL\\2pcd\\Data1\\crystal_4000.xyz";
//xyz2pcd(file5, cloud);
string file6 = "E:\\VS2019Projects\\PCL\\2pcd\\data\\000000.bin";
bin2pcd(file6, lascloud);
//las2pcd(file, lascloud, true);
//--------------------------------------可视化--------------------------
pcl::visualization::PCLVisualizer viewer;
viewer.addPointCloud<PointT>(cloud, "cloud");
viewer.addCoordinateSystem();
while (!viewer.wasStopped())
{
viewer.spinOnce(100);
}
//清空内存
cloud->points.clear();
}
多种常见三维格式数据转成pcd文件,除了las和bin格式的测试文件包含强度信息外,其余测试文件值包含xyz三维数据,如果包含RGB或强度信息,只需要在对应部分进行简单修改,在此不予赘述。
此外,如果有其他格式转换需求也可以在评论区提出来,有时间我将进行补充~