一、安装

1.1 下载PCL

首先我们需要下载pcl1.11.0 ,这个版本与vs2019对应。
有两种下载方法:百度网盘、官网下载。二选一即可~


下载方法1:百度网盘
链接:https://pan.baidu.com/s/1tQEzhvY4HYw1OJw6W-0fOQ
提取码:qi8w


下载方法2:官网下载

1.2 安装PCL

  • 双击“PCL-1.9.0-AllInOne-msvc2017-win64.exe”进行安装
               选择“Add PCL to the system PATH for all users”,自动把路径添加到系统环境变量中。
    在这里插入图片描述
    默认是C:\Program Files\PCL 1.11.0 ,也可以改到其他的路径,但是需要记住安装的根路径,方便后续对环境进行配置。

如果安装的过程中提示 path too long installer unable to modify path, 不要慌,说明只是环境变量没有自动配置好,接下来我们手动配置即可。


  • 解压“pcl-1.11.0-pdb-msvc2019-win64.zip”,将解压得到的文件夹中的内容添加“C:\Program Files\\PCL 1.11.0\bin”中。

 

检测路径C:\Program Files\PCL 1.11.0\3rdParty\OpenNI2下是否安装了OpenNI2:

  • 如果文件夹中只有下图红框标注的.msi文件,则说明未安装OpenNI2,则需要点击该.msi文件进行手动安装。
    否则跳过这一步就可以啦。
    点击该.msi文件进行手动安装,注意安装的路径选择C:\Program Files\PCL 1.11.0\3rdParty\OpenNI2

1.3 安装OSGeo4W

  • OSGeo4W下载地址
  • 安装OSGeo4W
            选择默认的安装路径(也可以自定义路径,但需要记住安装的根路径,方便后续添加环境变量)
                 选择https://ftp.osuosl.org
     搜索框输入pdal,点击skip,选中图中版本。
    开始安装各种依赖
    安装完成后,如下图

二、配置

2.1 配置环境变量

  • 搜索 查看高级系统设置
  • 点击环境变量
  • 查看系统变量,已经有自动设置好的PCL_ROOT
  • 双击Path 新建如下环境变量
%PCL_ROOT%\bin
%PCL_ROOT%\3rdParty\FLANN\bin
%PCL_ROOT%\3rdParty\VTK\bin
%PCL_ROOT%\3rdParty\Qhull\bin
%PCL_ROOT%\3rdParty\OpenNI2\Tools
%PCL_ROOT%\3rdParty\OpenNI2\Redist
C:\OSGeo4W\bin

  • 点击确定,重启电脑后生效

2.2 配置VS2019

  • 打开VS2019,创建一个名为testPCL的空项目
  • 编译环境改为X64,Release版本。
  • 视图-其他窗口-属性管理器
  • Release|x64 - 添加新项目属性表
  • 给属性表命名
  • 双击新建的属性表
  • VC++ 目录
  • VC++ 目录 - 包含目录/库目录 - 下三角 -<编辑..>

包含目录中添加以下7个目录:(注意版本和路径以及名称,建议点击右上角黄色的图标手动添加)

C:\Program Files\PCL 1.11.0\3rdParty\VTK\include\vtk-8.2
C:\Program Files\PCL 1.11.0\3rdParty\OpenNI2\Include
C:\Program Files\PCL 1.11.0\3rdParty\Qhull\include
C:\Program Files\PCL 1.11.0\3rdParty\FLANN\include
C:\Program Files\PCL 1.11.0\3rdParty\Eigen\eigen3
C:\Program Files\PCL 1.11.0\3rdParty\Boost\include\boost-1_73
C:\Program Files\PCL 1.11.0\include\pcl-1.11

库目录 中添加以下7个目录:

C:\Program Files\PCL 1.11.0\3rdParty\OpenNI2\Lib
C:\OSGeo4W\lib
C:\Program Files\PCL 1.11.0\3rdParty\VTK\lib
C:\Program Files\PCL 1.11.0\3rdParty\Qhull\lib
C:\Program Files\PCL 1.11.0\3rdParty\FLANN\lib
C:\Program Files\PCL 1.11.0\3rdParty\Boost\lib
C:\Program Files\PCL 1.11.0\lib


C/C++—>预处理器—>预处理器定义

  • 点击预处理定义
  • 添加如下内容
BOOST_USE_WINDOWS_H
NOMINMAX
_CRT_SECURE_NO_DEPRECATE


C/C++ ->所有选项->SDL检查

  • 属性页中将SDL检查设为
  • 项目也中将SDL检查设为

  • 链接器—>输入—>附加的依赖项
  • PCL 1.11.0\3rdParty\VTK\libPCL 1.11.0\lib以及C:\OSGeo4W\lib这三个文件夹下的lib文件的release版本添加到附加依赖项中
       
pcl_common.lib
pcl_features.lib
pcl_filters.lib
pcl_io.lib
pcl_io_ply.lib
pcl_kdtree.lib
pcl_keypoints.lib
pcl_ml.lib
pcl_octree.lib
pcl_outofcore.lib
pcl_people.lib
pcl_recognition.lib
pcl_registration.lib
pcl_sample_consensus.lib
pcl_search.lib
pcl_segmentation.lib
pcl_stereo.lib
pcl_surface.lib
pcl_tracking.lib
pcl_visualization.lib
vtkChartsCore-8.2.lib
vtkCommonColor-8.2.lib
vtkCommonComputationalGeometry-8.2.lib
vtkCommonCore-8.2.lib
vtkCommonDataModel-8.2.lib
vtkCommonExecutionModel-8.2.lib
vtkCommonMath-8.2.lib
vtkCommonMisc-8.2.lib
vtkCommonSystem-8.2.lib
vtkCommonTransforms-8.2.lib
vtkDICOMParser-8.2.lib
vtkDomainsChemistry-8.2.lib
vtkDomainsChemistryOpenGL2-8.2.lib
vtkdoubleconversion-8.2.lib
vtkexodusII-8.2.lib
vtkexpat-8.2.lib
vtkFiltersAMR-8.2.lib
vtkFiltersCore-8.2.lib
vtkFiltersExtraction-8.2.lib
vtkFiltersFlowPaths-8.2.lib
vtkFiltersGeneral-8.2.lib
vtkFiltersGeneric-8.2.lib
vtkFiltersGeometry-8.2.lib
vtkFiltersHybrid-8.2.lib
vtkFiltersHyperTree-8.2.lib
vtkFiltersImaging-8.2.lib
vtkFiltersModeling-8.2.lib
vtkFiltersParallel-8.2.lib
vtkFiltersParallelImaging-8.2.lib
vtkFiltersPoints-8.2.lib
vtkFiltersProgrammable-8.2.lib
vtkFiltersSelection-8.2.lib
vtkFiltersSMP-8.2.lib
vtkFiltersSources-8.2.lib
vtkFiltersStatistics-8.2.lib
vtkFiltersTexture-8.2.lib
vtkFiltersTopology-8.2.lib
vtkFiltersVerdict-8.2.lib
vtkfreetype-8.2.lib
vtkGeovisCore-8.2.lib
vtkgl2ps-8.2.lib
vtkglew-8.2.lib
vtkGUISupportMFC-8.2.lib
vtkhdf5-8.2.lib
vtkhdf5_hl-8.2.lib
vtkImagingColor-8.2.lib
vtkImagingCore-8.2.lib
vtkImagingFourier-8.2.lib
vtkImagingGeneral-8.2.lib
vtkImagingHybrid-8.2.lib
vtkImagingMath-8.2.lib
vtkImagingMorphological-8.2.lib
vtkImagingSources-8.2.lib
vtkImagingStatistics-8.2.lib
vtkImagingStencil-8.2.lib
vtkInfovisCore-8.2.lib
vtkInfovisLayout-8.2.lib
vtkInteractionImage-8.2.lib
vtkInteractionStyle-8.2.lib
vtkInteractionWidgets-8.2.lib
vtkIOAMR-8.2.lib
vtkIOAsynchronous-8.2.lib
vtkIOCityGML-8.2.lib
vtkIOCore-8.2.lib
vtkIOEnSight-8.2.lib
vtkIOExodus-8.2.lib
vtkIOExport-8.2.lib
vtkIOExportOpenGL2-8.2.lib
vtkIOExportPDF-8.2.lib
vtkIOGeometry-8.2.lib
vtkIOImage-8.2.lib
vtkIOImport-8.2.lib
vtkIOInfovis-8.2.lib
vtkIOLegacy-8.2.lib
vtkIOLSDyna-8.2.lib
vtkIOMINC-8.2.lib
vtkIOMovie-8.2.lib
vtkIONetCDF-8.2.lib
vtkIOParallel-8.2.lib
vtkIOParallelXML-8.2.lib
vtkIOPLY-8.2.lib
vtkIOSegY-8.2.lib
vtkIOSQL-8.2.lib
vtkIOTecplotTable-8.2.lib
vtkIOVeraOut-8.2.lib
vtkIOVideo-8.2.lib
vtkIOXML-8.2.lib
vtkIOXMLParser-8.2.lib
vtkjpeg-8.2.lib
vtkjsoncpp-8.2.lib
vtklibharu-8.2.lib
vtklibxml2-8.2.lib
vtklz4-8.2.lib
vtklzma-8.2.lib
vtkmetaio-8.2.lib
vtkNetCDF-8.2.lib
vtkogg-8.2.lib
vtkParallelCore-8.2.lib
vtkpng-8.2.lib
vtkproj-8.2.lib
vtkpugixml-8.2.lib
vtkRenderingAnnotation-8.2.lib
vtkRenderingContext2D-8.2.lib
vtkRenderingContextOpenGL2-8.2.lib
vtkRenderingCore-8.2.lib
vtkRenderingExternal-8.2.lib
vtkRenderingFreeType-8.2.lib
vtkRenderingGL2PSOpenGL2-8.2.lib
vtkRenderingImage-8.2.lib
vtkRenderingLabel-8.2.lib
vtkRenderingLOD-8.2.lib
vtkRenderingOpenGL2-8.2.lib
vtkRenderingVolume-8.2.lib
vtkRenderingVolumeOpenGL2-8.2.lib
vtksqlite-8.2.lib
vtksys-8.2.lib
vtktheora-8.2.lib
vtktiff-8.2.lib
vtkverdict-8.2.lib
vtkViewsContext2D-8.2.lib
vtkViewsCore-8.2.lib
vtkViewsInfovis-8.2.lib
vtkzlib-8.2.lib
pdalcpp.lib
pdal_util.lib
libpdal_plugin_writer_pgpointcloud.lib
libpdal_plugin_reader_pgpointcloud.lib
libpdal_plugin_kernel_fauxplugin.lib
liblas_c.lib
liblas.lib
laszip3.lib

三、点云格式转换以及可视化

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

//#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:\\dataset\\PCL\\kitti_000008_points.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();
}

obj pcd文件为例
运行效果如下:


在终端按下H 出现操作指南。

参考

win10+vs2019+pcl1.11.0安装教程_a_zhua66的博客-CSDN博客_vs pcl1.11

配置PCL过程中提示 path too long installer unable to modify path解决_Quelquefois的博客-CSDN博客_pcl path too long

https://github.com/PointCloudLibrary/pcl/releases/tag/pcl-1.11.0

PCL 各种三维格式转PCD文件(ply、stl、xyz、obj、asc、txt、las、laz、bin)_stay hungry foolish的博客-CSDN博客_pcd格式转换

最具体和最简单的PDAL库配置及在VS2019上测试_stay hungry foolish的博客-CSDN博客_osgeo4w安装liblas