【PCL】(二十六)自定义条件的欧几里得聚类分割点云

news/2024/5/20 10:37:47 标签: 聚类, 机器学习, 人工智能

(二十六)自定义条件的欧几里得聚类分割点云

以下代码实现自定义条件对点进行欧几里得聚类分割。

conditional_euclidean_clustering.cpp

#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/console/time.h>

#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/segmentation/conditional_euclidean_clustering.h>

typedef pcl::PointXYZI PointTypeIO;
typedef pcl::PointXYZINormal PointTypeFull;


/*条件函数的格式是固定的:
前两个输入参数的类型必须与pcl::ConditionalEuclideanClustering类中使用的模板化类型相同:包括当前种子点(第一个参数)和当前候选点(第二个参数)的点信息。
第三个输入参数必须是浮点值:为种子点和候选点之间的平方距离。
输出参数必须是布尔值。返回TRUE将把候选点合并到种子点的簇中,否则不会。*/

// 条件函数示例1
bool enforceIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float /*squared_distance*/)
{
      // 根据强度值相近程度进行聚类
      if (std::abs (point_a.intensity - point_b.intensity) < 5.0f)
            return (true);
      else
            return (false);
}
// 条件函数示例2
bool enforceNormalOrIntensitySimilarity (const PointTypeFull& point_a, const PointTypeFull& point_b, float /*squared_distance*/)
{
      // 强度值相似或法线方向相似归为一类
      Eigen::Map<const Eigen::Vector3f> point_a_normal = point_a.getNormalVector3fMap (), point_b_normal = point_b.getNormalVector3fMap ();
      if (std::abs (point_a.intensity - point_b.intensity) < 5.0f)
            return (true);
      if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI)))
            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.getNormalVector3fMap (), point_b_normal = point_b.getNormalVector3fMap ();
      // 与第二个条件函数相似,但根据点之间的距离具有不同的条件
      if (squared_distance < 10000)
      {
            if (std::abs (point_a.intensity - point_b.intensity) < 8.0f)
                        return (true);
            if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI)))
                        return (true);
      }
      else
      {
            if (std::abs (point_a.intensity - point_b.intensity) < 3.0f)
                        return (true);
      }
      return (false);
}

int main ()
{
      // Data containers used
      pcl::PointCloud<PointTypeIO>::Ptr cloud_in (new pcl::PointCloud<PointTypeIO>), cloud_out (new pcl::PointCloud<PointTypeIO>);
      pcl::PointCloud<PointTypeFull>::Ptr cloud_with_normals (new pcl::PointCloud<PointTypeFull>);
      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 ("Statues_5.pcd", *cloud_in);
      std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_in->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 (80.0, 80.0, 80.0);
      vg.setDownsampleAllData (true);
      vg.filter (*cloud_out);
      std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_out->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 (300.0);
      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);  // 类初始化为TRUE。这将允许提取太小或太大的簇
      cec.setInputCloud (cloud_with_normals);
      cec.setConditionFunction (&customRegionGrowing);  //   指定条件函数
      cec.setClusterTolerance (100.0);
      cec.setMinClusterSize (cloud_with_normals->size () / 1000);   // 占云总点不到0.1%的簇被认为太小。
      cec.setMaxClusterSize (cloud_with_normals->size () / 5);   // 占云总点20%以上的簇被认为太大。
      cec.segment (*clusters);
      // 太小的集群或太大的集群不会传递到主输出,而是可以在单独的pcl::Indices据容器中检索,但前提是类已用TRUE初始化。
      cec.getRemovedClusters (small_clusters, large_clusters); 
      std::cerr << ">> Done: " << tt.toc () << " ms\n";



      // Using the intensity channel for lazy visualization of the output
      for (const auto& small_cluster : (*small_clusters))
            for (const auto& j : small_cluster.indices)
                  (*cloud_out)[j].intensity = -2.0;
      for (const auto& large_cluster : (*large_clusters))
            for (const auto& j : large_cluster.indices)
                  (*cloud_out)[j].intensity = +10.0;
      for (const auto& cluster : (*clusters))
      {
            int label = rand () % 8;
            for (const auto& j : cluster.indices)
                  (*cloud_out)[j].intensity = label;
      }

      // Save the output point cloud
      std::cerr << "Saving...\n", tt.tic ();
      pcl::io::savePCDFile ("output.pcd", *cloud_out);
      std::cerr << ">> Done: " << tt.toc () << " ms\n";

      return (0);
}

编译

cmake_minimum_required(VERSION 3.5 FATAL_ERROR)

project(conditional_euclidean_clustering)

find_package(PCL 1.7 REQUIRED)

include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})

add_executable (conditional_euclidean_clustering conditional_euclidean_clustering.cpp)
target_link_libraries (conditional_euclidean_clustering ${PCL_LIBRARIES})

数据样本

编译并运行:

$ ./conditional_euclidean_clustering

在这里插入图片描述
太小的簇为蓝色的;太大的簇为红色的。


http://www.niftyadmin.cn/n/5415521.html

相关文章

量化投资实战(三)之配对交易策略--协整模型法

点赞、关注&#xff0c;养成良好习惯 Life is short, U need Python 量化投资实战系列&#xff0c;不断更新中 1. 初识配对交易策略 配对交易&#xff08;Pairing Trading&#xff09;是指八十年代中期华尔街著名投行Morgan Stanley的数量交易员Nunzio Tartaglia成立的一个数量…

基于机器视觉的动态物体追踪研究与实现

目 录 摘 要 I Abstract II 引 言 1 1 相关技术 3 1.1 Python 3 1.2图像二值化 3 1.3 Opencv 3 1.4图像去噪 3 1.5本章小结 4 2 动态目标检测算法 5 2.1 背景差分法 5 2.2 帧差法 7 2.3 光流法 9 2.4 本章小结 10 3 动态目标跟踪算法 11 3.1 Mean Shift 11 3.2 Cam Shift 13 3…

MRI基础--k空间

k空间定义 k空间是表示 MR 图像中空间频率的数字数组。 k空间物理意义 k 空间的单元通常显示在主轴 kx 和 ky 的矩形网格上。 k 空间的 kx 和 ky 轴对应于图像的水平 (x) 和垂直 (y) 轴。然而,k 轴表示 x 和 y 方向上的空间频率而不是位置。 k 空间中的各个点 (kx,ky) 与图像…

Material UI 5 学习02-其它按钮组件

Material UI 5 学习02-其它按钮组件 一、IconButton按钮二、 ButtonGroup按钮组1、最基本的实例2、垂直按钮组 一、IconButton按钮 图标按钮通常适用于切换按钮&#xff0c;允许选择或选择单个选项 取消选择&#xff0c;例如在项目中添加或删除星号。 <IconButton aria-lab…

【VTKExamples::Points】第三期 ExtractClusters

很高兴在雪易的CSDN遇见你 VTK技术爱好者 QQ:870202403 公众号:VTK忠粉 前言 本文分享VTK样例ExtractClusters,并解析接口vtkEuclideanClusterExtraction,希望对各位小伙伴有所帮助! 感谢各位小伙伴的点赞+关注,小易会继续努力分享,一起进步! 你的点赞就是我…

Agent——记忆模块

在基于大模型的 Agent架构设计方面,论文[1]提出了一个统一的框架,包括Profile模块、Memory模块、Planning模块和Action模块。其中长期记忆的状态维护至关重要,在 OpenAI AI 应用研究主管 Lilian Weng 的博客《基于大模型的 Agent 构成》[2]中,将记忆视为关键的组件之一,下…

ACL的应用与ENSP配置

目录 ACL的定义 ACL的功能 访问控制列表的调用方向 访问控制列表类型 1、标准访问控制列表 2、扩展访问控制列表 访问控制列表的处理原则 ENSP调用命令 经典案例 tip&#xff1a;RFC 1918私有地址空间 ACL的定义 ACL&#xff0c;中文名称是“访问控制列表”&#xff…

拼夕夕的拼团模式已经过时!全新拼团你可以看看!

在当前的电商格局中&#xff0c;社交电商异军突起&#xff0c;成为了市场的新宠。面对这样的趋势&#xff0c;我们的化妆品品牌必须与时俱进&#xff0c;不仅要在品牌建设和产品质量上下足功夫&#xff0c;更要在营销策略上有所创新。如今&#xff0c;价格不再是唯一的竞争武器…