Point Cloud Library

软件 版本号 文件名
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 下载两个文件:

  1. PCL-1.8.1-AllInOne-msvc2017-win64.exe
  2. pcl-1.8.1-pdb-msvc2017-win64.zip

Install

  1. 双击 PCL-1.8.1-AllInOne-msvc2017-win64.exe 文件进行安装,
    建议勾选 Add PCl to the system PATH for all users.
    安装位置为 D:\PCL\. 安装时会顺带安装一些第三方库到子目录3rdParty

  2. 安装过程中会弹出一个第三方库 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, 转而通过源码自行编译, 待议!

  3. pcl-1.8.1-pdb-msvc2017-win64.zip 解压后的所有 *.pdb 文件复制到 D:\PCL\bin\ 路径下.

Configure

安装完成后需要对系统以及 VS2017 进行适当的配置才能成功使用PCL.

  1. 之前安装过程中如果勾选了 Add PCl to the system PATH for all users, 那么在系统变量中应当会有一个名为: PCL_ROOT, 值为: D:\PCL 的系统变量. 如果没有, 自行添加也可以:系统属性 -> 环境变量 -> 系统变量 -> 新建 -> ....

  2. 新建 VS2017 项目

  3. 在 VS2017 中添加用户宏: 视图 (V) -> 其他窗口 (E) -> 属性管理器 (M) -> Debug | x64 -> Microsoft.Cpp.x64.user -> 用户宏 -> 添加宏 -> 名称:PCL_3rdParty_ROOTDIR, 值:D:\PCL\3rdParty, 勾选 将此宏设置为生成环境中的环境变量.

  4. 添加头文件目录
    C/C++ -> 常规 -> 附加包含目录

1
2
3
4
5
6
7
$(PCL_ROOT)\include\pcl-1.8
$(PCL_3rdParty_ROOTDIR)\Boost\include\boost-1_64
$(PCL_3rdParty_ROOTDIR)\Eigen\eigen3
$(PCL_3rdParty_ROOTDIR)\FLANN\include
$(PCL_3rdParty_ROOTDIR)\OpenNI2\Include
$(PCL_3rdParty_ROOTDIR)\Qhull\include
$(PCL_3rdParty_ROOTDIR)\VTK\include\vtk-8.0
  1. 添加 lib 文件目录
    链接器 -> 常规 -> 附加库目录

    1
    2
    3
    4
    5
    6
    $(PCL_ROOT)\lib
    $(PCL_3rdParty_ROOTDIR)\Boost\lib
    $(PCL_3rdParty_ROOTDIR)\FLANN\lib
    $(PCL_3rdParty_ROOTDIR)\OpenNI2\Lib
    $(PCL_3rdParty_ROOTDIR)\Qhull\lib
    $(PCL_3rdParty_ROOTDIR)\VTK\lib

    Note: 这里 Eigen 没有附加库

  2. 添加 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.txt
    echo "all *.lib files for debug:"> lib_debug.txt
    echo "all *.lib files for release:"> lib_release.txt
    rem lib files of pcl
    for %%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.txt
    for %%I in (lib/*release.lib) do echo %%I>>lib_release.txt
    rem lib files of Boost
    for %%I in (3rdParty/Boost/lib/*.lib) do echo %%I>>lib_all.txt
    for %%I in (3rdParty/Boost/lib/*mt-gd-1_64.lib) do echo %%I>>lib_debug.txt
    for %%I in (3rdParty/Boost/lib/*mt-1_64.lib) do echo %%I>>lib_release.txt
    rem lib files of Qhull
    for %%I in (3rdParty/Qhull/lib/*.lib) do echo %%I>>lib_all.txt
    for %%I in (3rdParty/Qhull/lib/*_d.lib) do echo %%I>>lib_debug.txt
    for %%I in (3rdParty/Qhull/lib/*l.lib) do echo %%I>>lib_release.txt
    for %%I in (3rdParty/Qhull/lib/*p.lib) do echo %%I>>lib_release.txt
    for %%I in (3rdParty/Qhull/lib/*r.lib) do echo %%I>>lib_release.txt
    for %%I in (3rdParty/Qhull/lib/*c.lib) do echo %%I>>lib_release.txt
    rem lib files of VTK
    for %%I in (3rdParty/VTK/lib/*.lib) do echo %%I>>lib_all.txt
    for %%I in (3rdParty/VTK/lib/*-gd.lib) do echo %%I>>lib_debug.txt
    for %%I in (3rdParty/VTK/lib/*8.0.lib) do echo %%I>>lib_release.txt
    for %%I in (3rdParty/VTK/lib/*c++.lib) do echo %%I>>lib_release.txt
    rem lib files of FLANN
    for %%I in (3rdParty/FLANN/lib/*.lib) do echo %%I>>lib_all.txt
    for %%I in (3rdParty/FLANN/lib/*-gd.lib) do echo %%I>>lib_debug.txt
    for %%I in (3rdParty/FLANN/lib/*n.lib) do echo %%I>>lib_release.txt
    for %%I in (3rdParty/FLANN/lib/*p.lib) do echo %%I>>lib_release.txt
    for %%I in (3rdParty/FLANN/lib/*s.lib) do echo %%I>>lib_release.txt
    rem lib files of OPENNI2
    for %%I in (3rdParty/OpenNI2/Lib/*.lib) do echo %%I>>lib_all.txt
    for %%I in (3rdParty/OpenNI2/Lib/*.lib) do echo %%I>>lib_debug.txt
    for %%I in (3rdParty/OpenNI2/Lib/*.lib) do echo %%I>>lib_release.txt

    rem pause
  1. 添加 DLL
    将如下路径下的所有 *.dll 文件复制到新建目录 dll\ 路径下:
    1
    2
    3
    4
    5
    $(PCL_ROOT)\bin
    $(PCL_3rdParty_ROOTDIR)\Qhull\bin
    $(PCL_3rdParty_ROOTDIR)\FLANN\bin
    $(PCL_3rdParty_ROOTDIR)\VTK\bin
    $(PCL_3rdParty_ROOTDIR)\OpenNI2\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
// main.cpp
#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;
}

踩坑

  1. 错误 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-)

  1. 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);
  1. 运行 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();
// Define a translation of 0 meters on the x axis.
transform.translation() << 0.0, 0.0, 0.0;
// The same rotation matrix as before; theta radians arround Z axis
transform.rotate(Eigen::AngleAxisf(M_PI_2, Eigen::Vector3f::UnitZ()));
// Print the transformation
std::cout << transform.matrix() << std::endl;

// Executing the transformation
pcl::PointCloud<pcl::PointXYZ>::Ptr transformed_cloud(new pcl::PointCloud<pcl::PointXYZ>());
// You can either apply transform_1 or transform_2; they are the same
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
/***********************************************************************************
// 提取出最大的点云聚类
#include <pcl/kdtree/kdtree.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/extract_clusters.h>
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;
*************************************************************************************/
PointCloudT::Ptr largestClusterCloud(const PointCloudT::Ptr& cloud)
{
// 为提取点云时使用的搜素对象利用输入点云 cloud_filtered 创建 Kd 树对象 tree。
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); // 设置近邻搜索的搜索半径为 5mm
ec.setMinClusterSize(1000); // 设置一个聚类需要的最少点数目为 1000
ec.setMaxClusterSize(50000); // 设置一个聚类需要的最大点数目为 50000
ec.setSearchMethod(tree); // 设置点云的搜索机制
ec.setInputCloud(cloud); // 设置原始点云
ec.extract(cluster_indices); // 从点云中提取聚类 clusters have been sorted based on their size (largest one first)

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>
// #include <opencv2/opencv.hpp>
// #include <ctime>

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.setIndices (indices);
reg.setInputNormals(normals);
reg.setSmoothnessThreshold(6.0 / 180.0 * M_PI);
reg.setCurvatureThreshold(6.0);

std::vector <pcl::PointIndices> clusters;
reg.extract(clusters);
// Sort the clusters based on their size (largest one first)
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>
/************************************
// 调用 addText3D 时需添加该段代码,否则报错 Error:no override found for 'vtkPolyDataMapper'
// https://stackoverflow.com/questions/40086584/errorno-override-found-for-vtkpolydatamapper
#include <vtkAutoInit.h>
VTK_MODULE_INIT(vtkRenderingOpenGL);
VTK_MODULE_INIT(vtkInteractionStyle);
#pragma comment(lib,"OpenGL32.Lib")
// pcl 中 setCameraPosition 的参数说明
// https://blog.csdn.net/nicai41/article/details/98726465
// 为了在指定的视角观察点云,设置一个相机位置,其中 pos_[xyz] 表示相机位置,view_[xyz]表示相机视线方向,up_[xyz]表示相机正上方向向量
double pos_x, double pos_y, double pos_z,
double view_x, double view_y, double view_z,
double up_x, double up_y, double up_z,
****************************************/
// 显示类
pcl::visualization::PCLVisualizer CoordinateViewer("Cloud Viewer");
// 添加坐标系
CoordinateViewer.addCoordinateSystem(10, Eigen::Affine3f::Identity());// 用 Affine3f 表示
CoordinateViewer.addCoordinateSystem(10, 5, 5, 6);// 用 x,y,z 表示
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;
}

作者

Luo Siyou

发布于

2023-01-03

更新于

2023-01-09

许可协议