Ubuntu 20.04.06 PCL C++学习记录(二十二)

@[TOC]PCL中点云分割模块的学习

学习背景

参考书籍:《点云库PCL从入门到精通》以及官方代码PCL官方代码链接,,PCL版本为1.10.0,CMake版本为3.16,可用点云下载地址

学习内容

在本教程中,我们将学习如何使用 pcl::DifferenceOfNormalsEstimation 类中实现的法线差特征,对无组织点云进行基于比例的分割。

源代码及所用函数

源代码

//法线差示例
#include <string>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/search/kdtree.h>
#include<pcl/search/organized.h>//用于在有序点云数据中进行近邻搜索
#include<pcl/features/normal_3d_omp.h>//提供一个利用OpenMP加速的法线估计类pcl::NormalEstimationOMP,用于计算点云中每个点的法线。
#include<pcl/filters/conditional_removal.h>//提供条件滤波器
#include<pcl/segmentation/extract_clusters.h>//定义pcl::EuclideanClusterExtraction类,用于从点云数据中提取聚类
#include<pcl/features/don.h>//定义 pcl::DONEstimator 类,用于为点云中的每个点计算其法向量

int main(int argc,char** argv)
{
    //在 DoN 滤波器中使用的最小刻度
    double scale1;
    //在 DoN 滤波器中使用的最大刻度
    double scale2;
    //阈值的最小 DoN 幅值
    double threshold;
    //使用欧几里得聚类将场景划分为具有给定距离容差的群组
    double segradius;

    if(argc < 6)
    {
        std::cout <<  argv[0] << "输入必要的参数" << std::endl;
        exit(EXIT_FAILURE);  
    }
    
    std::string infile = argv[1];//读取PCD文件名
    std::istringstream(argv[2]) >> scale1; //最小刻度
    std::istringstream (argv[3]) >> scale2;//最大刻度
    std::istringstream (argv[4]) >> threshold;//DoN 幅值阈值
    std::istringstream (argv[5]) >> segradius;//距离分割阈值
    /***************************以 blob 格式加载云***********************/
    //pcl::PCLPointCloud2是PCL中用于存储点云数据的通用数据结构,它可以存储任意类型的点云数据,包括具有多种字段(如XYZ坐标、RGB颜色、法向量等)的点云
    pcl::PCLPointCloud2 blob;//
    pcl::io::loadPCDFile (infile.c_str (), blob);
    pcl::PointCloud<pcl::PointXYZRGB>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGB>);
    //pcl::fromPCLPointCloud2()是PCL提供的一个函数,用于将pcl::PCLPointCloud2类型的数据转换为其他类型的点云数据
    pcl::fromPCLPointCloud2(blob,*cloud);
    /********************************使用KDTREE进行无组织搜索*************************/
    pcl::search::Search<pcl::PointXYZRGB>::Ptr tree;
    if (cloud->isOrganized())
    {
        tree.reset(new pcl::search::OrganizedNeighbor<pcl::PointXYZRGB>);
    }
    else
    {
        tree.reset(new pcl::search::KdTree<pcl::PointXYZRGB>(false));
    }
    tree->setInputCloud(cloud);

    if (scale1 >= scale2)
    {
        std::cout << "最大刻度必须比最小刻度大" << std::endl;
        exit(EXIT_FAILURE);
    }
    /*******************************************使用每个点的小比例尺和大比例尺计算法线***************************/
    pcl::NormalEstimationOMP<pcl::PointXYZRGB,pcl::PointNormal> ne;
    ne.setInputCloud(cloud);
    ne.setSearchMethod(tree);
    //设置视角才能使法线朝向同一方向
    ne.setViewPoint(std::numeric_limits<float>::max(),std::numeric_limits<float>::max(),std::numeric_limits<float>::max());
    //以小比例尺计算法线
    std::cout << "以此刻度计算:" << scale1 << std::endl;
    pcl::PointCloud<pcl::PointNormal>::Ptr normals_small_scale(new pcl::PointCloud<pcl::PointNormal>);
    ne.setRadiusSearch(scale1);
    ne.compute(*normals_small_scale);
    //以大比例尺计算法线
    std::cout << "以此刻度计算:" << scale2 << std::endl;
    pcl::PointCloud<pcl::PointNormal>::Ptr normals_large_scale (new pcl::PointCloud<pcl::PointNormal>);
    ne.setRadiusSearch (scale2);
    ne.compute (*normals_large_scale);
    /****************************************为DON结果生成输出点云*************************************/
    pcl::PointCloud<pcl::PointNormal>::Ptr doncloud(new pcl::PointCloud<pcl::PointNormal>);
    pcl::copyPointCloud(*cloud,*doncloud);
    std::cout << "计算DON" << std::endl;
    //创建 DoN 运算符
    pcl::DifferenceOfNormalsEstimation<pcl::PointXYZRGB,pcl::PointNormal,pcl::PointNormal> don;
    don.setInputCloud(cloud);
    don.setNormalScaleLarge(normals_large_scale);
    don.setNormalScaleSmall(normals_small_scale);
    if (!don.initCompute())
    {
        std::cout << "错误: 无法初始化 DoN 功能操作符" << std::endl;
        exit(EXIT_FAILURE);
    }
    //计算DON
    don.computeFeature(*doncloud);
    //保存DON特征
    pcl::PCDWriter writer;
    writer.write<pcl::PointNormal>("don.pcd",*doncloud,false);

    std::cout << "筛选出 DoN mag <= " << threshold << "....." << std::endl;
    /***************************************************建立过滤条件******************************/
    pcl::ConditionOr<pcl::PointNormal>::Ptr range_cond(new pcl::ConditionOr<pcl::PointNormal>);
    range_cond->addComparison(pcl::FieldComparison<pcl::PointNormal>::ConstPtr(
        new pcl::FieldComparison<pcl::PointNormal>("curvature",pcl::ComparisonOps::GT,threshold)));
    // 构建过滤器
    pcl::ConditionalRemoval<pcl::PointNormal> condrem;
    condrem.setCondition(range_cond);
    condrem.setInputCloud(doncloud);
    pcl::PointCloud<pcl::PointNormal>::Ptr doncloud_filtered (new pcl::PointCloud<pcl::PointNormal>);
    //使用过滤器
    condrem.filter(*doncloud_filtered);
    doncloud = doncloud_filtered;
    //保存过滤结果
    std::cout << "滤波后点云有: " << doncloud->size() << " 个点." << std::endl;
    writer.write<pcl::PointNormal> ("don_filtered.pcd", *doncloud, false); 
    //按幅度筛选
    std::cout << "使用带有容差的欧氏聚类提取进行聚类 <= " << segradius << "..." << std::endl;
    pcl::search::KdTree<pcl::PointNormal>::Ptr segtree (new pcl::search::KdTree<pcl::PointNormal>);
    segtree->setInputCloud (doncloud);

    std::vector<pcl::PointIndices> cluster_indices;
    pcl::EuclideanClusterExtraction<pcl::PointNormal> ec;
    ec.setClusterTolerance(segradius);
    ec.setMinClusterSize(50);
    ec.setMaxClusterSize(100000);
    ec.setSearchMethod (segtree);
    ec.setInputCloud (doncloud);
    ec.extract(cluster_indices);

    int j = 0;
    for (const auto& cluster : cluster_indices)
    {
        pcl::PointCloud<pcl::PointNormal>::Ptr cloud_cluster_don (new pcl::PointCloud<pcl::PointNormal>);
        for(const auto& idx : cluster.indices)
        {
            cloud_cluster_don->points.push_back ((*doncloud)[idx]);
        }
        cloud_cluster_don->width = cloud_cluster_don->size ();
        cloud_cluster_don->height = 1;
        cloud_cluster_don->is_dense = true;

        std::cout << "代表集群的点云: " << cloud_cluster_don->size () << " 个点." << std::endl;
        std::stringstream ss;
        ss << "don_cluster_" << j << ".pcd";
        writer.write<pcl::PointNormal> (ss.str (), *cloud_cluster_don, false);
        ++j;
    }

}

CMakeLists.txt

cmake_minimum_required(VERSION 3.16 FATAL_ERROR)#指定CMake的最低版本要求为3.16
project(project)#设置项目名称
find_package(PCL 1.10 REQUIRED)#查找PCL库,要求版本为1.10或更高。
include_directories(${PCL_INCLUDE_DIRS})#将PCL库的头文件目录添加到包含路径中
link_directories(${PCL_LIBRARY_DIRS})#将PCL库的库文件目录添加到链接器搜索路径中。
add_definitions(${PCL_DEFINITIONS})#添加PCL库的编译器定义
add_executable (don_segmentation don_segmentation.cpp)
target_link_libraries (don_segmentation ${PCL_LIBRARIES})#将PCL库链接到可执行文件目标。

运行结果

这段代码要求输入的PCD文件包含RGB颜色信息,即点云中的每个点除了XYZ坐标外,还包含RGB颜色值。
以下为命令示例

./don_segmentation output.pcd 0.5 2.0 0.1 0.5

函数

  • #include<pcl/features/normal_3d_omp.h>这个头文件的作用是提供了一个利用OpenMP加速的法线估计类pcl::NormalEstimationOMP,用于计算点云中每个点的法线。通过设置不同的搜索半径scale1和scale2,分别计算了点云在小比例尺和大比例尺下的法线,并将结果存储在normals_small_scale和normals_large_scale中。

补充内容

  • #include<pcl/search/organized.h> 这个头文件属于点云库(Point Cloud Library, PCL)中的 search 模块,主要用于在有序点云数据中进行近邻搜索。具体来说,这个头文件中定义了两个类:
    1. pcl::search::OrganizedNeighbor
      这个类实现了一种高效的近邻搜索算法,专门针对有序点云数据(例如来自深度相机或激光雷达的数据)进行优化。它利用了点云数据的有序性质,可以快速查找给定查询点附近的邻居点,从而加速许多基于近邻关系的点云处理算法,如surface normal estimation(表面法向量估计)、feature estimation(特征估计)等。
    2. pcl::search::OrganizedNeighborSearch
      这个类是一个基类,提供了统一的接口来执行近邻搜索。OrganizedNeighbor类继承自它,并实现了高效的有序点云近邻搜索算法。使用这个头文件的主要好处是可以显著加速对有序点云数据的近邻搜索过程,从而提高点云处理算法的整体性能。但是,它只适用于有序点云数据,对于无序点云数据,需要使用其他搜索数据结构,如kd树或octree。
  • exit() 函数会立即终止程序,在程序终止之前,exit() 函数会执行一些与 C 语言标准库相关的清理操作。但exit() 不会执行与用户定义的对象和资源相关的清理工作,如调用析构函数、释放动态分配的内存等。这意味着,如果在调用 exit() 之前没有手动释放这些资源,就可能导致资源泄漏。
  • 14
    点赞
  • 20
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值