[点云分割] 平面分割

一、介绍

SACSegmentation(Sample Consensus Segmentation)是PCL中的一个分割算法,用于从点云中识别出具有相同几何形状的模型。该算法使用采样一致性(Sample Consensus)方法,通过迭代地随机采样一组数据点,并拟合模型,然后评估拟合模型与数据点的一致性,最终找到最佳的模型参数。

SACSegmentation算法的基本原理如下:

  1. 随机采样:从输入的点云中随机选择一组数据点作为采样集。

  2. 模型拟合:根据采样集,使用最小二乘或其他方法拟合一个几何模型(如平面、球体、圆柱体等)。

  3. 评估一致性:计算所有点与拟合模型之间的距离,并将距离小于阈值的点划分为内点(inliers),距离大于阈值的点划分为外点(outliers)。

  4. 重复迭代:重复执行步骤1至3,直到达到预设的迭代次数或满足停止条件。

  5. 选择最佳模型:根据内点的数量或其他评估指标选择最佳的模型作为分割结果。

SACSegmentation算法具有很好的鲁棒性和通用性,可以用于分割各种几何形状的模型。通过调整阈值和迭代次数等参数,可以控制算法的精度和速度。

在PCL中,通过设置SACSegmentation对象的参数,如模型类型、方法类型、距离阈值等,以及输入点云数据,调用segment()方法即可执行分割算法,并获得分割结果,包括模型系数和内点索引等。

总而言之,SACSegmentation算法是一种常用的基于采样一致性的点云分割算法,可用于识别点云中的几何模型,为后续的点云处理和分析提供了基础。

二、代码

#include <iostream>
#include <chrono>

#include <pcl/ModelCoefficients.h> // 模型系数的定义
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h> // 各种点云数据类型
#include <pcl/sample_consensus/method_types.h> // 包含用于采样一致性算法的不同方法的定义,如RANSAC、MSAC等
#include <pcl/sample_consensus/model_types.h> // 包含用于采样一致性算法的不同模型的定义,如平面、球体、圆柱体
#include <pcl/segmentation/sac_segmentation.h> // 包含用于分割点云的采样一致性算法(SACSegmentation)的定义,用于识别点云的几何模型
#include <pcl/filters/extract_indices.h> // 包含用于从点云中提取特定索引的函数和类,用于根据索引提取点云中的子集
#include <pcl/visualization/pcl_visualizer.h> // 包含了用于可视化点云的函数和类,用于在3D视窗中现实点云数据

int main(){
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    // Fill the cloud data
    cloud->width = 100000;
    cloud->height = 1;
    cloud->points.resize(cloud->width * cloud->height);

    // generate the data
    for(auto& point: *cloud)
    {
        point.x = 1024 * rand() / (RAND_MAX + 1.0f);
        point.y = 1024 * rand() / (RAND_MAX + 1.0f);
        point.z = 1.0;
    }

    // Set a few outlierss
    for(int i=0; i< 1000; i++)
    {
        (*cloud)[i].z = 50 * rand() / (RAND_MAX + 1.0f);
    }

    std::cerr << "Point cloud data:" << cloud->size() << " points" << std::endl;
    for (const auto& point: *cloud)
        std::cerr << "   " << point.x << " "
                  << point.y << " "
                  << point.z << std::endl;

    pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
    pcl::PointIndices::Ptr inliers(new pcl::PointIndices);

    // Create the segmentation object
    pcl::SACSegmentation<pcl::PointXYZ> seg;

    auto start = std::chrono::high_resolution_clock::now();
    // 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);

    auto end = std::chrono::high_resolution_clock::now();
    std::chrono::duration<double, std::milli> duration = end - start;
    std::printf("segment cost time:%.2f ms\n", duration.count());

    if(inliers->indices.size() ==0)
    {
        PCL_ERROR("Cloud not estimate a planar model for the given dataset.\n");
        return(-1);
    }

//    std::cerr << "Model coefficients: " << coefficients->values[0] << " "
//                                        << coefficients->values[1] << " "
//                                        << coefficients->values[2] << " "
//                                        << coefficients->values[3] << std::endl;

//    std::cerr << "Model inliers: " << inliers->indices.size() << std::endl;
//    for (const auto& idx: inliers->indices)
//        std::cerr << idx << "   " << cloud->points[idx].x << " "
//                                  << cloud->points[idx].y << " "
//                                  << cloud->points[idx].z << std::endl;


    // extract inliers for visualization
    pcl::PointCloud<pcl::PointXYZ>::Ptr inlierCloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::ExtractIndices<pcl::PointXYZ> extract;

    extract.setInputCloud(cloud);
    extract.setIndices(inliers);
    extract.setNegative(false); // 提取inliers
    extract.filter(*inlierCloud);


    // visualization
    pcl::visualization::PCLVisualizer vis("cloud visualization");

    int v0(0);
    vis.createViewPort(0.0, 0.0, 0.5, 1.0, v0);
    vis.addCoordinateSystem(0.5,"reference0", v0);
    vis.setBackgroundColor(0.05, 0.05, 0.05, v0);

    vis.addPointCloud(cloud, "cloud0", v0);
    vis.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 4.0, "cloud0", v0);


    int v1(1);
    vis.createViewPort(0.5, 0, 1, 1, v1);
    vis.addCoordinateSystem(0.5, "reference1", v1);
    vis.setBackgroundColor(0,0,0,v1);

    vis.addPointCloud(inlierCloud, "cloud1", v1);
    vis.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 4.0, "cloud1", v1);


    while(!vis.wasStopped())
    {
        vis.spinOnce(100);
    }

    return(0);

}

猜你喜欢

转载自blog.csdn.net/weixin_45824067/article/details/134527565
今日推荐