PCL分割学习

1.点云切割概述

点云分割是根据空间,几何和纹理等特征对点云进行划分,使得同一划分内的点云拥有相似的特征,点云的有效分割往往是许多应用的前提,例如逆向工作,CAD领域对零件的不同扫描表面进行分割,然后才能更好的进行空洞修复曲面重建,特征描述和提取,进而进行基于3D内容的检索,组合重用等。

2.PCL中常用的点云分割方法

Plane model segmentation (平面模型分割):这个算法能够把地面等一些平面给分割出来,方便后面的物体的点云分割。
Cylinder model segmentation(圆柱模型分割):这个算法能够把一些圆柱体分割出来,方便后面的物体的点云分割。
Euclidean Cluster Extraction (欧几里德聚类提取):这个算法通俗来讲就是先从点云中找出一个点p0,然后寻找p0周围最近的n个点,如果这n个点与p0之间的距离小于预先设定的阈值,那么就把这个点取出,依次重复。
Region growing segmentation (区域蔓延分割):对于普通点云,其可由法线、曲率估计算法获得其法线和曲率值。通过法线和曲率来判断某点是否属于该类,向周边蔓延直至完成。
Progressive Morphological Filter(渐进形态过滤器):这个算法本身用于处理高空获取的激光雷达数据,把地面与非地面的物体分割,也就是可以将地面分割出来使其他物体悬空,为下一步打基础。

3.几种分割的使用实例

3.1.简单平面分割

这个算法分割点云的平面的原理就是,通过改变平面模型(ax+by+cz+d=0)的参数,找出哪一组的参数能使得这个模型一定程度上拟合最多的点。这个程度就是由distancethreshold这个参数来设置。那找到这组参数后,这些能够被拟合的点就是平面的点。总体感受就是这个算法如果理解的不好调参有点复杂。
代码:

#include <iostream>
#include <pcl/ModelCoefficients.h>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/sample_consensus/method_types.h>   //随机参数估计方法头文件
#include <pcl/sample_consensus/model_types.h>   //模型定义头文件
#include <pcl/segmentation/sac_segmentation.h>   //基于采样一致性分割的类的头文件
#include <pcl/filters/extract_indices.h>
#include <pcl/visualization/cloud_viewer.h>

int
 main (int argc, char** argv)
{
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

  // 读取一个PCD文件
   if (pcl::io::loadPCDFile<pcl::PointXYZ>("d:/2.pcd", *cloud) != 0)
   {
       return -1;
   }


  //创建分割时所需要的模型系数对象,coefficients及存储内点的点索引集合对象inliers
  pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
  pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
  // 创建分割对象
  pcl::SACSegmentation<pcl::PointXYZ> seg;
  // 可选择配置,设置模型系数需要优化
  seg.setOptimizeCoefficients (true);
  // 必要的配置,设置分割的模型类型,所用的随机参数估计方法,距离阀值,输入点云
  seg.setModelType (pcl::SACMODEL_PLANE);   //设置模型类型
  seg.setMethodType (pcl::SAC_RANSAC);      //设置随机采样一致性方法类型
  seg.setDistanceThreshold (5);    //设定距离阀值,距离阀值决定了点被认为是局内点是必须满足的条件
                                       //表示点到估计模型的距离最大值,

  seg.setInputCloud (cloud);
  //引发分割实现,存储分割结果到点几何inliers及存储平面模型的系数coefficients
  seg.segment (*inliers, *coefficients);

  if (inliers->indices.size () == 0)
  {
    return (-1);
  }

   pcl::ExtractIndices<pcl::PointXYZ> extract;        //创建点云提取对象
  extract.setInputCloud (cloud);
      extract.setIndices (inliers);
      extract.setNegative (false);
   extract.filter (*cloud);

   //点云可视化
   pcl::visualization::CloudViewer viewer("sa");

       viewer.showCloud(cloud);
        while (!viewer.wasStopped()){
        }

  return (0);
}

处理前:
在这里插入图片描述
处理后:
在这里插入图片描述
要的就是这种效果,这样就可以将地面分割出去,使车辆悬空,然后通过后面的进一步处理将货车显示出来

3.2.圆柱模型分割

圆柱模型分割的具体原理与平面模型分割类似,如果理解了平面模型分割那么圆柱模型分割也就容易理解了,这里就不再详述。

3.3.欧几里德聚类提取

这个算法通俗来讲就是先从点云中找出一个点p0,然后寻找p0周围最近的n个点,如果这n个点与p0之间的距离小于预先设定的阈值,那么就把这个点取出,依次重复,最终分割出多个点云。
代码:

#include <pcl/io/pcd_io.h>
#include <pcl/segmentation/extract_clusters.h>
#include <QDebug>
#include <pcl/visualization/cloud_viewer.h>

#include <iostream>

int
main(int argc, char** argv)
{
    // 申明存储点云的对象.
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    // 读取一个PCD文件
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("d:/2.pcd", *cloud) != 0)
    {
        return -1;
    }
    // 建立kd-tree对象用来搜索
    pcl::search::KdTree<pcl::PointXYZ>::Ptr kdtree(new pcl::search::KdTree<pcl::PointXYZ>);
    kdtree->setInputCloud(cloud);

    // Euclidean 聚类对象.
    pcl::EuclideanClusterExtraction<pcl::PointXYZ> clustering;
    // 设置聚类的最小值 2cm
    clustering.setClusterTolerance(0.2);
    // 设置聚类的小点数和最大点云数
    clustering.setMinClusterSize(1000);
    //clustering.setMaxClusterSize(25000);
    clustering.setSearchMethod(kdtree);
    clustering.setInputCloud(cloud);
    std::vector<pcl::PointIndices> clusters;
    clustering.extract(clusters);
    // For every cluster...
    for (std::vector<pcl::PointIndices>::const_iterator i = clusters.begin(); i != clusters.end(); ++i)
    {
        //添加所有的点云到一个新的点云中
        pcl::PointCloud<pcl::PointXYZ>::Ptr cluster(new pcl::PointCloud<pcl::PointXYZ>);
        for (std::vector<int>::const_iterator point = i->indices.begin(); point != i->indices.end(); point++)
        cluster->points.push_back(cloud->points[*point]);
        cluster->width = cluster->points.size();
        cluster->height = 1;
        cluster->is_dense = true;
        //实验预先知道了最大的点云数量,偷懒就不排序查找点云数量最大的点云了
        if(cluster->points.size()>10000){
            //处理后点云显示
            pcl::visualization::CloudViewer viewer("PCL滤波");
            viewer.showCloud(cluster);
            while (!viewer.wasStopped()){
            }
        }
    }
}

处理前:
在这里插入图片描述
处理后:
在这里插入图片描述
效果很明显了,这已经很接近想要的结果了,但是目前默认的是货车的点云数量最多,所以很多地方还不够严谨。更好的实现方法应该是与其他处理结合。

3.4.区域蔓延分割

区域生长算法直观感觉上和欧几里德算法相差不大,都是从一个点出发,最终占领整个被分割区域。欧几里德算法是通过距离远近,来判断该点是否为要找的点,而区域蔓延分割算法是通过曲率、法线方向的来判断的。对于普通点云,先按照点的曲率值对点进行排序,找到最小曲率值点,并把它添加到种子点集,从种子的位置出发,开始往四周搜索点,然后比对点于点之间的曲率和法线方向,如果差距小于阈值就视为同一个簇。如果一个簇无法再蔓延,在剩下的点云里再找曲率小的面播种,然后继续重复直到遍历完毕。
代码:

#include <iostream>
#include <vector>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/search/search.h>
#include <pcl/search/kdtree.h>
#include <pcl/features/normal_3d.h>
#include <pcl/visualization/cloud_viewer.h>
#include <pcl/filters/passthrough.h>
#include <pcl/segmentation/region_growing.h>

int
main (int argc, char** argv)
{
    //读取PCL文件
  pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
  if ( pcl::io::loadPCDFile <pcl::PointXYZ> ("d:/2.pcd", *cloud) == -1)
  {
    std::cout << "Cloud reading failed." << std::endl;
    return (-1);
  }


  //创建法线估计对象,估计点云法向量
  pcl::search::Search<pcl::PointXYZ>::Ptr tree = boost::shared_ptr<pcl::search::Search<pcl::PointXYZ> > (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;
  //设置最小点簇的点数min
  reg.setMinClusterSize (50);
  //reg.setMaxClusterSize (1000000);
  reg.setSearchMethod (tree);
  reg.setNumberOfNeighbours (30);
  //输入点云
  reg.setInputCloud (cloud);

  reg.setInputNormals (normals);
  //设置法线角度差
  reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI);
  //设置曲率阈值
  reg.setCurvatureThreshold (1.0);

  std::vector <pcl::PointIndices> clusters;
  //切割处理保存到clusters中
  reg.extract (clusters);


  pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud ();
  pcl::visualization::CloudViewer viewer ("Cluster viewer");
  viewer.showCloud(colored_cloud);
  while (!viewer.wasStopped ())
  {
  }

  return (0);
}

处理前:
在这里插入图片描述
处理后:
在这里插入图片描述

4.总结

通过滤波和分割的学习,对分离出车辆已经有了一个实际不知是否可行的思路,具体思路如下:
1.首先由于点云数据中点的数量很大,做一些处理时耗时较多,所以第一步是使用体素滤波,实现下采样,即在保留点云原有形状的基础上减少点的数量 减少点云数据,以提高后面对点云处理的速度。
2.通过随机采样一致性(前面多出用到)分割地面,将地面从点云中分离出来,这时候地面上的物体就悬空了
3.使用统计滤波取出离散点
4.物体悬空后就更好分离了,现在就构建Kdtree通过欧几里得聚类提取获取路面上不同物体,然后车辆就提取了出来。

  • 4
    点赞
  • 23
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
### 回答1: PCL (Point Cloud Library) 是一个非常强大的点云处理库,它提供了丰富的功能来处理、分析和可视化点云数据。下面将从学习教程的角度来介绍PCL C++ 学习教程。 在学习PCL C++学习教程之前,我们先了解一下PCL的基础知识。PCL是一个开源项目,可以在Windows、Linux和Mac OS等操作系统上使用。它提供了常见的点云数据类型、滤波、分割、配准、特征提取和重建等功能。此外,PCL还有一个强大的可视化模块,可以方便地实时显示点云数据。 对于初学者而言,可以从PCL官方网站上的教程入手。官方网站提供了完整的文档和示例代码,可供学习者参考。此外,还有一些博客和视频教程可以帮助学习者更好地掌握PCL的使用。 学习PCL C++,需要一定的编程基础知识,例如掌握C++语言、面向对象编程和基本的算法理论等。在学习过程中,可以按照如下步骤进行: 1. 安装PCL库:根据自己的操作系统选择合适的安装方式,到PCL官方网站下载安装包并按照指南进行安装。 2. 学习PCL的基础知识:首先熟悉PCL的常见数据类型,例如点云表示和常见的PCL数据结构。然后学习如何读取和保存点云数据,以及基本的点云操作和可视化。 3. 学习PCL的模块功能:PCL库包含多个模块,例如滤波、分割、配准、特征提取和三维重建等。可以针对自己的需求选择相应的模块进行学习,并掌握它们的基本原理和使用方法。 4. 练习和实践:通过完成一些PCL的实际项目,例如点云配准、目标检测或三维重建等,来巩固所学的知识。 总之,学习PCL C++需要一定的时间和耐心,通过实践和不断学习,逐渐掌握PCL的使用技巧。希望以上简要的回答能对你理解PCL C++学习教程有所帮助。 ### 回答2: PCL(Point Cloud Library)是一个开源的计算机视觉库,主要用于处理和分析点云数据。它提供了许多功能强大的算法和工具,可以帮助开发人员在点云处理方面进行快速开发。 PCL C学习教程是PCL官方提供的一份入门教程,旨在帮助初学者快速上手PCL C的开发。该教程主要介绍了PCL的基本概念和使用方法,并提供了一些常见的点云处理算法的示例代码。通过学习PCL C学习教程,我们可以了解PCL的基本功能和使用技巧,并且可以开始进行简单的点云处理任务。 在学习PCL C的过程中,我们需要掌握一些基础知识,比如点云的表示和存储方式、点云的滤波和分割方法、点云的特征提取和匹配算法等等。PCL C学习教程提供了详细的解释和示例代码,以帮助我们理解和运用这些基础知识。 此外,PCL C学习教程还介绍了一些常见的点云处理应用场景,比如目标检测、点云配准和重建等。通过学习这些应用场景,我们可以了解到PCL C在不同领域的应用和相关的算法思想。 总结来说,PCL C学习教程是学习和使用PCL的入门指南,通过学习教程中的内容,我们可以掌握PCL C的基础知识和技能,并且开始进行简单的点云处理任务。 ### 回答3: PCL(Point Cloud Library)是一个用于点云数据处理的开源库。学习PCL可以帮助我们更好地理解和处理点云数据,从而在计算机视觉、机器人领域等方面开展相关工作。 学习PCL可以从以下几个方面入手。首先,了解PCL的基本概念和原理是非常重要的。PCL涵盖了点云数据获取、滤波、特征提取、配准等算法,了解这些基本概念是进行更高级别的数据处理的基础。 其次,学习PCL的使用方法。PCL提供了丰富的功能库和示例代码,通过实践使用可以更好地掌握PCL的各项功能。可以通过看官方文档、阅读教程、查阅论坛等方式学习PCL的使用方法。 再次,尝试应用PCL解决实际问题。通过完成一些小项目,如点云数据的滤波、分割、配准等任务,可以锻炼我们对PCL的熟练程度,并将PCL应用于实际工程中。 最后,与其他PCL爱好者交流学习。在互联网上可以找到很多与PCL相关的讨论组、社区和论坛,与其他使用PCL的人交流经验、分享学习心得,可以提高我们的学习效果。 总之,学习PCL需要理解基本概念和原理、掌握使用方法、应用于实践项目以及与他人交流学习。希望以上建议对学习PCL有所帮助。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值