精华内容
下载资源
问答
  • 基于欧几里得的点云分割,先放结果图,图1为原图,图2为分割后的图,图3为输出的点云数量。 图1 图2 图3 具体过程: 加载点云,滤波; 分割平面模型;(下一篇博客) 去除所有平面点云,对余下的点进行聚类分割...


    欧几里得算法:

    基于欧几里得的点云分割,先放结果图,图1为原图,图2为分割后的图,图3为输出的点云数量。

    图1
    在这里插入图片描述
    图2
    在这里插入图片描述
    图3
    具体过程:

    1. 加载点云,滤波;
    2. 分割平面模型;(下一篇博客)
    3. 去除所有平面点云,对余下的点进行聚类分割;
    4. 显示聚类分割结果。
      首先加载点云滤波,即对点云进行下采样,减少点云数量,提高精度;然后分割平面模型,该图中平面有两个,桌子平面和地面,将平面点云去除后,进行聚类分割;接着采用欧几里得聚类算法进行聚类分割。
      一般情况下,很少有点云悬空漂浮和其他点云无连接,因此可以先进行平面模型分割,就比如桌子,桌子平面分割了,桌子上的物体就会更容易分割和识别。
    展开全文
  • 点云分割(point cloud segmentation) 根据空间、几何和纹理等特征点进行划分,同一划分内的点云拥有相似的特征。 点云分割的目的是分块,从而便于单独处理。 点云分类(point cloud classification) 为每个点...

    目录

    概念

    点云分割(point cloud segmentation)

    点云分类(point cloud classification)

     特征提取

    分割

    物体识别

    分类

     常见点云分割方法

    随机抽样一致算法(Random Sample Consensus,RANSAC)

    算法流程

     RANSAC与最小二乘区别

     PCL中的 Sample_consensus 模块

     欧式聚类分割(聚类)

    区域生长算法(聚类)

    基于颜色的区域生长分割(聚类)

     最小图割的分割

    基于法线微分的分割

     基于超体素的分割

     深度学习的分割方法


    概念

    点云分割(point cloud segmentation)

    根据空间、几何和纹理等特征点进行划分,同一划分内的点云拥有相似的特征。

    点云分割的目的是分块,从而便于单独处理。

    点云分类(point cloud classification)

    为每个点分配一个语义标记。点云的分类是将点云分类到不同的点云集。同一个点云集具有相似或相同的属性,例如地面、树木、人等。也叫做点云语义分割。

     特征提取

    单个点或一组点可以根据低级属性检测某种类型的点。

    • “低级属性”是指没有语义(例如,位置,高程,几何形状,颜色,强度,点密度等)的信息。
    • “低级属性 ”信息通常可以从点云数据中获取而无需事先的高级知识。例如,平面提取和边缘检测、以及特征描述子的 计算都可以视为特征提取过程。

    分割

    基于上述低级属性将点分组为一个部分或一个对象的过程。与单独对每个点处理或分析相比,分割过 程对每个对象的进一步处理和分析,使其具有更丰富的信息。

    物体识别

    识别点云中一种或多种类型对象的过程。该过程通常通过根据特征提取和分割的结果执行分析, 并基于先验知识在给定的约束和规则下进行。

    分类

    类似于对象识别的过程,该过程为每个点,线段或对象分配一个类别或标识,以表示某些类型的对象 (例如,标志,道路,标记或建筑物)。


    对象识别点云分类之间的区别在于:

    • 对象识别是利用一种方法以将一些特定对象与其他对象区分开
    • 分类的目的通常是在语义上标记整个场景。

    点云的有效分割是许多应用的前提

    • 工业测量/逆向工程:对零件表面提前进行分割,再进行后续重建、计算特征等操作。
    • 遥感领域:对地物进行提前分割,再进行分类识别等工作 

     常见点云分割方法

    随机抽样一致算法(Random Sample Consensus,RANSAC)

    采用迭代的方式从一组包含离群的被观测数据中估算出数学模型的参数。

    RANSAC算法假设数据中包含正确数据异常数据(或称为噪声)。

    正确数据记为内点(inliers),异常数据记为外点(outliers)。

    同时RANSAC也假设,给定一组正确的数据,存在可以计算出符合这些数据的模型参数的方法。该算法核心思想就是随机性和假设性:

    • 随机性是根据正确数据出现概率去随机选取抽样数据,根据大数定律,随机性模拟可以近似得到正确结果。
    • 假设性是假设选取出的抽样数据都是正确数据,然后用这些正确数据通过问题满足的模型,去计算其他点 ,然后对这次结果进行一个评分。

    RANSAC算法被广泛应用在计算机视觉领域和数学领域,例如直线拟合平面拟合计算图像点云间的变换矩阵计算基础矩阵等方面,使用的非常多。

    基于RANSAC的基本检测算法虽然具有较高的鲁棒性和效率,但是目前仅针对平面,球,圆柱体,圆锥和圆环物种基本的基元。

    算法流程

    1. 要得到一个直线模型,需要两个点唯一确定一个直线方程。所以第一 步随机选择两个点。
    2. 通过这两个点,可以计算出这两个点所表示的模型方程y=ax+b。
    3. 将所有的数据点套到这个模型中计算误差。
    4. 找到所有满足误差阈值的点。
    5. 然后我们再重复1~4这个过程,直到达到一定迭代次数后,选出那个被 支持的最多的模型,作为问题的解。

    Martin A. Fischler 和Robert C. Bolles于1981年发表在ACM期刊上的论文《Random Sample Consensus: A Paradigm for Model Fitting with Applications to Image Analysis and Automated Cartography》

     RANSAC与最小二乘区别


    最小二乘法尽量去适应包括局外点在内的所有点。相 反,RANSAC能得出一个仅仅用局内点计算出模型, 并且概率还足够高。但是,RANSAC并不能保证结果 一定正确,为了保证算法有足够高的合理概率,必须小心的选择算法的参数(参数配置)。经实验验证, 对于包含80%误差的数据集,RANSAC的效果远优于直接的最小二乘法。

     最重要的参数就是迭代的次数 k :

    1. 假设任取一个点是内群点的概率为 w,则有w = 数 据中内群点的数量/数据中点的总数;
    2. 则任取 n 个点都是内群点的概率为 𝑤𝑛;
    3. 所以我们所选择的 n 个点至少有一个不是内群点的 概率为 1 − 𝑤𝑛;
    4. 所以我们连续重复 k 次都不能有一次全是内群点的 概率 𝑝𝑒为 1 − 𝑤𝑛 𝑘;
    5. 由上,我们发现当 w 保持不变时,我们要想让𝑝𝑒尽 量小,则 n 越大,k 就需要越大

     

     PCL中的 Sample_consensus 模块

     PCL中的 Sample_consensus库实现了随机采样一致性及其泛化估计算法,以及例如平面、柱面等各种常见几何模型,用不同的估计算法和不同的几何模型自由结合估算点云中隐含的具体几何模型的系数, 实现点云中所处的几何模型的分割。

    支持以下模型:

    • SACMODEL_PLANE - 用于确定平面模型。平面的四个系数。
    • SACMODEL_LINE - 用于确定线模型。直线的六个系数由直线上的一个点和直线的方向给出。
    • SACMODEL_CIRCLE2D - 用于确定平面中的 2D 圆。圆的三个系数由其中心和半径给出。
    • SACMODEL_CIRCLE3D - 用于确定平面中的 3D 圆。圆的七个系数由其中心、半径和法线给出。
    • SACMODEL_SPHERE - 用于确定球体模型。球体的四个系数由其 3D 中心和半径给出。
    • SACMODEL_CYLINDER - 用于确定气缸模型。圆柱体的七个系数由其轴上的点、轴方向和半径给出。
    • SACMODEL_CONE - 用于确定锥模型。锥体的七个系数由其顶点、轴方向和张角给出。
    • SACMODEL_TORUS - 尚未实施
    • SACMODEL_PARALLEL_LINE -在最大指定角度偏差内确定与给定轴平行的线的模型。线系数类似于SACMODEL_LINE
    • SACMODEL_PERPENDICULAR_PLANE -在最大指定角度偏差内确定垂直于用户指定轴的平面的模型。平面系数类似于SACMODEL_PLANE
    • SACMODEL_PARALLEL_LINES - 尚未实现

    以下列表描述了实现的稳健样本共识估计器:

    //创建一个模型参数对象,用于记录结果
    pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
    //inliers表示误差能容忍的点 记录的是点云的序号
    pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
    // 创建一个分割器
    pcl::SACSegmentation<pcl::PointXYZ> seg;
    // Optional seg.setOptimizeCoefficients (true);
    // Mandatory-设置目标几何形状
    seg.setModelType (pcl::SACMODEL_PLANE);
    //分割方法:随机采样法seg.setMethodType (pcl::SAC_RANSAC);
    //设置误差容忍范围seg.setDistanceThreshold (0.01);
    //输入点云seg.setInputCloud (cloud);
    //分割点云,得到参数
    seg.segment (*inliers, *coefficients);
    

     

    Schnabel R, Wahl R, Klein R. Efficient RANSAC for pointcloud shape detection[C]//Computer graphics forum. Oxford, UK: Blackwell Publishing Ltd, 2007, 26(2): 214-226.

    https://cg.cs.uni-bonn.de/en/publications/paper-details/schnabel-2007-efficient/

     欧式聚类分割(聚类)

    聚类方法,通过特征空间确定点与点之间的亲疏程度

    算法流程:

    1. 找到空间中某点p,有kdTree找到离他最近的n个点,判断这n个点到p的距离。将距离小于阈值r的点p1,p2,p3... 放在类Q里
    2. 在 Q里找到一点p1,重复1,找到p22,p23,p24 全部放进Q里
    3. 当 Q 再也不能有新点加入了,则完成搜索了

    pcl::EuclideanClusterExtraction<pcl::Point XYZ> ec;
    ec.setClusterTolerance (0.02); ec.setMinCl
    usterSize (100);
    ec.setMaxClusterSize (25000); ec.setSearchMethod (tree); ec.setInputCloud (cloud_filtered); ec.extract (cluster_indices);
    

    使用类pcl::ConditionEuclideanClustering实现点云分割,与其他分割方法不同的是该方法的聚类约束条件(欧式距离、平滑度、RGB颜色等)可以由用户自己定义,即当搜索到一个近邻点时,用户可以自定义该邻域点是否合并到当前聚类的条件。

    pcl::ConditionalEuclideanClustering<PointTypeFull> cec (true);//创建条件聚类分割对象,并进行初始化。cec.setInputCloud (cloud_with_normals);//设置输入点集
    //用于选择不同条件函数
    switch(Method)
    {
    case 1:
    cec.setConditionFunction (&enforceIntensitySimilarity); break;
    case 2:
    cec.setConditionFunction (&enforceCurvatureOrIntensitySimilarity); break;
    case 3:
    cec.setConditionFunction (&customRegionGrowing); break;
    default:
    cec.setConditionFunction (&customRegionGrowing); break;
     
    }
    cec.setClusterTolerance (500.0);//设置聚类参考点的搜索距离
    cec.setMinClusterSize (cloud_with_normals->points.size () / 1000);//设置过小聚类的标准cec.setMaxClusterSize (cloud_with_normals->points.size () / 5);//设置过大聚类的标准cec.segment (*clusters);//获取聚类的结果,分割结果保存在点云索引的向量中
    cec.getRemovedClusters (small_clusters, large_clusters);//获取无效尺寸的聚类
    

    这个条件的设置是可以由我们自定义的,因为除了距离检查,聚类的点还需要满足一个特殊的自定义的要 求,就是以第一个点为标准作为种子点,候选其周边的点作为它的对比或者比较的对象,如果满足条件就加入到聚类的对象中。

    //如果此函数返回true,则将添加候选点到种子点的簇类中。 
    bool customCondition(const pcl::PointXYZ& seedPoint, const pcl::PointXYZ& candidatePoin t, float squaredDistance) {
    
            // 在这里你可以添加你自定义的条件 
            return false; 
            return true;
    }

    区域生长算法(聚类)

    区域生长算法: 将具有相似性的点云集合起来构成区域。
    首先对每个需要分割的区域找出一个种子点作为生长的起点,然后将种子点周围邻域中与种子有相同或相似性质的点合并到种子像素所在的区域中。而新的点继续作为种子向四周生长,直到再没有满足条件 的像素可以包括进来,一个区域就生长而成了。

    算法流程:

    1. 计算 法线normal 和 曲率curvatures,依据曲率升序排序;
    2. 选择曲率最低的为初始种子点,种子周围的临近点和种子点云相比较;
    3. 法线的方向是否足够相近(法线夹角足够 r p y), 法线夹角阈值;
    4. 曲率是否足够小(表面处在同一个弯曲程度),区域差值阈值;
    5. 如果满足2,3则该点可用做种子点;
    6. 如果只满足2,则归类而不做种子;

     算法是针对小曲率变化面设计的,尤其适合对连续阶梯平面进行分割。

    //区域增长聚类分割对象	< 点 , 法 线 > 
    pcl::RegionGrowing<pcl::PointXYZ, pcl::Normal> reg; 
    reg.setMinClusterSize (50);	//最小的聚类的点数
    reg.setMaxClusterSize (1000000);//最大的聚类的点数
    reg.setSearchMethod (tree);	//搜索方式
    reg.setNumberOfNeighbours (30); //设置搜索的邻域点的个数
    reg.setInputCloud (cloud);	//输入点
    //reg.setIndices (indices); 
    reg.setInputNormals (normals);	//输入的法线
    reg.setSmoothnessThreshold (3.0 / 180.0 * M_PI);//设置平滑度 法线差值阈值
    reg.setCurvatureThreshold (1.0);	//设置曲率的阀值
    

    基于颜色的区域生长分割(聚类)

    基于颜色的区域生长分割

    基于颜色的区域生长分割原理上和基于曲率,法线的分割方法是一致的,只不过比较目标换成了颜色。可以认为,同一个颜色且挨得近,是一类的可能性很大,比较适合用于室内场景分割。尤其是复杂室内场景,颜色分割可以轻松的将连续的场景点云变成不同的物体。哪怕是高低不平的地面,设法用采样一致分割器抽掉平面,颜色分割算法对不同的颜色的物体实现分割。

    算法主要分为两步:

    1. 分割,当前种子点和领域点之间色差小于色差阀值的视为一个聚类。
    2. 合并,聚类之间的色差小于色差阀值和并为一个聚类,且当前聚类中点的数量小于聚类点数量的与最近的聚类合并在一起。

     RBG的距离

    //基于颜色的区域生成的对象 
    pcl::RegionGrowingRGB<pcl::PointXYZRGB> reg; 
    reg.setInputCloud (cloud); 
    reg.setIndices (indices); //点云的索引 
    reg.setSearchMethod (tree); 
    reg.setDistanceThreshold (10);//距离的阀值 
    reg.setPointColorThreshold (6);//点与点之间颜色容差 
    reg.setRegionColorThreshold (5);//区域之间容差 
    reg.setMinClusterSize (600); //设置聚类的大小 
    std::vector <pcl::PointIndices> clusters; 
    reg.extract (clusters);//
    pcl::PointCloud <pcl::PointXYZRGB>::Ptr colored_cloud = reg.getColoredCloud ();

     最小图割的分割

    图论中的最小割(min-cut) 广泛应用在网络规划,求解桥问题,图像分割等领域。

    最小割算法是图论中的一个概念,其作用是以某种方式,将两个点分开,当然这两个点中间可能是通过无数的点再相连的。 如果要分开最左边的点和最右边的点,红绿两种割法都是可行的, 但是红线跨过了三条线,绿线只跨过了两条。单从跨线数量上来论可以得出绿线这种切割方法更优的结论。但假设线上有不同的权值,那么最优切割则和权值有关了。

     

     http://gfx.cs.princeton.edu/pubs/Golovinskiy_2009_MBS/paper_small.pdf

    算法主要思想:

    1. 建图:对于给定的点云,算法将包含点云中每一个点的图构造为一组普通顶点和另外两个称为源点和汇点的顶点。每个普通顶点都有边缘,将对应的点与其最近的邻居连接起来。
    2. 算法为每条边缘分配权重。有三种不同的权:首先,它将权重分配到云点之间的边缘。这个权重称为平滑成本,由公式计算:

    这里dist是点之间的距离。距离点越远,边被切割的可能性就越大。

            3.算法设置数据成本。它包括前景和背景惩罚。第一个是将云点与源顶点连接起来并具有用户定义的常量值的边缘的权重。

     对点云的前景点和背景点进行划分。

    // 申明一个Min-cut的聚类对象pcl::MinCutSegmentation<pcl::PointXYZ> clustering; clustering.setInputCloud(cloud);	//设置输入
    //创建一个点云,列出所知道的所有属于对象的点
    // (前景点)在这里设置聚类对象的中心点(想想是不是可以可以使用鼠标直接选择聚类中心点的方法呢?) pcl::PointCloud<pcl::PointXYZ>::Ptr foregroundPoints(new pcl::PointCloud<pcl::PointXYZ>()); pcl::PointXYZ point;
    point.x = 100.0;
    point.y = 100.0;
    point.z = 100.0;
    foregroundPoints->points.push_back(point);
    clustering.setForegroundPoints(foregroundPoints);//设置聚类对象的前景点
    
    //设置sigma,它影响计算平滑度的成本。它的设置取决于点云之间的间隔(分辨率) clustering.setSigma(0.02);// cet cost = exp(-(dist/cet)^2)
    // 设 置 聚 类 对 象 的 半 径 . clustering.setRadius(0.01);// dist2Center / radius
    
    //设置需要搜索的临近点的个数,增加这个也就是要增加边界处图的个数
    clustering.setNumberOfNeighbours(20);
    
    //设置前景点的权重(也就是排除在聚类对象中的点,它是点云之间线的权重,) clustering.setSourceWeight(0.6);
    
     
    std::vector <pcl::PointIndices> clusters; clustering.extract(clusters);
    

    基于法线微分的分割

    根据不同尺度下法向量特征的差异性,利用pcl::DifferenceOfNormalsEstimation实现点云分割,在处理有较大尺度变化的场景点云分割效果较好,利用不同支撑半径去估算同一点的两个单位法向量,单位法向量的差定义DoN特征

    DoN算法:

    DoN特征源于观察到基于所给半径估计的表面法向量可以反映曲面的内在几何特征,因此这种分割算法是基于法线估计的,需要计算点云中某一点的法线估计。而通常在计算法线估计的时候都会用到邻域信息,很明显邻域大小的选取会影响法线估计的结果。

    而在DoN算法中,邻域选择的大小就被称为support radius。对点云中某一点选取不同的支持半径,即可以得到不同的法线估计,而法线之间的差异,就是是所说的法线差异。

    PCL_点云分割_基于法线微分分割

    算法流程:

    1. 对于输入点云数据中的每一点,利用较大的支撑半径计算法向量;
    2. 对于输入点云数据中的每一点,利用较大的支撑半径计算法向量;
    3. 对于输入点云数据中的每一点,单位化每一点的法向量差异
    4. 过滤所得的向量域(DoN特征向量),分割出目标尺寸对应的点云;
    // Create output cloud for DoN results
    PointCloud<PointNormal>::Ptr doncloud (new pcl::PointCloud<PointNormal>); copyPointCloud<PointXYZRGB, PointNormal>(*cloud, *doncloud);
    
    pcl::DifferenceOfNormalsEstimation<PointXYZRGB, PointNormal, PointNormal> do
    n;
    don.setInputCloud (cloud); 
    don.setNormalScaleLarge (normals_large_scale); 
    don.setNormalScaleSmall (normals_small_scale); don.initCompute ();
    // Compute DoN 
    don.computeFeature (*doncloud);
    

    Difference of Normals as a Multi-Scale Operator in Unorganized Point Clouds

     基于超体素的分割

     超体(super voxel)是一种集合,集合的元素是“体素”。
    与体素滤波器中的体类似,其本质是一个个的小方块。与之前提到的所有分割手段不同,超体聚类的目的 并不是分割出某种特定物体,其对点云实施过分割(over segmentation),将场景点云化成很多小块,并 研究每个小块之间的关系。
    以八叉树对点云进行划分,获得不同点团之间的邻接关系。与图像相似,点云的邻接关系也有很多,如面 邻接、线邻接、点邻接。

    【PCL】—超体聚类点云分割算法详解 

     超体聚类实际上是一种特殊的区域生长算法,和无限制的生长不同,超体聚类首先需要规律的布置区域生长“晶核”。晶核在空间中实际上是均匀分布的,并指定晶核距离(Rseed),再指定粒子距离(Rvoxel),再指定最小晶粒(MOV),过小的晶粒需要融入最近的大晶粒。

     有了晶粒和结晶范围之后,我们只需要控制结晶过程,就能将整个空间划分开了。结晶过程的本质就是不断吸纳类似的粒子(八分空间)。类似是一个比较模糊的概念,关于类似的定义有以下公式:

    公式中的Dc表示颜色上的差异,Dn表示法线上的差异,Ds代表点距离上的差异。w表示一系列权重,用于控制结晶形状。在晶核周围寻找一圈,D最小的体素被认为是下一个“被发展的对象”。

    需要注意的是,结晶过程并不是长完一个晶核再长下一个,而是所有的晶核同时开始生长。接下来所有晶核继续公平竞争,发展第二个“对象”,以此循环。最终所有晶体应该几乎同时完成生长,整个点云也被晶格所分割开来,并且保证了一个晶包里的粒子都是类似的。

    //生成结晶器
    pcl::SupervoxelClustering<PointT> super(voxel_resolution, seed_resolution);
    //和点云形式有关if(disable_transform)
    super.setUseSingleCameraTransform(false);
    //输入点云及结晶参数
    super.setInputCloud(cloud); 
    super.setColorImportance(color_importance);
    super.setSpatialImportance(spatial_importance); super.setNormalImportance(normal_importance);
    //输出结晶分割结果:结果是一个映射表
    std::map <uint32_t, pcl::Supervoxel<PointT>::Ptr > supervoxel_clusters; super.extract(supervoxel_clusters);	//获得晶体中心
    PointCloudT::Ptr voxel_centroid_cloud = super.getVoxelCentroidCloud();	//获得晶体
    PointLCloudT::Ptr labeled_voxel_cloud = super.getLabeledVoxelCloud();
    

     深度学习的分割方法

    深度学习是当前模式识别,计算机视觉和数据分析中最有影响力,发展最快的前沿技术。

     1、基于多视图​​​​​​​

     2、基于体素

     

     3、端到端-直接对点云进行处理

     

     Guo Y, Wang H, Hu Q, et al. Deep learning for 3d point clouds: A survey[J]. IEEE transactions on pattern analysis and machine intelligence, 2020.

     Guo Y, Wang H, Hu Q, et al. Deep learning for 3d point clouds: A survey[J]. IEEE transactions on pattern analysis and machine intelligence, 2020.

    展开全文
  • 点云分割

    2020-03-01 20:49:49
    // 点云法线估计(过滤之后的),后续分割基于法线操作 ne.setSearchMethod (tree); //设置近邻搜索方式 ne.setInputCloud (cloud_filtered); //此时输入的点云为过滤之后的点云 ne.setKSearch (50); //计算点云法...

    这是官网的一个例子,参考网上一些前辈的注释自己理解了一下.

    #include <pcl/ModelCoefficients.h>
    #include <pcl/io/pcd_io.h>
    #include <pcl/point_types.h>
    #include <pcl/filters/extract_indices.h>
    #include <pcl/filters/passthrough.h>
    #include <pcl/features/normal_3d.h>
    #include <pcl/sample_consensus/method_types.h>
    #include <pcl/sample_consensus/model_types.h>
    #include <pcl/segmentation/sac_segmentation.h>
    #include <pcl/filters/passthrough.h>
    #include <pcl/visualization/pcl_visualizer.h>
    
    //强制类型转换
    typedef pcl::PointXYZ PointT;
    
    int
    main (int argc, char** argv)
    {
      
      //所属类,数据类型,名称
      pcl::PCDReader reader;       //读取pcd文件
      pcl::PassThrough<PointT> pass;    //直通滤波器
      pcl::NormalEstimation<PointT, pcl::Normal> ne;   //法线估计对象
      pcl::SACSegmentationFromNormals<PointT, pcl::Normal> seg;    //分割对象
      pcl::PCDWriter writer;       //写入pcd文件
      pcl::ExtractIndices<PointT> extract;     //点提取对象
      pcl::ExtractIndices<pcl::Normal> extract_normals;     //点提取对象
      pcl::search::KdTree<PointT>::Ptr tree (new pcl::search::KdTree<PointT> ());
    
      //点云消息转化,分别用指针存储
      pcl::PointCloud<PointT>::Ptr cloud (new pcl::PointCloud<PointT>);
      pcl::PointCloud<PointT>::Ptr cloud_filtered (new pcl::PointCloud<PointT>);
      pcl::PointCloud<pcl::Normal>::Ptr cloud_normals (new pcl::PointCloud<pcl::Normal>);
      pcl::PointCloud<PointT>::Ptr cloud_filtered2 (new pcl::PointCloud<PointT>);
      pcl::PointCloud<pcl::Normal>::Ptr cloud_normals2 (new pcl::PointCloud<pcl::Normal>);
      pcl::ModelCoefficients::Ptr coefficients_plane (new pcl::ModelCoefficients), coefficients_cylinder (new pcl::ModelCoefficients);
      pcl::PointIndices::Ptr inliers_plane (new pcl::PointIndices), inliers_cylinder (new pcl::PointIndices);
    
      //创建可视化窗口
      pcl::visualization::PCLVisualizer viewer("滤波");
    
      int v1(0);   //设置左右窗口
      int v2(1);
    
      viewer.createViewPort(0.0, 0.0, 0.5, 1, v1);
      viewer.setBackgroundColor(0, 0, 0, v1);
     
      viewer.createViewPort(0.5, 0.0, 1, 1, v2);
      viewer.setBackgroundColor(0.5, 0.5, 0.5, v2);
    
      // Read in the cloud data
      reader.read ("/home/zqh/table_scene_mug_stereo_textured.pcd", *cloud);
      std::cerr << "PointCloud has: " << cloud->points.size () << " data points." << std::endl;
    
       pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_out_green(cloud, 20, 180, 20);      // 显示绿色点云
       viewer.addPointCloud(cloud, cloud_out_green, "cloud_out1", v1); 
    
    
      pass.setInputCloud (cloud);      //设置输入点云
      pass.setFilterFieldName ("z");   //设置z轴为过滤字段
      pass.setFilterLimits (0, 1.5);
      pass.filter (*cloud_filtered);   //将过滤之后的点云存入cloud_filtered
      std::cerr << "PointCloud after filtering has: " << cloud_filtered->points.size () << " data points." << std::endl;
    
      // 点云法线估计(过滤之后的),后续分割基于法线操作
      ne.setSearchMethod (tree);            //设置近邻搜索方式
      ne.setInputCloud (cloud_filtered);    //此时输入的点云为过滤之后的点云
      ne.setKSearch (50);                   //计算点云法向量时,搜索的点云个数
      ne.compute (*cloud_normals);
    
    
      seg.setOptimizeCoefficients (true);            //这一句可以选择最优化参数的因子
      seg.setModelType (pcl::SACMODEL_NORMAL_PLANE);
      seg.setNormalDistanceWeight (0.1);
      seg.setMethodType (pcl::SAC_RANSAC);
      seg.setMaxIterations (100);
      seg.setDistanceThreshold (0.03);
      seg.setInputCloud (cloud_filtered);
      seg.setInputNormals (cloud_normals);
      // Obtain the plane inliers and coefficients
      seg.segment (*inliers_plane, *coefficients_plane);  //分割 得到平面系数 已经在平面上的点的 索引
      std::cerr << "Plane coefficients: " << *coefficients_plane << std::endl;
    
      // Extract the planar inliers from the input cloud
      extract.setInputCloud (cloud_filtered);
      extract.setIndices (inliers_plane);       //设置分割后点需要提取的点集
      extract.setNegative (false);            //设置提取内点而非外点
    
      // 存储分割后平面上的点到点云文件
      pcl::PointCloud<PointT>::Ptr cloud_plane (new pcl::PointCloud<PointT> ());
      extract.filter (*cloud_plane);
      std::cerr << "PointCloud representing the planar component: " << cloud_plane->points.size () << " data points." << std::endl;
    
      // Remove the planar inliers, extract the rest
      extract.setNegative (true);
      extract.filter (*cloud_filtered2);       //过滤之后保存到cloud_filtered2
      extract_normals.setNegative (true);
      extract_normals.setInputCloud (cloud_normals);
      extract_normals.setIndices (inliers_plane);           //索引平面内的点
      extract_normals.filter (*cloud_normals2);       //法线过滤之后存在cloud_normals2
    
    
      seg.setOptimizeCoefficients (true);         //设置对估计模型优化
      seg.setModelType (pcl::SACMODEL_CYLINDER);  //设置分割模型为圆柱形
      seg.setMethodType (pcl::SAC_RANSAC);        
      seg.setNormalDistanceWeight (0.1);         //设置表面法线权重系数
      seg.setMaxIterations (10000);              
      seg.setDistanceThreshold (0.05);         //内点到模型的距离允许的最大值
      seg.setRadiusLimits (0, 0.1);            //估计出圆柱模型的半径范围 
      seg.setInputCloud (cloud_filtered2);
      seg.setInputNormals (cloud_normals2);
    
      // Obtain the cylinder inliers and coefficients
      seg.segment (*inliers_cylinder, *coefficients_cylinder);
      std::cerr << "Cylinder coefficients: " << *coefficients_cylinder << std::endl;
    
      // Write the cylinder inliers to disk
      extract.setInputCloud (cloud_filtered2);
      extract.setIndices (inliers_cylinder);
      extract.setNegative (false);
      pcl::PointCloud<PointT>::Ptr cloud_cylinder (new pcl::PointCloud<PointT> ());
      extract.filter (*cloud_cylinder);
      
      pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_out_orage(cloud_cylinder, 250, 128, 10);     //显示橘色点云
      viewer.addPointCloud(cloud_cylinder, cloud_out_orage, "cloud_out2", v2);
    //viewer.setSize(960, 780);
      while (!viewer.wasStopped())
      {
      viewer.spinOnce();
      }
      return (0);
    }
    

    结果:
    在这里插入图片描述

    这个例子用到的知识点比较多,主要是要熟悉RANSAC算法的特点
    后续接着这个例子学习下点云索引提取子集 pcl::ExtractIndices extract;
    以及学习下点云法向量估计 pcl::NormalEstimation<PointT, pcl::Normal> ne;

    展开全文
  • PCL_点云分割_条件欧式聚类点云分割

    千次阅读 2020-03-17 11:04:24
    使用类pcl::ConditionEuclideanClustering实现点云分割,与其他分割方法不同的是该方法的聚类约束条件(欧式距离、平滑度、RGB颜色等)可以由用户自己定义,即当搜索到一个近邻点时,用户可以自定义该邻域点是否合并...

    使用类pcl::ConditionEuclideanClustering实现点云分割,与其他分割方法不同的是该方法的聚类约束条件(欧式距离、平滑度、RGB颜色等)可以由用户自己定义,即当搜索到一个近邻点时,用户可以自定义该邻域点是否合并到当前聚类的条件。
    代码:

    #include <pcl/point_types.h>
    #include <pcl/io/pcd_io.h>
    #include <pcl/console/time.h>
    #include <iostream>
    #include <ostream>
    #include <pcl/filters/voxel_grid.h>
    #include <pcl/features/normal_3d.h>
    #include <pcl/segmentation/conditional_euclidean_clustering.h>
    #include <pcl/console/parse.h>
    #include <pcl/visualization/pcl_visualizer.h>
    #include <pcl/visualization/point_cloud_color_handlers.h>
    typedef pcl::PointXYZI PointTypeIO;
    typedef pcl::PointXYZINormal PointTypeFull;
    typedef pcl::visualization::PointCloudColorHandler<pcl::PCLPointCloud2> ColorHandler;
    typedef ColorHandler::Ptr ColorHandlerPtr;
    typedef ColorHandler::ConstPtr ColorHandlerConstPtr;
    using namespace pcl::console;
    //设置条件函数1
    bool
    	enforceIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
    {
    	if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 5.0f)
    		return (true);
    	else
    		return (false);
    }
    //设置条件函数2
    bool
    	enforceCurvatureOrIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
    {
    	Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.normal, point_b_normal = point_b.normal;
    	if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 5.0f)
    		return (true);
    	if (fabs (point_a_normal.dot (point_b_normal)) < 0.05)
    		return (true);
    	return (false);
    }
    //设置条件函数3
    bool
    	customRegionGrowing (const PointTypeFull& point_a, const PointTypeFull& point_b, float squared_distance)
    {
    	Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.normal, point_b_normal = point_b.normal;
    	if (squared_distance < 10000)
    	{
    		if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 8.0f)
    			return (true);
    		if (fabs (point_a_normal.dot (point_b_normal)) < 0.06)
    			return (true);
    	}
    	else
    	{
    		if (fabs ((float)point_a.intensity - (float)point_b.intensity) < 3.0f)
    			return (true);
    	}
    	return (false);
    }
    
    int
    	main (int argc, char** argv)
    {
    
    	if(argc<2)
    	{
    		std::cout<<".exe xx.pcd -l 40 -r 300.0 -v 1 -m 1/2/3"<<std::endl;
    
    		return 0;
    	}//如果输入参数小于1个,输出提示
    	bool Visual=true;
    	//设置默认输入参数
    	float Leaf=40,Radius=300;
    	int Method=1;
    	//设置输入参数方式
    	parse_argument (argc, argv, "-l", Leaf);
    	parse_argument (argc, argv, "-r", Radius);
    	parse_argument (argc, argv, "-v", Visual);
    	parse_argument (argc, argv, "-m", Method);
    	// Data containers used
    	pcl::PointCloud<PointTypeIO>::Ptr cloud_in (new pcl::PointCloud<PointTypeIO>), cloud_out (new pcl::PointCloud<PointTypeIO>);//创建PointCloud <pcl::PointXYZI>共享指针并进行实例化
    	pcl::PointCloud<PointTypeFull>::Ptr cloud_with_normals (new pcl::PointCloud<PointTypeFull>);//创建PointCloud <pcl::PointXYZINormal>共享指针并进行实例化
    	pcl::IndicesClustersPtr clusters (new pcl::IndicesClusters), small_clusters (new pcl::IndicesClusters), large_clusters (new pcl::IndicesClusters);
    	pcl::search::KdTree<PointTypeIO>::Ptr search_tree (new pcl::search::KdTree<PointTypeIO>);
    	pcl::console::TicToc tt;
    
    	// Load the input point cloud
    	std::cerr << "Loading...\n", tt.tic ();
    	pcl::io::loadPCDFile (argv[1], *cloud_in);//打开输入点云文件
    	std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_in->points.size () << " points\n";
    
    	// Downsample the cloud using a Voxel Grid class
    	std::cerr << "Downsampling...\n", tt.tic ();
    	pcl::VoxelGrid<PointTypeIO> vg;//设置滤波对象
    	vg.setInputCloud (cloud_in);//设置需要过滤的点云给滤波对象
    	vg.setLeafSize (Leaf,Leaf,Leaf);//设置滤波时创建的栅格边长
    	vg.setDownsampleAllData (true);//设置所有的数值域需要被下采样
    	vg.filter (*cloud_out);//执行滤波处理,存储输出cloud_out
    	std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_out->points.size () << " points\n";
    
    	// Set up a Normal Estimation class and merge data in cloud_with_normals
    	std::cerr << "Computing normals...\n", tt.tic ();
    	pcl::copyPointCloud (*cloud_out, *cloud_with_normals);//复制点云
    	pcl::NormalEstimation<PointTypeIO, PointTypeFull> ne;//创建法线估计对象
    	ne.setInputCloud (cloud_out);//设置法线估计对象输入点集
    	ne.setSearchMethod (search_tree);//设置搜索方法
    	ne.setRadiusSearch (Radius);// 设置搜索半径
    	ne.compute (*cloud_with_normals);//计算并输出法向量
    	std::cerr << ">> Done: " << tt.toc () << " ms\n";
    
    	// Set up a Conditional Euclidean Clustering class
    	std::cerr << "Segmenting to clusters...\n", tt.tic ();
    	pcl::ConditionalEuclideanClustering<PointTypeFull> cec (true);//创建条件聚类分割对象,并进行初始化。
    	cec.setInputCloud (cloud_with_normals);//设置输入点集
    	//用于选择不同条件函数
    	switch(Method)
    	{
    	case 1:
    		cec.setConditionFunction (&enforceIntensitySimilarity);
    		break;
    	case 2:
    		cec.setConditionFunction (&enforceCurvatureOrIntensitySimilarity);
    		break;
    	case 3:
    		cec.setConditionFunction (&customRegionGrowing);
    		break;
    	default:
    		cec.setConditionFunction (&customRegionGrowing);
    		break;
    	}
    
    	cec.setClusterTolerance (500.0);//设置聚类参考点的搜索距离
    	cec.setMinClusterSize (cloud_with_normals->points.size () / 1000);//设置过小聚类的标准
    	cec.setMaxClusterSize (cloud_with_normals->points.size () / 5);//设置过大聚类的标准
    	cec.segment (*clusters);//获取聚类的结果,分割结果保存在点云索引的向量中
    	cec.getRemovedClusters (small_clusters, large_clusters);//获取无效尺寸的聚类
    	std::cerr << ">> Done: " << tt.toc () << " ms\n";
    	
    	for (int i = 0; i < small_clusters->size (); ++i)
    		for (int j = 0; j < (*small_clusters)[i].indices.size (); ++j)
    			cloud_out->points[(*small_clusters)[i].indices[j]].intensity = -2.0;
    
    	for (int i = 0; i < large_clusters->size (); ++i)
    		for (int j = 0; j < (*large_clusters)[i].indices.size (); ++j)
    			cloud_out->points[(*large_clusters)[i].indices[j]].intensity = +10.0;
    	
    	for (int i = 0; i < clusters->size (); ++i)
    	{
    		int label = rand () % 8;
    		for (int j = 0; j < (*clusters)[i].indices.size (); ++j)
    			cloud_out->points[(*clusters)[i].indices[j]].intensity = label;
    	}
    	// Save the output point cloud
    	if(0)
    	{//可视化部分包含有错误。待修改!
    		
    		boost::shared_ptr<pcl::visualization::PCLVisualizer> MView (new pcl::visualization::PCLVisualizer ("点云库PCL学习教程第二版-条件分割方法")); 
    		//View-Port1 
    		int v1(0); 
    		MView->createViewPort (0.0, 0.0, 0.5, 1.0, v1); //设置视口1的几何参数
    		MView->setBackgroundColor (1, 0.2, 1); //设置视口1的背景
    		MView->addText ("Before segmentation", 10, 10, "Before segmentation", v1); //为视口1添加标签
    		int v2(0); 
    		MView->createViewPort (0.5, 0.0, 1.0, 1.0, v2); 
    		MView->setBackgroundColor (0.5, 0.5,0.5, v2); 
    		MView->addText ("After segmentation", 10, 10, "After segmentation", v2); 
    		//pcl::visualization::PointCloudColorHandlerLabelField<pcl::PointXYZI>::Ptr color_handler(new pcl::visualization::PointCloudColorHandlerLabelField<pcl::PointXYZI>());
    		/*pcl::PCLPointCloud2::Ptr cloud;
    		ColorHandlerPtr color_handler;
    		pcl::fromPCLPointCloud2 (*cloud, *cloud_out);
    		Eigen::Vector4f origin=Eigen::Vector4f::Identity();
    		Eigen::Quaternionf orientation=Eigen::Quaternionf::Identity();
    
    		color_handler.reset (new pcl::visualization::PointCloudColorHandlerGenericField<pcl::PCLPointCloud2> (cloud,"intensity"));*/
    		MView->addPointCloud<pcl::PointXYZI>(cloud_in,"input",v1);//设置视口1的输入点云
    		//MView->addPointCloud(cloud,color_handler,origin, orientation,"output",v2);
    		MView->addPointCloud<pcl::PointXYZI>(cloud_out,"output",v2);
    		MView->spin();
    	}
    	else
    	{
    		std::cerr << "Saving...\n", tt.tic ();
    		pcl::io::savePCDFile ("output.pcd", *cloud_out);
    		std::cerr << ">> Done: " << tt.toc () << " ms\n";
    	}
    
    
    	return (0);
    }
    
    展开全文
  • PCL学习-点云分割-基于DoN的点云分割

    千次阅读 2019-07-09 14:34:49
    类pcl::DifferenceOfNormalsEstimation提供了一种根据不同尺度下法向量特征的差异性的点云分割方法,即DoN(Difference of Normals)算法。 DoN算法: DoN特征源于观察到基于所给半径估计的表面法向量可以反映曲面...
  • RANSAC激光点云分割

    2021-05-15 18:27:40
    RANSAC激光点云分割
  • 常见点云分割技术

    万次阅读 多人点赞 2019-06-08 15:21:47
    点云分割  点云分割可谓点云处理的精髓,也是三维图像相对二维图像最大优势的体现。  点云分割的目的是提取点云中的不同物体,从而实现分而治之,突出重点,单独处理的目的。而在现实点云数据中,往往对场景中的...
  • 点云分割笔记.pdf

    2021-09-14 15:53:24
    点云分割笔记.pdf
  • 点云分割是点云处理的一个关键环节,其分割质量决定了目标测量、位姿估计等任务的精确与否。提出了一种采用空间投影的深度图像(RGB-D)点云分割方法,在分析了相机模型、RGB-D数据特征以及图像阈值与目标点云关系的基础...
  • 点云分割方法

    千次阅读 2020-05-13 10:10:06
     点云分割可谓点云处理的精髓,也是三维图像相对二维图像最大优势的体现。  点云分割的目的是提取点云中的不同物体,从而实现分而治之,突出重点,单独处理的目的。而在现实点云数据中,往往对场景中的物体有一定...
  • 点云分割是点云数据处理的关键环节,区域生长因在三维点云分割中易于实现、便于使用而得到了广泛应用,然而由于点云特征的不确定性及种子点选取不合理导致传统区域生长法局部分割性能不稳定。针对此问题,提出一种...
  • 3D点云分割技术

    2019-02-03 14:03:24
    究了局部描述 符和全符在 3D点云中对象识 别与分类中的应用,并对点云匹配过程误校正算法进行了研究。同时针 别与分类中的应用,并对点云匹配过程误校正算法进行了...本文提出了一种基于拓扑结构变性3D点云分割方法。
  • 点云分割的学习 使用的数据等
  • 运行环境: ...在参考了CSDN博主:有梦想的田园犬对于PCL官方几种例程中的点云分割方法的实验后,考虑到系统的实时性要求,选择基于平面模型的地面点云去噪方法。 1、算法细节 该方法是利用RANS...
  • 针对机器人随机箱体抓取过程中场景分割困难的问题, 提出一种基于改进欧氏聚类的散乱工件点云分割方法。采用直通滤波法和迭代半径滤波法进行预处理, 得到去除干扰点后的散乱工件点云; 通过基于法线夹角的边缘检测去除...
  • 3D点云分割算法汇总

    2021-01-06 23:18:23
    来源:汇总|3D点云分割算法 前言 最近在arXiv和一些会议上看到了几篇3D点云分割paper,觉得还不错,在这里分享下基本思路。 1、SceneEncoder: Scene-Aware Semantic Segmentation of Point Clouds with A Learnable ...
  • 最近在一些工作材料时,偶然翻到几年前写的一篇《点云分割算法概述》的PPT,当时把这些算法都实现了一下,现在读起来还是很有参考价值。现把它分享出来,供大家分享交流。
  • 点云分割 PointCloudSegmentation测试笔记.pdf
  • 点云分割的目的提取点云中的不同物体,从而实现分而治之,突出重点,单独处理的目的。而在现实点云数据中,往往对场景中的物体有一定先验知识。比如:桌面墙面多半是大平面,桌上的罐子应该是圆柱体,长方体的盒...
  • 基于MATLAB实现的激光雷达点云分割和障碍物检测。基于MATLAB实现的激光雷达点云分割和障碍物检测。基于MATLAB实现的激光雷达点云分割和障碍物检测。基于MATLAB实现的激光雷达点云分割和障碍物检测。
  • 运行环境: VS2013,PCL1.8.0 ...在参考了CSDN博主:有梦想的田园犬对于PCL官方几种例程中的点云分割方法的实验后,考虑到系统的实时性要求,选择基于平面模型的地面点云去噪方法。   1、算法细节  ...
  • 点云学习之点云分割之导语

    千次阅读 2017-10-13 11:48:35
    点云分割算法主要有: 点云分割的目的:将点云分为多个同质区域,分割在同一区域中的点云具有相似的性质。 点云分割的难点所在: 数据的冗余;点密度的不均匀性;在数据结构表示上,缺乏明确统一的点云数据结构; ...
  • 地面点云分割与欧式聚类.zip
  • 基于局部几何特征的点云分割算法,侯琳琳,黄华,本文针对现有结构复杂的三维点云模型分割算法中过分割导致分割精度降低的问题,提出一种基于局部几何特征的点云分割算法。首先提
  • PCL 基于超体素的点云分割.pdf

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 9,124
精华内容 3,649
关键字:

点云分割