PCL 各种三维格式转PCD文件(ply、stl、xyz、obj、asc、txt、las、laz、bin)

系列文章目录

事先准备
PCL环境配置
PDAL环境配置


前言

现有的点云格式繁杂多样,如stl、ply、obj、txt等都是常见的点云格式,这些不同类型的点云格式是在不同的时间阶段为了不同的目的而创建的,各有优点也均有不足,为了统一内部的点云格式,减少点云转换的额外花销,同时也为了解决现有文件结构不支持PCL中某些补充拓展的问题,PCL设计了内部独有的pcd文件格式,因此如果想利用PCL库,第一步就是需要将待研究的点云转换为pcd格式。


一、本博客包含哪些格式?

  • ply
  • stl
  • xyz
  • obj
  • asc、txt
  • las、laz
  • bin

二、转换代码

1.ply2pcd

代码如下:

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;
    }
}
}

2. stl2pcd

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;
    }
}

3. xyz2pcd

代码如下(示例):

//导入文件
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;
    }
}

4. obj2pcd

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;
    }
}

5. asc2pcd、txt2pcd

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;
    }
}

6. las、laz2pcd

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;
    }

}

7. bin2pcd

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<PointTI>::Ptr points(new pcl::PointCloud<PointXYZI>);

    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 <Winsock2.h>
#include <windows.h>
//pcd
#include <pcl/io/pcd_io.h>
//ply
#include <pcl/io/ply_io.h>
//stl
#include <pcl/io/vtk_lib_io.h>
//mesh
#include <vtkTriangleFilter.h>
#include <pcl/common/common.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pdal/PointTable.hpp>
#include <pdal/Options.hpp>
#include <pdal/io/LasHeader.hpp>
#include <pdal/io/LasReader.hpp>
#include <string>


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<PointTI>::Ptr points(new pcl::PointCloud<PointXYZI>);

    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或强度信息,只需要在对应部分进行简单修改,在此不予赘述。
此外,如果有其他格式转换需求也可以在评论区提出来,有时间我将进行补充~

  • 10
    点赞
  • 59
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值