pcl中ransac提取直线_利用 PCL 分割平面上的物体

利用 PCL 可以分割坐落于某一平面上的物体,首先要对整体点云执行平面分割,以找到场景中的某一平面,然后利用 pcl::ExtractPolygonalPrismData 类,可以分割出在该平面之上的物体聚类。

具体的使用流程是:

  1. 加载点云
  2. 滤波之类的预处理(这一步可有可无,取决于你的点云是否需要滤波)
  3. 对整体点云执行 RANSAC 平面分割,得到某一平面的内点索引 inliers 和平面方程系数 coefficients
  4. 利用 pcl::ExtractIndices 类提取内点,将提取到的内点保存到新的点云中
  5. 为内点点云创建二维凸多边形(或者凹多边形)
  6. 利用 pcl::ExtractPolygonalPrismData 类,分割出位于平面之上的物体

以下是我的代码

#include <pcl/io/pcd_io.h>

#include <pcl/filters/passthrough.h>
#include <pcl/filters/extract_indices.h>

#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_polygonal_prism_data.h>

#include <pcl/surface/concave_hull.h>

#include <pcl/visualization/pcl_visualizer.h>

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

    pcl::io::loadPCDFile<pcl::PointXYZ>(argv[1], *cloud);


    // 为点云做一次直通滤波
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);

    pcl::PassThrough<pcl::PointXYZ> pass;
    pass.setInputCloud (cloud);
    pass.setFilterFieldName ("z");
    pass.setFilterLimits (0, 1.1);
    pass.filter (*cloud_filtered);
    std::cerr << "cloud_filtered->size = " << cloud_filtered->size () << std::endl;


    // 对滤波之后的点云做平面分割,目的是确定场景中的平面,并得到平面的内点及其系数
    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 (0.01);
    seg.setMaxIterations(500);
    seg.setInputCloud (cloud_filtered);
    seg.segment (*inliers, *coefficients);
    std::cerr << "inliers->indices.size = " << inliers->indices.size () << std::endl;


    // 把平面内点提取到一个新的点云中
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane (new pcl::PointCloud<pcl::PointXYZ>);

    pcl::ExtractIndices<pcl::PointXYZ> ex ;
    ex.setInputCloud(cloud_filtered);
    ex.setIndices(inliers);
    ex.filter(*cloud_plane);


    // 对平面内点的点云创建二维的凹多边形
    // 凸多边形的效果不太好,是凹是凸取决于具体的点云,可视化一下 cloud_hull 点云就知道了
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_hull (new pcl::PointCloud<pcl::PointXYZ>);

    pcl::ConcaveHull<pcl::PointXYZ> hull;
    hull.setInputCloud (cloud_plane);  // 注意这里,输入点云是平面内点的点云
    hull.setAlpha(0.1);
    hull.reconstruct (*cloud_hull);  // 这一步就把平面内点的外接凹多边形创建出来了
    std::cerr << "cloud_hull->size = " << cloud_hull->size () << std::endl;


    // 最后一步,分割平面上的物体
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_object (new pcl::PointCloud<pcl::PointXYZ>);
    if (hull.getDimension() == 2)
    {
        pcl::PointIndices::Ptr indices_object (new pcl::PointIndices);

        pcl::ExtractPolygonalPrismData<pcl::PointXYZ> prism ;
        prism.setInputCloud(cloud_filtered);  // 注意这里,输入点云是过滤后的点云
        prism.setInputPlanarHull(cloud_hull);  // 再把平面的凹多边形输入进去
        prism.setHeightLimits(0.01, 0.5);  // 从平面上 1cm 到 50cm 的高度范围之内分割物体
        prism.segment(*indices_object);  // 执行分割,得到物体的点索引

        ex.setIndices(indices_object);
        ex.filter(*cloud_object);  // 把物体单独提取到一个新的点云中

        std::cerr << "cloud_object->size = " << cloud_object->size() << std::endl;
    }


    // 以下都是可视化部分
    pcl::visualization::PCLVisualizer::Ptr viewer (new pcl::visualization::PCLVisualizer ("3D Viewer"));
    viewer->addCoordinateSystem (0.5);

    int v1 ;
    viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> red(cloud_filtered, 255, 0, 0);
    viewer->addPointCloud (cloud_filtered, red, "cloud_filtered", v1);

    int v2 ;
    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> green(cloud_object, 0, 255, 0);
    viewer->addPointCloud (cloud_object, green, "cloud_object", v2);

    while (!viewer->wasStopped ())
    {
        viewer->spinOnce ();
    }

    return 0;
}

分割完毕之后,效果是这样的

30401d159f866c845c77c5f53d609046.png

左边是原始点云经过直通滤波之后的样子,是一个平面上放了一个杯子;右边是把杯子给分割出来了。

  • 0
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PCL(Point Cloud Library)是一个开源的点云处理库,而RANSAC(Random Sample Consensus)是一种常用的参数估计算法。在PCL使用RANSAC进行平面直线拟合是非常常见的操作。 对于平面拟合,你可以使用PCL的`pcl::SACSegmentation`类来实现。以下是一个使用RANSAC拟合平面的示例代码: ```cpp #include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/ModelCoefficients.h> #include <pcl/sample_consensus/method_types.h> #include <pcl/sample_consensus/model_types.h> #include <pcl/segmentation/sac_segmentation.h> int main() { // 读取点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); pcl::io::loadPCDFile<pcl::PointXYZ>("input_cloud.pcd", *cloud); // 创建分割器对象 pcl::SACSegmentation<pcl::PointXYZ> seg; pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients); pcl::PointIndices::Ptr inliers(new pcl::PointIndices); // 设置分割器参数 seg.setOptimizeCoefficients(true); seg.setModelType(pcl::SACMODEL_PLANE); seg.setMethodType(pcl::SAC_RANSAC); seg.setMaxIterations(1000); seg.setDistanceThreshold(0.01); // 执行平面拟合 seg.setInputCloud(cloud); seg.segment(*inliers, *coefficients); // 输出拟合结果 std::cout << "Model coefficients: " << coefficients->values[0] << " " << coefficients->values[1] << " " << coefficients->values[2] << " " << coefficients->values[3] << std::endl; return 0; } ``` 上述代码,`pcl::SACSegmentation`类用于执行RANSAC算法进行点云拟合。你需要设置模型类型为`pcl::SACMODEL_PLANE`表示拟合平面,设置方法类型为`pcl::SAC_RANSAC`表示使用RANSAC算法。通过调整`setMaxIterations`和`setDistanceThreshold`可以控制算法的迭代次数和距离阈值。 对于直线拟合,可以将模型类型设置为`pcl::SACMODEL_LINE`,其余代码基本相同。 希望以上信息对你有帮助!如果你还有其他问题,请随时提问。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值