软件
版本号
文件名
os
windows10-x64
-
Visual Studio
VS2017
-
PCL
PCL-1.8.1
PCL-1.8.1-AllInOne-msvc2017-win64.exe; pcl-1.8.1-pdb-msvc2017-win64.zip
Download 从官方 github 仓库 Point Cloud Library - Github Release 下载两个文件:
PCL-1.8.1-AllInOne-msvc2017-win64.exe
pcl-1.8.1-pdb-msvc2017-win64.zip
Install
双击 PCL-1.8.1-AllInOne-msvc2017-win64.exe
文件进行安装, 建议勾选 Add PCl to the system PATH for all users
. 安装位置为 D:\PCL\
. 安装时会顺带安装一些第三方库到子目录3rdParty
下
安装过程中会弹出一个第三方库 OpenNI2
的安装: OpenNI 2.2 SDK for Windows 64-bit Setup
,建议设置路径到子目录 3rdParty
下. 最终在 D:\PCL\3rdParty\
路径下有: Boost,Eigen,FLANN,OpenNI2,Qhull,VTK
共 6 个第三方库. 其中 VTK
库是”万恶之源”, 会导致后续许多 bug. 网上有的帖子建议删除 PCL 自带的 VTK, 转而通过源码自行编译, 待议!
将 pcl-1.8.1-pdb-msvc2017-win64.zip
解压后的所有 *.pdb
文件复制到 D:\PCL\bin\
路径下.
安装完成后需要对系统以及 VS2017
进行适当的配置才能成功使用PCL
.
之前安装过程中如果勾选了 Add PCl to the system PATH for all users
, 那么在系统变量中应当会有一个名为: PCL_ROOT
, 值为: D:\PCL
的系统变量. 如果没有, 自行添加也可以:系统属性
-> 环境变量
-> 系统变量
-> 新建
-> ...
.
新建 VS2017 项目
在 VS2017 中添加用户宏: 视图 (V)
-> 其他窗口 (E)
-> 属性管理器 (M)
-> Debug | x64
-> Microsoft.Cpp.x64.user
-> 用户宏
-> 添加宏
-> 名称:PCL_3rdParty_ROOTDIR
, 值:D:\PCL\3rdParty
, 勾选 将此宏设置为生成环境中的环境变量
.
添加头文件目录 C/C++
-> 常规
-> 附加包含目录
1 2 3 4 5 6 7 $(PCL_ROOT)\i nclude\pcl-1.8$(PCL_3rdParty_ROOTDIR)\B oost\include \boost-1_64$(PCL_3rdParty_ROOTDIR)\E igen\eigen3$(PCL_3rdParty_ROOTDIR)\F LANN\include $(PCL_3rdParty_ROOTDIR)\O penNI2\Include$(PCL_3rdParty_ROOTDIR)\Q hull\include $(PCL_3rdParty_ROOTDIR)\V TK\include \vtk-8.0
添加 lib 文件目录 链接器
-> 常规
-> 附加库目录
1 2 3 4 5 6 $(PCL_ROOT)\l ib$(PCL_3rdParty_ROOTDIR)\B oost\lib$(PCL_3rdParty_ROOTDIR)\F LANN\lib$(PCL_3rdParty_ROOTDIR)\O penNI2\Lib$(PCL_3rdParty_ROOTDIR)\Q hull\lib$(PCL_3rdParty_ROOTDIR)\V TK\lib
Note : 这里 Eigen 没有附加库
添加 lib 文件名 链接器
-> 输入
-> 附加依赖项
需要添加的 *.lib
文件名太多了, 这里参考 VS 中 PCL 库附加依赖项配置 - 博客园 通过批处理程序来完成.
在 D:\PCL
下新建一个批处理文件echo.bat
, 双击运行该文件, 将所有 lib 文件名分为 debug 和 release 两类, 并写入两个文本文件内. 对于不同版本的软件,也许文件名会不同, 需要仔细核实匹配字符串与对应路径下的文件是否匹配.
echo.bat 文件如下 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 @echo off echo "all *.lib files:"> lib_all.txtecho "all *.lib files for debug:"> lib_debug.txtecho "all *.lib files for release:"> lib_release.txtfor %%I in (lib/*.lib) do echo %%I >>lib_all.txt % 解释:对每一个(*.lib) 通配符匹配到的文件名 I,显示 I 到文件 all.txt,之后的语句类似理解就可 % for %%I in (lib/*debug.lib) do echo %%I >>lib_debug.txtfor %%I in (lib/*release.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/Boost/lib/*.lib) do echo %%I >>lib_all.txtfor %%I in (3 rdParty/Boost/lib/*mt-gd-1 _64.lib) do echo %%I >>lib_debug.txtfor %%I in (3 rdParty/Boost/lib/*mt-1 _64.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/Qhull/lib/*.lib) do echo %%I >>lib_all.txtfor %%I in (3 rdParty/Qhull/lib/*_d.lib) do echo %%I >>lib_debug.txtfor %%I in (3 rdParty/Qhull/lib/*l.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/Qhull/lib/*p.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/Qhull/lib/*r.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/Qhull/lib/*c.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/VTK/lib/*.lib) do echo %%I >>lib_all.txtfor %%I in (3 rdParty/VTK/lib/*-gd.lib) do echo %%I >>lib_debug.txtfor %%I in (3 rdParty/VTK/lib/*8 .0 .lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/VTK/lib/*c++.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/FLANN/lib/*.lib) do echo %%I >>lib_all.txtfor %%I in (3 rdParty/FLANN/lib/*-gd.lib) do echo %%I >>lib_debug.txtfor %%I in (3 rdParty/FLANN/lib/*n.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/FLANN/lib/*p.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/FLANN/lib/*s.lib) do echo %%I >>lib_release.txtfor %%I in (3 rdParty/OpenNI2/Lib/*.lib) do echo %%I >>lib_all.txtfor %%I in (3 rdParty/OpenNI2/Lib/*.lib) do echo %%I >>lib_debug.txtfor %%I in (3 rdParty/OpenNI2/Lib/*.lib) do echo %%I >>lib_release.txt
添加 DLL 将如下路径下的所有 *.dll
文件复制到新建目录 dll\
路径下:1 2 3 4 5 $(PCL_ROOT)\b in$(PCL_3rdParty_ROOTDIR)\Q hull\bin$(PCL_3rdParty_ROOTDIR)\F LANN\bin$(PCL_3rdParty_ROOTDIR)\V TK\bin$(PCL_3rdParty_ROOTDIR)\O penNI2\Tools
并将该路径添加到 VS2017
的项目环境下. 在 解决方案资源管理器
右击项目名 ->属性
-> 调试
-> 环境
->PATH=.\dll;%PATH%
.
或者参考 pcl1.8.0+vs2013 环境配置(详细)- CSDN 将以下路径添加到系统路径中,系统属性
-> 环境变量
-> 系统变量
-> Path
-> 编辑
-> 添加
1 2 3 4 5 ;%PCL_ROOT%\bin ;%PCL_ROOT%\3rdParty\Qhull\bin ;%PCL_ROOT%\3rdParty\FLANN\bin ;%PCL_ROOT%\3rdParty\VTK\bin ;%PCL_ROOT%\3rdParty\OpenNI2\Tools
属性配置好以后,可以右键属性表,将其保存,以后用的时候直接”添加现有属性表”就可以,不用每次使用 PCL 都重新配置了
Test 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 #include <iostream> #include <pcl/common/common_headers.h> #include <pcl/io/pcd_io.h> #include <pcl/visualization/pcl_visualizer.h> #include <pcl/visualization/cloud_viewer.h> #include <pcl/console/parse.h> int main (int argc, char **argv) { std::cout << "Test PCL !!!" << std::endl; pcl::PointCloud<pcl::PointXYZRGB>::Ptr point_cloud_ptr (new pcl::PointCloud<pcl::PointXYZRGB>) ; uint8_t r (255 ) , g (15 ) , b (15 ) ; for (float z (-1.0 ); z <= 1.0 ; z += 0.05 ) { for (float angle (0.0 ); angle <= 360.0 ; angle += 5.0 ) { pcl::PointXYZRGB point; point.x = 0.5 * cosf (pcl::deg2rad (angle)); point.y = sinf (pcl::deg2rad (angle)); point.z = z; uint32_t rgb = (static_cast <uint32_t >(r) << 16 | static_cast <uint32_t >(g) << 8 | static_cast <uint32_t >(b)); point.rgb = *reinterpret_cast <float *>(&rgb); point_cloud_ptr->points.push_back (point); } if (z < 0.0 ) { r -= 12 ; g += 12 ; } else { g -= 12 ; b += 12 ; } } point_cloud_ptr->width = (int )point_cloud_ptr->points.size (); point_cloud_ptr->height = 1 ; pcl::visualization::CloudViewer viewer ("test" ) ; viewer.showCloud (point_cloud_ptr); while (!viewer.wasStopped ()) {}; return 0 ; }
踩坑
错误 C4996
严重性 代码 说明 项目 文件 行 禁止显示状态 错误 C4996 ‘std::fpos<_Mbstatet>::seekpos’: warning STL4019: The member std::fpos::seekpos() is non-Standard, and is preserved only for compatibility with workarounds for old versions of Visual C++. It will be removed in a future release, and in this release always returns 0. Please use standards-conforming mechanisms to manipulate fpos, such as conversions to and from streamoff, or an integral type, instead. If you are receiving this message while compiling Boost.IOStreams, a fix has been submitted upstream to make Boost use standards-conforming mechanisms, as it does for other compilers. You can define _SILENCE_FPOS_SEEKPOS_DEPRECATION_WARNING to acknowledge that you have received this warning, or define _REMOVE_FPOS_SEEKPOS to remove std::fpos::seekpos entirely. demo_Proj d:\pcl\3rdparty\boost\include\boost-1_64\boost\iostreams\positioning.hpp 96
解决办法: 属性
-> 配置属性
-> C/C++
-> 高级
-> 禁用特定警告
-> 4996;
. 也可以关闭 SDL 检查
来解决这一问题: 属性
-> 配置属性
-> C/C++
-> 常规
-> SDL 检查
: 否(/sdl-)
no override found for ‘vtkPolyDataMapper’
参考:https://github.com/PointCloudLibrary/pcl/issues/1797
将 $(PCL_3rdParty_ROOTDIR)\OpenNI2\Samples\SimpleViewer\
添加到 附加包含目录
, 该路径下有头文件GL/glut.h
需要在源文件中包含; 该路径下的 glut32.lib
需要链接到 附加库
; 对应的glut32.dll
文件复制到相应的位置. 在主程序最开始的地方添加如下代码段:
1 2 3 4 #include <GL/glut.h> #include <vtkAutoInit.h> VTK_MODULE_INIT (vtkRenderingOpenGL);VTK_MODULE_INIT (vtkInteractionStyle);
运行 PCL 代码出现 C2988,C2143,C2913 等错误的解决方法
PCL 点云格式转换 ply 文件可以用 windows 自带的 3d 查看器打开,pcd 文件可以用 CloudViewer 打开
这是目标工件生产时参考的标准 ply 模型文件, 通过 pcl 工具转换为 pcd 文件
1 2 3 4 5 6 7 8 9 10 11 12 13 .\pcl_mesh_sampling_release.exe ..\model.ply ..\model.pcd Convert a CAD model to a point cloud using uniform sampling. For more information, use: D:\PCL\bin\pcl_mesh_sampling_release.exe -h Syntax is: D:\PCL\bin\pcl_mesh_sampling_release.exe input.{ply,obj} output.pcd <options> where options are: -n_samples X = number of samples (default: 100000 ) -leaf_size X = the XYZ leaf size for the VoxelGrid -- for data reduction (default: 0.010000 m) -write_normals = flag to write normals to the output pcd -no_vis_result = flag to stop visualizing the generated pcd (base) PS D:\PCL\bin> .\pcl_mesh_sampling_release.exe ..\model.ply ..\model.pcd -leaf_size 0.001
补充说明 : 我一开始在命令行中运行pcl_mesh_sampling_release.exe
时,命令行直接毫无显示,也没报错。 双击该可执行文件时弹窗说找不到 OpenNI2.dll,于是把该文件拷贝到 pcl_mesh_sampling_release.exe
同一路径下,就可以在命令行中执行转换了。
参考
Reference
代码段示例 统计滤波: 去除离群点 1 2 3 4 5 6 7 8 9 #include <pcl/filters/statistical_outlier_removal.h> pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>) ; pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>) ; pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor; sor.setInputCloud (cloud); sor.setMeanK (50 ); sor.setStddevMulThresh (1.0 ); sor.filter (*cloud_filtered);
体素滤波: 降采样 1 2 3 4 5 6 7 8 9 10 11 12 #include <pcl/filters/voxel_grid.h> pcl::PointCloud<pcl::PointXYZ>::Ptr downsample (pcl::PointCloud<pcl::PointXYZ>::Ptr cloud) { pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filter (new pcl::PointCloud<pcl::PointXYZ>) ; pcl::VoxelGrid<pcl::PointXYZ> voxel_filter; voxel_filter.setInputCloud (cloud); float leafsz = 0.3f ; voxel_filter.setLeafSize (leafsz, leafsz, leafsz); voxel_filter.filter (*cloud_filter); return cloud_filter; }
可视化 1 2 3 4 5 6 visualization::PCLVisualizer viewer ("PPF Object Recognition - Results" ) ;viewer.setBackgroundColor (0 , 0 , 0 ); viewer.addPointCloud (cloud_scene); viewer.spinOnce (10 ); visualization::PointCloudColorHandlerRandom<PointXYZ> random_color (cloud_output->makeShared()) ;viewer.addPointCloud (cloud_output, random_color, mode_name);
平移旋转 1 2 3 4 5 6 7 8 9 10 11 12 Eigen::Affine3f transform = Eigen::Affine3f::Identity (); transform.translation () << 0.0 , 0.0 , 0.0 ; transform.rotate (Eigen::AngleAxisf (M_PI_2, Eigen::Vector3f::UnitZ ())); std::cout << transform.matrix () << std::endl; pcl::PointCloud<pcl::PointXYZ>::Ptr transformed_cloud (new pcl::PointCloud<pcl::PointXYZ>()) ; pcl::transformPointCloud (*cloud, *transformed_cloud, transform);
聚类 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 PointCloudT::Ptr largestClusterCloud (const PointCloudT::Ptr& cloud) { pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT>) ; tree->setInputCloud (cloud); std::vector<pcl::PointIndices> cluster_indices; pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec; ec.setClusterTolerance (5 ); ec.setMinClusterSize (1000 ); ec.setMaxClusterSize (50000 ); ec.setSearchMethod (tree); ec.setInputCloud (cloud); ec.extract (cluster_indices); if (cluster_indices.size () == 0 ) { return cloud; } PointCloudT::Ptr cloud_max_cluster (new PointCloudT) ; pcl::copyPointCloud (*cloud, cluster_indices[0 ], *cloud_max_cluster); return cloud_max_cluster; }
区域生长分割 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/filters/statistical_outlier_removal.h> #include <pcl/filters/voxel_grid.h> #include <pcl/kdtree/kdtree.h> #include <pcl/filters/extract_indices.h> #include <pcl/segmentation/extract_clusters.h> #include <pcl/segmentation/region_growing.h> #include <pcl/search/search.h> #include <pcl/search/kdtree.h> #include <pcl/features/normal_3d.h> #include <pcl/visualization/cloud_viewer.h> typedef pcl::PointCloud<pcl::PointXYZ> PointCloudT;std::vector<pcl::PointIndices> region_growing_segmentation (const PointCloudT::Ptr& cloud,bool viewflag) {pcl::search::Search<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>) ; pcl::PointCloud <pcl::Normal>::Ptr normals (new pcl::PointCloud <pcl::Normal>) ; pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> normal_estimator; normal_estimator.setSearchMethod (tree); normal_estimator.setInputCloud (cloud); normal_estimator.setKSearch (50 ); normal_estimator.compute (*normals); pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg; reg.setMinClusterSize (5000 ); reg.setMaxClusterSize (50000 ); reg.setSearchMethod (tree); reg.setNumberOfNeighbours (30 ); reg.setInputCloud (cloud); reg.setInputNormals (normals); reg.setSmoothnessThreshold (6.0 / 180.0 * M_PI); reg.setCurvatureThreshold (6.0 ); std::vector <pcl::PointIndices> clusters; reg.extract (clusters); std::sort (clusters.rbegin (), clusters.rend (), [](pcl::PointIndices a, pcl::PointIndices b){return a.indices.size ()>b.indices.size ();}); if (viewflag){ pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud (); pcl::visualization::CloudViewer viewer ("Cluster viewer" ) ; viewer.showCloud (colored_cloud); while (!viewer.wasStopped ()) { } } return clusters;}
显示多个坐标系 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 #include <pcl/visualization/pcl_visualizer.h> pcl::visualization::PCLVisualizer CoordinateViewer ("Cloud Viewer" ) ; CoordinateViewer.addCoordinateSystem (10 , Eigen::Affine3f::Identity ()); CoordinateViewer.addCoordinateSystem (10 , 5 , 5 , 6 ); CoordinateViewer.addText3D ("coor 1" , pcl::PointXYZ (5 ,5 ,6 ), 2 , 1 , 0 , 0 , "text1" ); CoordinateViewer.addCoordinateSystem (10 , 4 , 4 , 4 ); CoordinateViewer.addPointCloud (point_cloud_ptr); CoordinateViewer.setCameraPosition (10 , -10 , 3 , -10 ,10 ,-3 , 0.1 , -0.1 , 1 ); while (!CoordinateViewer.wasStopped ()) { CoordinateViewer.spinOnce (); };
生成简单几何体 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 typedef pcl::PointXYZ PointT;typedef pcl::PointCloud<PointT> PointCloudT;PointCloudT::Ptr ConsCylinderCloud (float radius, float height, float d_degree = 0.5 ,float d_height = 0.05 ,float d_radius=0.5 ) { PointCloudT::Ptr cloud (new PointCloudT) ; for (float x = 0 ; x <= height; x += d_height) { for (float angle = 0.0 ; angle <= 360.0 ; angle += d_degree) { PointT point; point.x = x; point.y = radius * sinf (pcl::deg2rad (angle)); point.z = radius * cosf (pcl::deg2rad (angle)); cloud->points.push_back (point); } } for (float r = 0 ; r <= radius; r += d_radius) { for (float angle = 0.0 ; angle <= 360.0 ; angle += d_degree) { PointT point; point.x = 0 ; point.y = r * sinf (pcl::deg2rad (angle)); point.z = r * cosf (pcl::deg2rad (angle)); cloud->points.push_back (point); } } for (float r = 0 ; r <= radius; r += d_radius) { for (float angle = 0.0 ; angle <= 360.0 ; angle += d_degree) { PointT point; point.x = height; point.y = r * sinf (pcl::deg2rad (angle)); point.z = r * cosf (pcl::deg2rad (angle)); cloud->points.push_back (point); } } cloud->width = (int )cloud->points.size (); cloud->height = 1 ; return cloud; } PointCloudT::Ptr ConsCubeCloud (float x_length, float y_width, float z_height, float dx = 0.05 , float dy = 0.05 , float dz = 0.05 ) { float length_2 = x_length / 2 ; float width_2 = y_width / 2 ; float height_2 = z_height / 2 ; PointCloudT::Ptr cloud (new PointCloudT) ; for (float x = -length_2; x <= length_2; x += dx) { for (float y = -width_2; y <= width_2; y += dy) { PointT point_1; point_1.x = x; point_1.y = y; point_1.z = -height_2; PointT point_2; point_2.x = x; point_2.y = y; point_2.z = height_2; cloud->points.push_back (point_1); cloud->points.push_back (point_2); } for (float z = -height_2; z <= height_2; z += dz) { PointT point_1; point_1.x = x; point_1.y = -width_2; point_1.z = z; PointT point_2; point_2.x = x; point_2.y = width_2; point_2.z = z; cloud->points.push_back (point_1); cloud->points.push_back (point_2); } } for (float y = -width_2; y <= width_2; y += dy) { for (float z = -height_2; z <= height_2; z += dz) { PointT point_1; point_1.x = -length_2; point_1.y = y; point_1.z = z; PointT point_2; point_2.x = length_2; point_2.y = y; point_2.z = z; cloud->points.push_back (point_1); cloud->points.push_back (point_2); } } cloud->width = (int )cloud->points.size (); cloud->height = 1 ; return cloud; } PointCloudT::Ptr ConsSphereCloud (float radius, float d_theta=5.0 , float d_phi=5.0 ) { PointCloudT::Ptr cloud (new PointCloudT) ; for (float theta = 0.0 ; theta <= 180.0 ; theta += d_theta) { for (float phi = 0.0 ; phi <= 360.0 ; phi += d_phi) { PointT point; point.x = radius * sinf (pcl::deg2rad (theta)) * cosf (pcl::deg2rad (phi)); point.y = radius * sinf (pcl::deg2rad (theta)) * sinf (pcl::deg2rad (phi)); point.z = radius * cosf (pcl::deg2rad (theta)); cloud->points.push_back (point); } } cloud->width = (int )cloud->points.size (); cloud->height = 1 ; return cloud; }