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

news2024/11/20 11:48:42

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

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

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.coloradmin.cn/o/1500452.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

鞋服品牌怎样合理把控订货深度和宽度

在鞋服品牌的运营管理中&#xff0c;订货深度和宽度是两个至关重要的概念。订货深度指的是某一款式或规格的产品数量&#xff0c;而订货宽度则代表品牌所涵盖的产品种类和款式。合理把控订货深度和宽度对于品牌的库存管理、销售情况以及顾客满意度都有着深远的影响。本文将探讨…

【Linux】 yum —— Linux 的软件包管理器

Linux 的软件包管理器 yum yum 是什么什么是软件包查看软件包 yum 命令行工具yum 配置文件yum 凭什么可以支持下载呢&#xff1f;yum 生态yum 社区yum 的故障排除和资源支持yum 的持续集成和持续交付 yum 是什么 Yum&#xff08;Yellowdog Updater Modified&#xff09;是一个…

洛谷 P8816 [CSP-J 2022] 上升点列(T4)

目录 题目传送门 算法解析 最终代码 提交结果 尾声 题目传送门 [CSP-J 2022] 上升点列 - 洛谷https://www.luogu.com.cn/problem/P8816 算法解析 k 0 且 xi, yi 值域不大时&#xff0c;这题是非常简单的 DP&#xff0c;类似「数字三角形」。 记 dp(x,y) 为「以 (x,y) …

GaussDB(DWS)运维利刃:TopSQL工具解析

在生产环境中&#xff0c;难免会面临查询语句出现异常中断、阻塞时间长等突发问题&#xff0c;如果没能及时记录信息&#xff0c;事后就需要投入更多的人力及时间成本进行问题的定位和解决&#xff0c;有时还无法定位到错误出现的地方。在本期《GaussDB(DWS)运维利刃&#xff1…

Dubbo基础入门二

8、Dubbo协议 服务调用 8.1 服务端 启动过程深入分析 我们查看一下服务启动的过程 ProtocolFilterWrapper.export 好我们进入DubboProtocol.export 创建服务 分析我们的Handler 我们接着返回刚才位置 下面的super方法里面会创建服务&#xff0c;ChannelHandlers.wrap会对hand…

套接字编程 --- 一

目录 1. 预备知识 1.1. 端口号 1.2. 认识TCP协议 1.3. 认识UDP协议 1.4. 网络字节序 2. socket 2.1. socket 常见系统调用 2.1.1. socket 系统调用 2.1.2. bind 系统调用 2.1.3. recvfrom 系统调用 2.1.4. sendto系统调用 2.3. 其他相关接口 2.3.1. bzero 2.3.2…

代码随想录算法训练营第day10|232.用栈实现队列、 225. 用队列实现栈

目录 a.232.用栈实现队列 b. 225. 用队列实现栈 a.232.用栈实现队列 题目链接 请你仅使用两个栈实现先入先出队列。队列应当支持一般队列支持的所有操作&#xff08;push、pop、peek、empty&#xff09;&#xff1a; 实现 MyQueue 类&#xff1a; void push(int x) 将元素…

专题一 - 双指针 - leetcode 202. 快乐数 | 简单难度

leetcode 202. 快乐数 leetcode 202. 快乐数 | 简单难度1. 题目详情1. 原题链接2. 基础框架 2. 解题思路1. 题目分析2. 算法原理3. 时间复杂度 3. 代码实现4. 知识与收获 leetcode 202. 快乐数 | 简单难度 1. 题目详情 编写一个算法来判断一个数 n 是不是快乐数。 「快乐数」…

掼蛋的牌型与规律(上篇)

掼蛋是一项配合类的棋牌竞技游戏&#xff0c;掼蛋的最大魅力以及最集中的特点在于变化&#xff0c;在于组牌的变数。有的掼蛋新手往往先把牌配死&#xff0c;并且直接决定好出牌计划&#xff0c;然后守株待兔。掼蛋的取胜之道在于静态组合加上动态变化。本文主要介绍一下掼蛋的…

【广度优先搜索】【图论】【并集查找】2493. 将节点分成尽可能多的组

作者推荐 视频算法专题 本文涉及知识点 广度优先搜索 图论 并集查找 LeetCod2493. 将节点分成尽可能多的组 给你一个正整数 n &#xff0c;表示一个 无向 图中的节点数目&#xff0c;节点编号从 1 到 n 。 同时给你一个二维整数数组 edges &#xff0c;其中 edges[i] [ai…

神州大地人类来源猜想

在公元前2000年以前&#xff0c;伟大的中华民族还是石器时代&#xff0c;我们有很多美好的神话和传说&#xff0c;三皇五帝就是这个时代伟大部落或者部落首领的故事。 关于人类的历史&#xff0c;从基因学上最新的研究成果大概是这样的&#xff0c;虽然从300万年前就诞生了人类…

3D资产管理

3D 资产管理是指组织、跟踪、优化和分发 3D 模型和资产以用于游戏、电影、AR/VR 体验等各种应用的过程。 3D资产管理也称为3D内容管理。 随着游戏、电影、建筑、工程等行业中 3D 内容的增长&#xff0c;实施有效的资产管理工作流程对于提高生产力、减少错误、简化工作流程以及使…

Xinstall微信调起APP,提升用户体验与转化率

在移动互联网时代&#xff0c;APP已经成为人们日常生活中不可或缺的一部分。然而&#xff0c;随着市场竞争的加剧&#xff0c;如何让用户更便捷地使用APP&#xff0c;提高分享营销的下载转化率&#xff0c;成为了开发者们亟待解决的问题。今天&#xff0c;我们将向大家介绍一款…

C/C++的内存管理与初阶模板

引言 我们在学习C的时候&#xff0c;会经常在堆上申请空间&#xff0c;所以这个时候就体现了内存管理遍历。 图下是我们常见的计算机的内存划分&#xff1a; 我也在图下对部分变量存在的位置&#xff0c;及时标注。(如果有任何问题可以联系博主修改&#xff0c;感谢大家。) 那…

如何在Windows上使用Docker,搭建一款实用的个人IT工具箱It- Tools

文章目录 1. 使用Docker本地部署it-tools2. 本地访问it-tools3. 安装cpolar内网穿透4. 固定it-tools公网地址 本篇文章将介绍如何在Windows上使用Docker本地部署IT- Tools&#xff0c;并且同样可以结合cpolar实现公网访问。 在前一篇文章中我们讲解了如何在Linux中使用Docker搭…

Docker安装主从数据库

首先开启docker后直接执行命令 docker run -d \ -p 3307:3306 \ -v /xk857/mysql/master/conf:/etc/mysql/conf.d \ -v /xk857/mysql/master/data:/var/lib/mysql \ -e MYSQL_ROOT_PASSWORD123456 \ --name mysql-master \ mysql:8.0.29 默认情况下MySQL的binlog日志是自动开…

深入浅出Redis(八):Redis的集群模式

引言 Redis是一款优秀的键值对、内存非关系型数据库&#xff0c;单机节点下的Redis存在无法保证高可用、容量不足等问题 上篇文章介绍的哨兵主要能够保证主从架构下Redis的可用性&#xff0c;但是仍然存在容量不足、推举新的主节点时不能访问Redis的问题&#xff0c;集群可水…

#QT(串口助手-界面)

1.IDE&#xff1a;QTCreator 2.实验&#xff1a;编写串口助手 3.记录 接收框:Plain Text Edit 属性选择&#xff1a;Combo Box 发送框:Line Edit 广告&#xff1a;Group Box &#xff08;1&#xff09;仿照现有串口助手设计UI界面 &#xff08;2&#xff09;此时串口助手大…

ai脚本创作的软件有哪些?分享3款好用的工具!

随着人工智能技术的飞速发展&#xff0c;AI脚本创作软件已经成为内容创作者们的新宠。这些软件不仅能够帮助我们更高效地生成文章、视频脚本等&#xff0c;还能为我们提供独特的创意视角和无限的灵感。本文将带您深入了解几款备受瞩目的AI脚本创作软件&#xff0c;看看它们如何…

带胶囊按钮的标题是如何实现的

使用uni-app开发小程序经常会遇到胶囊按钮和标题之间融合的问题&#xff0c;因为这样可以大大提高页面的美观和整体性&#xff0c;那么接下来简单拆分步骤看下是如何实现的吧 &#x1f601; 可以看到我们设置的标题是在默认标题栏之下的&#xff08;这不是我们想要的效果 &…