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

系列文章目录

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

文章目录

  • 系列文章目录
    • 事先准备 [PCL环境配置](https://blog.csdn.net/Dbojuedzw/article/details/127165662?spm=1001.2014.3001.5502)、 [PDAL环境配置](https://blog.csdn.net/Dbojuedzw/article/details/126856880?spm=1001.2014.3001.5502)
  • 前言
  • 一、本博客包含哪些格式?
  • 二、转换代码
    • 1.ply2pcd
    • 2. stl2pcd
    • 3. xyz2pcd
    • 4. obj2pcd
    • 5. asc2pcd、txt2pcd
    • 6. las、laz2pcd
    • 7. bin2pcd
    • 完整的测试代码
  • 总结


前言

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

你可能感兴趣的:(PCL点云库教程,c++,visual,studio,算法)