• 圆柱模型分割


    本教程举例说明了如何为圆柱模型运行样本共识分割。为了使示例更实用,对输入数据集进行以下操作(按顺序):

    • 超过 1.5 米的数据点被过滤

    • 估计每个点的表面法线

    • 平面模型(描述我们演示数据集中的表)被分割并保存到磁盘

    • 一个圆柱形模型(描述我们演示数据集中的杯子)被分割并保存到磁盘

    下载数据集 https://raw.github.com/PointCloudLibrary/data/master/tutorials/table_scene_mug_stereo_textured.pcd

    创建cylinder_segmentation.cpp文件

    源码:

    1. 1#include <pcl/ModelCoefficients.h>
    2. 2#include <pcl/io/pcd_io.h>
    3. 3#include <pcl/point_types.h>
    4. 4#include <pcl/filters/extract_indices.h>
    5. 5#include <pcl/filters/passthrough.h>
    6. 6#include <pcl/features/normal_3d.h>
    7. 7#include <pcl/sample_consensus/method_types.h>
    8. 8#include <pcl/sample_consensus/model_types.h>
    9. 9#include <pcl/segmentation/sac_segmentation.h>
    10. 10
    11. 11typedef pcl::PointXYZ PointT;
    12. 12
    13. 13int
    14. 14main ()
    15. 15{
    16. 16 // All the objects needed
    17. 17 pcl::PCDReader reader;
    18. 18 pcl::PassThrough<PointT> pass;
    19. 19 pcl::NormalEstimation<PointT, pcl::Normal> ne;
    20. 20 pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;
    21. 21 pcl::PCDWriter writer;
    22. 22 pcl::ExtractIndices<PointT> extract;
    23. 23 pcl::ExtractIndices<pcl::Normal> extract_normals;
    24. 24 pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT> ());
    25. 25
    26. 26 // Datasets
    27. 27 pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
    28. 28 pcl::PointCloud<PointT>::Ptr cloud_filtered (new pcl::PointCloud<PointT>);
    29. 29 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
    30. 30 pcl::PointCloud<PointT>::Ptr cloud_filtered2 (new pcl::PointCloud<PointT>);
    31. 31 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals2 (new pcl::PointCloud<pcl::Normal>);
    32. 32 pcl::ModelCoefficients::Ptr coefficients_plane (new pcl::ModelCoefficients), coefficients_cylinder (new pcl::ModelCoefficients);
    33. 33 pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices), inliers_cylinder (new pcl::PointIndices);
    34. 34
    35. 35 // Read in the cloud data
    36. 36 reader.read ("table_scene_mug_stereo_textured.pcd", *cloud);
    37. 37 std::cerr << "PointCloud has: " << cloud->size () << " data points." << std::endl;
    38. 38
    39. 39 // Build a passthrough filter to remove spurious NaNs and scene background
    40. 40 pass.setInputCloud (cloud);
    41. 41 pass.setFilterFieldName ("z");
    42. 42 pass.setFilterLimits (0, 1.5);
    43. 43 pass.filter (*cloud_filtered);
    44. 44 std::cerr << "PointCloud after filtering has: " << cloud_filtered->size () << " data points." << std::endl;
    45. 45
    46. 46 // Estimate point normals
    47. 47 ne.setSearchMethod (tree);
    48. 48 ne.setInputCloud (cloud_filtered);
    49. 49 ne.setKSearch (50);
    50. 50 ne.compute (*cloud_normals);
    51. 51
    52. 52 // Create the segmentation object for the planar model and set all the parameters
    53. 53 seg.setOptimizeCoefficients (true);
    54. 54 seg.setModelType (pcl::SACMODEL_NORMAL_PLANE);
    55. 55 seg.setNormalDistanceWeight (0.1);
    56. 56 seg.setMethodType (pcl::SAC_RANSAC);
    57. 57 seg.setMaxIterations (100);
    58. 58 seg.setDistanceThreshold (0.03);
    59. 59 seg.setInputCloud (cloud_filtered);
    60. 60 seg.setInputNormals (cloud_normals);
    61. 61 // Obtain the plane inliers and coefficients
    62. 62 seg.segment (*inliers_plane, *coefficients_plane);
    63. 63 std::cerr << "Plane coefficients: " << *coefficients_plane << std::endl;
    64. 64
    65. 65 // Extract the planar inliers from the input cloud
    66. 66 extract.setInputCloud (cloud_filtered);
    67. 67 extract.setIndices (inliers_plane);
    68. 68 extract.setNegative (false);
    69. 69
    70. 70 // Write the planar inliers to disk
    71. 71 pcl::PointCloud<PointT>::Ptr cloud_plane (new pcl::PointCloud<PointT> ());
    72. 72 extract.filter (*cloud_plane);
    73. 73 std::cerr << "PointCloud representing the planar component: " << cloud_plane->size () << " data points." << std::endl;
    74. 74 writer.write ("table_scene_mug_stereo_textured_plane.pcd", *cloud_plane, false);
    75. 75
    76. 76 // Remove the planar inliers, extract the rest
    77. 77 extract.setNegative (true);
    78. 78 extract.filter (*cloud_filtered2);
    79. 79 extract_normals.setNegative (true);
    80. 80 extract_normals.setInputCloud (cloud_normals);
    81. 81 extract_normals.setIndices (inliers_plane);
    82. 82 extract_normals.filter (*cloud_normals2);
    83. 83
    84. 84 // Create the segmentation object for cylinder segmentation and set all the parameters
    85. 85 seg.setOptimizeCoefficients (true);
    86. 86 seg.setModelType (pcl::SACMODEL_CYLINDER);
    87. 87 seg.setMethodType (pcl::SAC_RANSAC);
    88. 88 seg.setNormalDistanceWeight (0.1);
    89. 89 seg.setMaxIterations (10000);
    90. 90 seg.setDistanceThreshold (0.05);
    91. 91 seg.setRadiusLimits (0, 0.1);
    92. 92 seg.setInputCloud (cloud_filtered2);
    93. 93 seg.setInputNormals (cloud_normals2);
    94. 94
    95. 95 // Obtain the cylinder inliers and coefficients
    96. 96 seg.segment (*inliers_cylinder, *coefficients_cylinder);
    97. 97 std::cerr << "Cylinder coefficients: " << *coefficients_cylinder << std::endl;
    98. 98
    99. 99 // Write the cylinder inliers to disk
    100. 100 extract.setInputCloud (cloud_filtered2);
    101. 101 extract.setIndices (inliers_cylinder);
    102. 102 extract.setNegative (false);
    103. 103 pcl::PointCloud<PointT>::Ptr cloud_cylinder (new pcl::PointCloud<PointT> ());
    104. 104 extract.filter (*cloud_cylinder);
    105. 105 if (cloud_cylinder->points.empty ())
    106. 106 std::cerr << "Can't find the cylindrical component." << std::endl;
    107. 107 else
    108. 108 {
    109. 109 std::cerr << "PointCloud representing the cylindrical component: " << cloud_cylinder->size () << " data points." << std::endl;
    110. 110 writer.write ("table_scene_mug_stereo_textured_cylinder.pcd", *cloud_cylinder, false);
    111. 111 }
    112. 112 return (0);
    113. 113}

     说明:
    1、相关的头文件

    1. 1#include <pcl/ModelCoefficients.h>
    2. 2#include <pcl/io/pcd_io.h>
    3. 3#include <pcl/point_types.h>
    4. 4#include <pcl/filters/extract_indices.h>
    5. 5#include <pcl/filters/passthrough.h>
    6. 6#include <pcl/features/normal_3d.h>
    7. 7#include <pcl/sample_consensus/method_types.h>
    8. 8#include <pcl/sample_consensus/model_types.h>
    9. 9#include <pcl/segmentation/sac_segmentation.h>

     2、创建所需要的对象

    1. 17 pcl::PCDReader reader;//创建读文件对象
    2. 18 pcl::PassThrough<PointT> pass;//创建直通滤波对象
    3. 19 pcl::NormalEstimation<PointT, pcl::Normal> ne;//点云法向量对象
    4. 20 pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg; //平面分割对象
    5. 21 pcl::PCDWriter writer;//写入对象
    6. 22 pcl::ExtractIndices<PointT> extract;//点云提取对象
    7. 23 pcl::ExtractIndices<pcl::Normal> extract_normals;//点提取对象
    8. 24 pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT> ());//kd搜索对象

     3、设置对应的存储容器

    1. 26 // Datasets
    2. 27 pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
    3. 28 pcl::PointCloud<PointT>::Ptr cloud_filtered (new pcl::PointCloud<PointT>);
    4. 29 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
    5. 30 pcl::PointCloud<PointT>::Ptr cloud_filtered2 (new pcl::PointCloud<PointT>);
    6. 31 pcl::PointCloud<pcl::Normal>::Ptr cloud_normals2 (new pcl::PointCloud<pcl::Normal>);
    7. 32 pcl::ModelCoefficients::Ptr coefficients_plane (new pcl::ModelCoefficients), coefficients_cylinder (new pcl::ModelCoefficients);
    8. 33 pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices), inliers_cylinder (new pcl::PointIndices);

    4、 读取数据到cloud

    1. 35 // Read in the cloud data
    2. 36 reader.read ("table_scene_mug_stereo_textured.pcd", *cloud);
    3. 37 std::cerr << "PointCloud has: " << cloud->size () << " data points." << std::endl;

    5、创建一个直通滤波器过滤cloud中不需要的点,存入cloud_filtered

    1. 39 // Build a passthrough filter to remove spurious NaNs and scene background
    2. 40 pass.setInputCloud (cloud);
    3. 41 pass.setFilterFieldName ("z");
    4. 42 pass.setFilterLimits (0, 1.5);
    5. 43 pass.filter (*cloud_filtered);
    6. 44 std::cerr << "PointCloud after filtering has: " << cloud_filtered->size () << " data points." << std::endl;

    6、估计cloud_filtered中点法线,存入cloud_normals

    1. 46 // Estimate point normals
    2. 47 ne.setSearchMethod (tree);
    3. 48 ne.setInputCloud (cloud_filtered);
    4. 49 ne.setKSearch (50);
    5. 50 ne.compute (*cloud_normals);

    7、为平面模型创建分割对象并设置所有参数

    1. 52 // Create the segmentation object for the planar model and set all the parameters
    2. 53 seg.setOptimizeCoefficients (true);//模型参数是否需要优化
    3. 54 seg.setModelType (pcl::SACMODEL_NORMAL_PLANE);//标准平面模型
    4. 55 seg.setNormalDistanceWeight (0.1);//设置表面法线权重系数
    5. 56 seg.setMethodType (pcl::SAC_RANSAC);//设置采用RANSAC作为算法的参数估计方法
    6. 57 seg.setMaxIterations (100);//最大迭代次数
    7. 58 seg.setDistanceThreshold (0.03);//设置内点到模型的距离允许最大值
    8. 59 seg.setInputCloud (cloud_filtered);
    9. 60 seg.setInputNormals (cloud_normals);
    10. 61 // Obtain the plane inliers and coefficients
    11. 62 seg.segment (*inliers_plane, *coefficients_plane);//分割结果索引点云存入inliers_plane,模型系数存入coefficients_plane
    12. 63 std::cerr << "Plane coefficients: " << *coefficients_plane << std::endl;

    8、从输入点云中提取内点

    1. 65 // Extract the planar inliers from the input cloud
    2. 66 extract.setInputCloud (cloud_filtered);
    3. 67 extract.setIndices (inliers_plane);
    4. 68 extract.setNegative (false);

    9、将分割后的点云通过索引找到该块点云 存入

    1. 70 // Write the planar inliers to disk
    2. 71 pcl::PointCloud<PointT>::Ptr cloud_plane (new pcl::PointCloud<PointT> ());
    3. 72 extract.filter (*cloud_plane);
    4. 73 std::cerr << "PointCloud representing the planar component: " << cloud_plane->size () << " data points." << std::endl;
    5. 74 writer.write ("table_scene_mug_stereo_textured_plane.pcd", *cloud_plane, false);

    10、删除内切线,提取其他点

    1. 76 // Remove the planar inliers, extract the rest
    2. 77 extract.setNegative (true);
    3. 78 extract.filter (*cloud_filtered2);
    4. 79 extract_normals.setNegative (true);
    5. 80 extract_normals.setInputCloud (cloud_normals);
    6. 81 extract_normals.setIndices (inliers_plane);
    7. 82 extract_normals.filter (*cloud_normals2);

    11、为圆柱体分割创建分割对象并设置所有参数

    1. 84 // Create the segmentation object for cylinder segmentation and set all the parameters
    2. 85 seg.setOptimizeCoefficients (true);//模型参数需要优化
    3. 86 seg.setModelType (pcl::SACMODEL_CYLINDER);//设置分割模型为圆柱
    4. 87 seg.setMethodType (pcl::SAC_RANSAC);//设置分割方法
    5. 88 seg.setNormalDistanceWeight (0.1);//设置表面法线权重系数
    6. 89 seg.setMaxIterations (10000);//设置最大迭代次数
    7. 90 seg.setDistanceThreshold (0.05);//设置内点到模型之间的最大距离
    8. 91 seg.setRadiusLimits (0, 0.1); //设置圆柱模型的半径范围
    9. 92 seg.setInputCloud (cloud_filtered2);//输入分割圆柱的点云数据
    10. 93 seg.setInputNormals (cloud_normals2);//输入分割圆柱的法线向量

    12、分割结果索引保存 系数保存

    1. 95 // Obtain the cylinder inliers and coefficients
    2. 96 seg.segment (*inliers_cylinder, *coefficients_cylinder);
    3. 97 std::cerr << "Cylinder coefficients: " << *coefficients_cylinder << std::endl;

    13、提取圆柱并输出圆柱点云

    1. 99 // Write the cylinder inliers to disk
    2. 100 extract.setInputCloud (cloud_filtered2);
    3. 101 extract.setIndices (inliers_cylinder);
    4. 102 extract.setNegative (false);
    5. 103 pcl::PointCloud<PointT>::Ptr cloud_cylinder (new pcl::PointCloud<PointT> ());
    6. 104 extract.filter (*cloud_cylinder);
    7. 105 if (cloud_cylinder->points.empty ())
    8. 106 std::cerr << "Can't find the cylindrical component." << std::endl;
    9. 107 else
    10. 108 {
    11. 109 std::cerr << "PointCloud representing the cylindrical component: " << cloud_cylinder->size () << " data points." << std::endl;
    12. 110 writer.write ("table_scene_mug_stereo_textured_cylinder.pcd", *cloud_cylinder, false);
    13. 111 }
    14. 112 return (0);
    15. 113}

    编译和运行程序

    1、将以下行添加到 CMakeLists.txt 文件中:

    1. 1cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
    2. 2
    3. 3project(cylinder_segmentation)
    4. 4
    5. 5find_package(PCL 1.2 REQUIRED)
    6. 6
    7. 7include_directories(${PCL_INCLUDE_DIRS})
    8. 8link_directories(${PCL_LIBRARY_DIRS})
    9. 9add_definitions(${PCL_DEFINITIONS})
    10. 10
    11. 11add_executable (cylinder_segmentation cylinder_segmentation.cpp)
    12. 12target_link_libraries (cylinder_segmentation ${PCL_LIBRARIES})

    2、运行

    $ ./cylinder_segmentation

    3、输出

    1. PointCloud has: 307200 data points.
    2. PointCloud after filtering has: 139897 data points.
    3. [pcl::SACSegmentationFromNormals::initSACModel] Using a model of type: SACMODEL_NORMAL_PLANE
    4. [pcl::SACSegmentationFromNormals::initSACModel] Setting normal distance weight to 0.100000
    5. [pcl::SACSegmentationFromNormals::initSAC] Using a method of type: SAC_RANSAC with a model threshold of 0.030000
    6. [pcl::SACSegmentationFromNormals::initSAC] Setting the maximum number of iterations to 100
    7. Plane coefficients: header:
    8. seq: 0
    9. stamp: 0.000000000
    10. frame_id:
    11. values[]
    12. values[0]: -0.0161854
    13. values[1]: 0.837724
    14. values[2]: 0.545855
    15. values[3]: -0.528787
    16. PointCloud representing the planar component: 117410 data points.
    17. [pcl::SACSegmentationFromNormals::initSACModel] Using a model of type: SACMODEL_CYLINDER
    18. [pcl::SACSegmentationFromNormals::initSACModel] Setting radius limits to 0.000000/0.100000
    19. [pcl::SACSegmentationFromNormals::initSACModel] Setting normal distance weight to 0.100000
    20. [pcl::SACSegmentationFromNormals::initSAC] Using a method of type: SAC_RANSAC with a model threshold of 0.050000
    21. [pcl::SampleConsensusModelCylinder::optimizeModelCoefficients] LM solver finished with exit code 2, having a residual norm of 0.322616.
    22. Initial solution: 0.0452105 0.0924601 0.790215 0.20495 -0.721649 -0.661225 0.0422902
    23. Final solution: 0.0452105 0.0924601 0.790215 0.20495 -0.721649 -0.661225 0.0396354
    24. Cylinder coefficients: header:
    25. seq: 0
    26. stamp: 0.000000000
    27. frame_id:
    28. values[]
    29. values[0]: 0.0452105
    30. values[1]: 0.0924601
    31. values[2]: 0.790215
    32. values[3]: 0.20495
    33. values[4]: -0.721649
    34. values[5]: -0.661225
    35. values[6]: 0.0396354
    36. PointCloud representing the cylindrical component: 8625 data points.

  • 相关阅读:
    HTML前端面试基础(一)
    23、分布式锁
    Mockito Spies InjectMocks & 回调测试
    第十二章 控制值的转换
    JMeter 性能测试基本过程及示例
    人工智能对建筑学的影响,关于智能建筑的论文
    基于JavaSSM的学生成绩管理APP系统设计与实现
    026-从零搭建微服务-文件服务(二)
    跨平台应用开发进阶(二十七)安卓应用加固签名后应用无法打开
    css nth-child 的使用
  • 原文地址:https://blog.csdn.net/m0_50046535/article/details/125472129