【PCL】Segmentation 模块—— 平面模型分割(Plane model segmentation) ...

一给  金牌会员 | 2025-1-18 11:09:35 | 显示全部楼层 | 阅读模式
打印 上一主题 下一主题

主题 994|帖子 994|积分 2982

1、简介

PCL(Point Cloud Library)中的平面模型分割(Plane Model Segmentation)是一种从点云数据中提取平面布局的方法。它通过识别点云中符合平面模型的点集,将场景中的平面地区分割出来。
1.1 紧张步骤


  • 选择模型:选择平面模型作为分割目标。
  • 采样点:随机选取点云中的点用于模型拟合。
  • 模型拟合:使用采样点拟合平面模型,通常通过最小二乘法或RANSAC算法。
  • 内点检测:盘算全部点到拟合平面的距离,距离小于阈值的点被视为内点。
  • 分割:将内点标记为属于该平面,并从点云中移除,以便后续处置惩罚。
1.2 常用算法



  • RANSAC:鲁棒的拟合算法,能有用处置惩罚噪声和离群点。
  • 最小二乘法:实用于噪声较少的点云数据。
1.3 应用场景



  • 室内场景:提取地面、墙面等平面。
  • 机器人导航:识别可通行地区。
  • 三维重建:简化场景多少布局。
2、代码

从给定的点云数据集分割任意平面模型。
兼容性:> PCL 1.3
2.1 planar_segmentation.cpp

  1. #include <iostream>
  2. #include <pcl/ModelCoefficients.h>
  3. #include <pcl/io/pcd_io.h>
  4. #include <pcl/point_types.h>
  5. #include <pcl/sample_consensus/method_types.h>
  6. #include <pcl/sample_consensus/model_types.h>
  7. #include <pcl/segmentation/sac_segmentation.h>
  8. int main ()
  9. {
  10.   // 读取点云数据
  11.   // pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  12.   // pcl::io::loadPCDFile<pcl::PointXYZ>("table_scene_lms400.pcd", *cloud);
  13.   //----------------------------------
  14.   pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  15.   // Fill in the cloud data
  16.   cloud->width  = 15;
  17.   cloud->height = 1;
  18.   cloud->points.resize (cloud->width * cloud->height);
  19.   // Generate the data
  20.   for (auto& point: *cloud)
  21.   {
  22.     point.x = 1024 * rand () / (RAND_MAX + 1.0f);
  23.     point.y = 1024 * rand () / (RAND_MAX + 1.0f);
  24.     point.z = 1.0;
  25.   }
  26.   // Set a few outliers
  27.   (*cloud)[0].z = 2.0;
  28.   (*cloud)[3].z = -2.0;
  29.   (*cloud)[6].z = 4.0;
  30.   //----------------------------------
  31.   std::cerr << "Point cloud data: " << cloud->size () << " points" << std::endl;
  32.   for (const auto& point: *cloud)
  33.     std::cerr << "    " << point.x << " "
  34.                         << point.y << " "
  35.                         << point.z << std::endl;
  36.   pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
  37.   pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
  38.   // Create the segmentation object
  39.   pcl::SACSegmentation<pcl::PointXYZ> seg;
  40.   // Optional
  41.   seg.setOptimizeCoefficients (true);
  42.   // Mandatory
  43.   seg.setModelType (pcl::SACMODEL_PLANE);
  44.   seg.setMethodType (pcl::SAC_RANSAC);
  45.   seg.setDistanceThreshold (0.01);
  46.   seg.setInputCloud (cloud);
  47.   seg.segment (*inliers, *coefficients);
  48.   if (inliers->indices.size () == 0)
  49.   {
  50.     PCL_ERROR ("Could not estimate a planar model for the given dataset.\n");
  51.     return (-1);
  52.   }
  53.   std::cerr << "Model coefficients: " << coefficients->values[0] << " "
  54.                                       << coefficients->values[1] << " "
  55.                                       << coefficients->values[2] << " "
  56.                                       << coefficients->values[3] << std::endl;
  57.   std::cerr << "Model inliers: " << inliers->indices.size () << std::endl;
  58.   for (const auto& idx: inliers->indices)
  59.     std::cerr << idx << "    " << cloud->points[idx].x << " "
  60.                                << cloud->points[idx].y << " "
  61.                                << cloud->points[idx].z << std::endl;
  62.   return (0);
  63. }
复制代码
2.2 CMakeLists.txt

  1. cmake_minimum_required(VERSION 3.5 FATAL_ERROR)
  2. project(planar_segmentation)
  3. find_package(PCL 1.2 REQUIRED)
  4. include_directories(${PCL_INCLUDE_DIRS})
  5. link_directories(${PCL_LIBRARY_DIRS})
  6. add_definitions(${PCL_DEFINITIONS})
  7. add_executable (${PROJECT_NAME} planar_segmentation.cpp)
  8. target_link_libraries (${PROJECT_NAME} ${PCL_LIBRARIES})
复制代码
3、运行结果



  • 编译运行
  1. mkdir build && cd build
  2. cmake ..
  3. make
  4. ./planar_segmentation
复制代码


  • 运行结果

  • 分割过程的图形显示如下(代码中未写可视化,这个只是增补说明)

4、核心代码解读

这段代码使用PCL库进行平面模型分割,核心是通过RANSAC算法从点云数据中提取平面:

1. 创建分割对象

  1. pcl::SACSegmentation<pcl::PointXYZ> seg;
复制代码


  • 创建了一个SACSegmentation对象seg,用于执行基于采样同等性(Sample Consensus, SAC)的分割。
  • 模板参数pcl:ointXYZ体现点云中的点类型为三维点(包罗x, y, z坐标)。

2. 设置优化系数(可选)

  1. seg.setOptimizeCoefficients(true);
复制代码


  • 这是一个可选设置,用于优化模型系数。
  • 如果设置为true,分割算法会在找到初始模型后进一步优化平面模型的系数(如平面的法向量和截距),以提高精度。

3. 设置模型类型(必选)

  1. seg.setModelType(pcl::SACMODEL_PLANE);
复制代码


  • 设置分割的模型类型为平面模型(SACMODEL_PLANE)。
  • 这意味着算法将尝试从点云中拟合一个平面。

4. 设置方法类型(必选)

  1. seg.setMethodType(pcl::SAC_RANSAC);
复制代码


  • 设置分割方法为RANSAC(Random Sample Consensus)。
  • RANSAC是一种鲁棒的拟合算法,可以或许有用处置惩罚噪声和离群点。它通过随机采样点来拟合模型,并选择内点(符合模型的点)最多的模型。

5. 设置距离阈值(必选)

  1. seg.setDistanceThreshold(0.01);
复制代码


  • 设置点到模型的最大距离阈值,用于判断点是否为内点。
  • 如果一个点到拟合平面的距离小于0.01(单位与点云数据同等),则该点被视为内点。
  • 这个值需要根据点云的尺度调整,值越小,拟合的平面越精确,但大概遗漏一些点;值越大,拟合的平面大概不够精确。

6. 设置输入点云

  1. seg.setInputCloud(cloud);
复制代码


  • 将待分割的点云数据cloud设置为分割对象的输入。
  • cloud是一个pcl:ointCloud<pcl:ointXYZ>:tr类型的指针,指向点云数据。

7. 执行分割

  1. seg.segment(*inliers, *coefficients);
复制代码


  • 执行分割操纵。
  • inliers是一个pcl:ointIndices:tr类型的指针,用于存储分割结果中的内点(即属于平面的点)的索引。
  • coefficients是一个pcl::ModelCoefficients:tr类型的指针,用于存储拟合平面的模型系数(平面方程ax + by + cz + d = 0的系数a, b, c, d)。

总结

这段代码的核心是通过RANSAC算法从点云中提取平面:

  • 创建一个分割对象。
  • 设置平面模型和RANSAC方法。
  • 设置距离阈值以判断内点。
  • 输入点云数据并执行分割。
  • 输出内点索引和平面模型系数。
输出结果



  • inliers:包罗全部属于平面的点的索引。
  • coefficients:包罗平面方程的系数(a, b, c, d),体现平面方程ax + by + cz + d = 0。
如果点云中没有找到平面,inliers->indices将为空。

免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

一给

金牌会员
这个人很懒什么都没写!
快速回复 返回顶部 返回列表