【PCL】Segmentation 模块—— 欧几里得聚类提取(Euclidean Cluster Extraction)
1、简介
PCL 的 Euclidean Cluster Extraction(欧几里得聚类提取) 是一种基于欧几里得距离的点云聚类算法。它的目标是将点云数据分割成多个独立的簇(clusters),每个簇代表一个独立的物体或结构。该算法通过计算点与点之间的欧几里得距离,将距离小于给定阈值的点归为同一个簇。
1.1 欧几里得聚类提取的原理
-
基于距离的聚类:
- 算法通过计算点云中每个点与其邻近点之间的欧几里得距离来判断它们是否属于同一个簇。
- 如果两个点之间的距离小于设定的阈值(
ClusterTolerance),则认为它们属于同一个簇。
-
使用 KdTree 加速搜索:
- 为了高效地查找每个点的邻近点,算法使用 KdTree 数据结构来组织点云数据。
- KdTree 是一种空间划分数据结构,可以快速找到某个点附近的点。
-
聚类条件:
- 每个簇需要满足一定的点数范围:
- 最小点数(
MinClusterSize):少于该点数的簇会被丢弃。 - 最大点数(
MaxClusterSize):超过该点数的簇会被分割或丢弃。
- 最小点数(
- 每个簇需要满足一定的点数范围:
1.2 PCL 中 EuclideanClusterExtraction 的关键参数
在 PCL 中,pcl::EuclideanClusterExtraction 类用于实现欧几里得聚类提取。以下是其关键参数:
-
setClusterTolerance:- 设置聚类的距离阈值。
- 例如,
setClusterTolerance(0.02)表示两点之间的距离小于 2cm 时,它们属于同一个簇。
-
setMinClusterSize:- 设置每个簇的最小点数。
- 例如,
setMinClusterSize(100)表示点数少于 100 的簇会被丢弃。
-
setMaxClusterSize:- 设置每个簇的最大点数。
- 例如,
setMaxClusterSize(25000)表示点数超过 25000 的簇会被分割或丢弃。
-
setSearchMethod:- 设置用于搜索邻近点的数据结构,通常是 KdTree。
- 例如,
setSearchMethod(tree),其中tree是一个 KdTree 对象。
-
setInputCloud:- 设置输入的点云数据。
-
extract:- 执行聚类提取,结果存储在
std::vector<pcl::PointIndices>中,每个pcl::PointIndices表示一个簇。
- 执行聚类提取,结果存储在
1.3 欧几里得聚类提取的步骤
-
构建 KdTree:
- 使用点云数据构建 KdTree,以便快速查找邻近点。
-
遍历点云:
- 遍历点云中的每个点,找到其邻近点。
- 如果邻近点与当前点的距离小于阈值,则将它们归为同一个簇。
-
递归扩展簇:
- 对于每个邻近点,继续查找其邻近点,直到没有新的点可以加入当前簇。
-
过滤簇:
- 根据设定的最小点数和最大点数,过滤掉不符合条件的簇。
-
输出结果:
- 将每个簇的点云索引存储在
std::vector<pcl::PointIndices>中。
- 将每个簇的点云索引存储在
2、代码示例
2.1 cluster_extraction.cpp
这段代码适用于处理3D点云数据,特别是在场景中分割平面和物体的应用中,代码主要包括点云的读取、滤波、平面分割、聚类以及保存聚类结果等步骤:
#include <pcl/ModelCoefficients.h>
#include <pcl/point_types.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/features/normal_3d.h>
#include <pcl/search/kdtree.h>
#include <pcl/sample_consensus/method_types.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
#include <iomanip> // for setw, setfillint
main ()
{// 读取点云数据pcl::PCDReader reader;pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>), cloud_f (new pcl::PointCloud<pcl::PointXYZ>);reader.read ("table_scene_lms400.pcd", *cloud);std::cout << "PointCloud before filtering has: " << cloud->size () << " data points." << std::endl; // 输出滤波前的点云数量// 创建滤波对象:使用1cm的叶子大小对数据集进行下采样pcl::VoxelGrid<pcl::PointXYZ> vg;pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered (new pcl::PointCloud<pcl::PointXYZ>);vg.setInputCloud (cloud);vg.setLeafSize (0.01f, 0.01f, 0.01f);vg.filter (*cloud_filtered);std::cout << "PointCloud after filtering has: " << cloud_filtered->size () << " data points." << std::endl; // 输出滤波后的点云数量// 创建平面模型的分割对象并设置所有参数pcl::SACSegmentation<pcl::PointXYZ> seg;pcl::PointIndices::Ptr inliers (new pcl::PointIndices);pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_plane (new pcl::PointCloud<pcl::PointXYZ> ());pcl::PCDWriter writer;seg.setOptimizeCoefficients (true);seg.setModelType (pcl::SACMODEL_PLANE);seg.setMethodType (pcl::SAC_RANSAC);seg.setMaxIterations (100);seg.setDistanceThreshold (0.02);int nr_points = (int) cloud_filtered->size ();while (cloud_filtered->size () > 0.3 * nr_points){// 从剩余的点云中分割出最大的平面组件seg.setInputCloud (cloud_filtered);seg.segment (*inliers, *coefficients);if (inliers->indices.size () == 0){std::cout << "Could not estimate a planar model for the given dataset." << std::endl;break;}// 从输入点云中提取平面内点pcl::ExtractIndices<pcl::PointXYZ> extract;extract.setInputCloud (cloud_filtered);extract.setIndices (inliers);extract.setNegative (false);// 获取与平面表面相关的点extract.filter (*cloud_plane);std::cout << "PointCloud representing the planar component: " << cloud_plane->size () << " data points." << std::endl;// 移除平面内点,提取剩余点extract.setNegative (true);extract.filter (*cloud_f);*cloud_filtered = *cloud_f;}// 为提取方法创建KdTree对象pcl::search::KdTree<pcl::PointXYZ>::Ptr tree (new pcl::search::KdTree<pcl::PointXYZ>);tree->setInputCloud (cloud_filtered);std::vector<pcl::PointIndices> cluster_indices;pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;ec.setClusterTolerance (0.02); // 2cmec.setMinClusterSize (100);ec.setMaxClusterSize (25000);ec.setSearchMethod (tree);ec.setInputCloud (cloud_filtered);ec.extract (cluster_indices);int j = 0;for (const auto& cluster : cluster_indices){pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_cluster (new pcl::PointCloud<pcl::PointXYZ>);for (const auto& idx : cluster.indices) {cloud_cluster->push_back((*cloud_filtered)[idx]);} // 将聚类中的点添加到新的点云中cloud_cluster->width = cloud_cluster->size ();cloud_cluster->height = 1;cloud_cluster->is_dense = true;std::cout << "PointCloud representing the Cluster: " << cloud_cluster->size () << " data points." << std::endl;std::stringstream ss;ss << std::setw(4) << std::setfill('0') << j;writer.write<pcl::PointXYZ> ("cloud_cluster_" + ss.str () + ".pcd", *cloud_cluster, false); // 保存聚类结果到PCD文件j++;}return (0);
}
2.2 主要步骤:
- 读取点云数据:从PCD文件中读取点云数据,并输出点云的数量。
- 滤波:使用VoxelGrid滤波器对点云进行下采样,减少点云的数量,同时保持点云的形状。
- 平面分割:使用RANSAC算法从点云中分割出最大的平面组件,并提取出平面内点。
- 移除平面内点:将平面内点从点云中移除,保留剩余的点云。
- 聚类:使用欧几里得聚类算法对剩余的点云进行聚类,将点云分割成多个簇。
- 保存聚类结果:将每个聚类结果保存为单独的PCD文件。
2.3 关键点:
- VoxelGrid滤波:通过设置叶子大小(
setLeafSize)来控制下采样的精度。 - RANSAC平面分割:通过设置最大迭代次数(
setMaxIterations)和距离阈值(setDistanceThreshold)来控制平面分割的精度。 - 欧几里得聚类:通过设置聚类容差(
setClusterTolerance)、最小聚类大小(setMinClusterSize)和最大聚类大小(setMaxClusterSize)来控制聚类的效果。
2.4 CMakeLists.txt
cmake_minimum_required(VERSION 3.5 FATAL_ERROR)project(cluster_extraction)find_package(PCL 1.2 REQUIRED)include_directories(${PCL_INCLUDE_DIRS})
link_directories(${PCL_LIBRARY_DIRS})
add_definitions(${PCL_DEFINITIONS})add_executable (${PROJECT_NAME} cluster_extraction.cpp)
target_link_libraries (${PROJECT_NAME} ${PCL_LIBRARIES})
3、运行结果
- 编译
mkdir build && cd build
cmake ..
make
- 运行
./cluster_extraction
./cluster_extraction
PointCloud before filtering has: 460400 data points.
PointCloud after filtering has: 41049 data points.
PointCloud representing the planar component: 20536 data points.
PointCloud representing the planar component: 12442 data points.
PointCloud representing the Cluster: 4857 data points.
PointCloud representing the Cluster: 1386 data points.
PointCloud representing the Cluster: 321 data points.
PointCloud representing the Cluster: 291 data points.
PointCloud representing the Cluster: 123 data points.
-
保存提取到的点云文件

-
点云源文件
table_scene_lms400.pcd

-
点云提取后

相关文章:
【PCL】Segmentation 模块—— 欧几里得聚类提取(Euclidean Cluster Extraction)
1、简介 PCL 的 Euclidean Cluster Extraction(欧几里得聚类提取) 是一种基于欧几里得距离的点云聚类算法。它的目标是将点云数据分割成多个独立的簇(clusters),每个簇代表一个独立的物体或结构。该算法通过计算点与点…...
LuaJIT Garbage Collector Algorithms
Explain 本篇文章是对Make Pall发表wili内容《LuaJIT 3.0 new Garbage Collector》的翻译和扩展,因为原文是对LuaJIT 2.x GC重要功能的简介和对LuaJIT 3.0 new GC的工作计划,所以它并不是系统性介绍GC的文章。希望以后能有精力系统性的对LuaJIT 2.x GC做…...
go采集注册表
package mainimport ("fmt""golang.org/x/sys/windows/registry""log""os""strconv""strings" )func USBSTOR_Enum() {// 打开注册表键keyPath : SYSTEM\CurrentControlSet\Services\USBSTOR\Enumk, err : regist…...
软件工程师欧以宁:引领无人机导航与物联网安全的技术革新
在科技日新月异的今天,软件工程师欧以宁凭借卓越的技术能力和前瞻性的创新思维,成为了无人机自主导航和物联网安全领域的佼佼者。作为一名深耕技术前沿的专家,欧以宁不仅推动了无人机导航技术的突破性进展,还为智能家居和物联网的安全架构提供了全新的解决方案。她的研究成果,以…...
从零开始:Gitee 仓库创建与 Git 配置指南
引言 Git 是一款广泛使用的版本控制工具,它能够帮助开发者在开发过程中高效地管理代码的版本。而 Gitee(码云)是国内知名的 Git 托管平台,它提供了强大的代码托管、团队协作和项目管理功能。如果你是 Git 和 Gitee 的新手&#x…...
浅谈计算机网络02 | SDN控制平面
计算机网络控制平面 一、现代计算机网络控制平面概述1.1 与数据平面、管理平面的关系1.2 控制平面的发展历程 二、控制平面的关键技术剖析2.1 网络层协议2.1.1 OSPF协议2.1.2 BGP协议 2.2 SDN控制平面技术2.2.1 SDN架构与原理2.2.2 OpenFlow协议2.2.3 SDN控制器 一、现代计算机…...
在 QNAP NAS中使用 Container Station 运行 Docker 的完整指南
QNAP 为用户提供了一个名为 Container Station 的应用,它在 QNAP NAS 上将 Docker 和 LXC 结合在一起,通过图形化界面,让用户更轻松地在 NAS 上管理容器。本文将带你一步步了解如何在 QNAP NAS 上安装和使用 Container Station,以…...
XML在线格式化 - 加菲工具
XML在线格式化 打开网站 加菲工具 选择“XML 在线格式化” 输入XML,点击左上角的“格式化”按钮 得到格式化后的结果...
大数据学习(34)-mapreduce详解
&&大数据学习&& 🔥系列专栏: 👑哲学语录: 承认自己的无知,乃是开启智慧的大门 💖如果觉得博主的文章还不错的话,请点赞👍收藏⭐️留言📝支持一下博主哦ᾑ…...
代码合并冲突解决push不上去的问题
环境:【IntelliJ IDEA】 【Gerrit】 1、错误信息 代码合并,迭代1合并到迭代2,解决冲突后,依然push不上去,报错信息如下: remote: Processing changes: refs: 1 remote: Processing changes: refs…...
万字长文介绍ARINC 653,以及在综合模块化航空电子设备(IMA)中的作用
文章目录 一、引言二、ARINC 653背景三、整体系统架构四、应用/执行(APEX)接口五、ARINC 653 RTOS内部机制六、健康监测功能七、软件应用八、ARINC 653现状九、总结 一、引言 在现代航空领域,综合模块化航空电子设备(IMA…...
MySQL 与 Redis 数据一致性 2
1. 强一致还是最终一致?2. 先写 MySQL 还是先写Redis?case 1 3. 缓存(Redis)更新还是清除?更新策略更新策略会有数据不一致问题?数据不一致的概率与影响如果使用监听binlog更新数据还会出现数据不一致问题?binlog的消费问题 使用消息队列行不行?其他方案总结: 数据不一致…...
MySQL程序之:使用类似URI的字符串或键值对连接到服务器
本节介绍使用类似URI的连接字符串或键值对来指定如何为MySQLShell等客户端建立到MySQL服务器的连接。 以下MySQL客户端支持使用类似URI的连接字符串或键值对连接到MySQL服务器: MySQL Shell实现X DevAPI的MySQL连接器 本节记录了所有有效的类似URI的字符串和键值…...
Docker私有仓库管理工具Registry
Docker私有仓库管理工具Registry 1 介绍 Registry是私有Docker仓库管理工具,Registry没有可视化管理页面和完备的管理策略。可借助Harbor、docker-registry-browser完成可视化和管理。Harbor是由VMware开发的企业级Docker registry服务。docker-registry-browser是…...
若依前后端分离项目部署(使用docker)
文章目录 一、搭建后端1.1 搭建流程:1.2 后端零件:1.2.1 mysql容器创建:1.2.2 redis容器创建:1.2.3 Dockerfile内容:1.2.4 构建项目镜像:1.2.5 创建后端容器: 二、前端搭建:2.1 搭建流程&#x…...
Unity2021.3.13崩溃的一种情况
如果出现如下的报错,可能是软件冲突的原因。自己的原因是使用f.lux这款软件似乎和Unity相互冲突,出现下面报错。 错误信息如上图...
Temp123
MapDB:的持久化机制,以及源码分析和摘取 1、spark streaming--struct streaming 基于 时间间隔 攒批 2、kafka-connect-hdfs 控制 flush.size 和 interval.ms控制 攒批 - 完全自研 攒批机制 - 使用 embeded 版 https://lxblog.com/qianwen/share?shar…...
春秋杯-WEB
SSTI 可以看到主页那里有个登录测试之后为ssti {{4*4}} fenjing梭哈即可得到payload {{((g.pop.__globals__.__builtins__.__import__(os)).popen(cat flag)).read()}}file_copy 看到题目名字为file_copy, 当输入路径时会返回目标文件的大小, 通…...
JavaEE:多线程初阶
JavaEE:多线程初阶 一、线程的原理和进程与线程之间的关系1. 线程的原理线程的基本概念线程的生命周期线程的调度线程的并发与并行 2. 进程与线程的关系进程(Process)线程与进程的关系进程和线程的对比线程的优势线程的缺点 3. 总结 二、多线…...
Linux之文件系统前世今生(一)
Linux在线1 Linux在线2 一、 基本概念 1.1 块(Block) 在计算机存储之图解机械硬盘这篇文章中我们提到过,磁盘读写的最小单位是扇区,也就是 512 Byte;很明显,每次读写的效率非常低。 为了提高IO效率&…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
Nuxt.js 中的路由配置详解
Nuxt.js 通过其内置的路由系统简化了应用的路由配置,使得开发者可以轻松地管理页面导航和 URL 结构。路由配置主要涉及页面组件的组织、动态路由的设置以及路由元信息的配置。 自动路由生成 Nuxt.js 会根据 pages 目录下的文件结构自动生成路由配置。每个文件都会对…...
GitHub 趋势日报 (2025年06月08日)
📊 由 TrendForge 系统生成 | 🌐 https://trendforge.devlive.org/ 🌐 本日报中的项目描述已自动翻译为中文 📈 今日获星趋势图 今日获星趋势图 884 cognee 566 dify 414 HumanSystemOptimization 414 omni-tools 321 note-gen …...
LLM基础1_语言模型如何处理文本
基于GitHub项目:https://github.com/datawhalechina/llms-from-scratch-cn 工具介绍 tiktoken:OpenAI开发的专业"分词器" torch:Facebook开发的强力计算引擎,相当于超级计算器 理解词嵌入:给词语画"…...
在鸿蒙HarmonyOS 5中使用DevEco Studio实现录音机应用
1. 项目配置与权限设置 1.1 配置module.json5 {"module": {"requestPermissions": [{"name": "ohos.permission.MICROPHONE","reason": "录音需要麦克风权限"},{"name": "ohos.permission.WRITE…...
ABAP设计模式之---“简单设计原则(Simple Design)”
“Simple Design”(简单设计)是软件开发中的一个重要理念,倡导以最简单的方式实现软件功能,以确保代码清晰易懂、易维护,并在项目需求变化时能够快速适应。 其核心目标是避免复杂和过度设计,遵循“让事情保…...
HarmonyOS运动开发:如何用mpchart绘制运动配速图表
##鸿蒙核心技术##运动开发##Sensor Service Kit(传感器服务)# 前言 在运动类应用中,运动数据的可视化是提升用户体验的重要环节。通过直观的图表展示运动过程中的关键数据,如配速、距离、卡路里消耗等,用户可以更清晰…...
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材)
推荐 github 项目:GeminiImageApp(图片生成方向,可以做一定的素材) 这个项目能干嘛? 使用 gemini 2.0 的 api 和 google 其他的 api 来做衍生处理 简化和优化了文生图和图生图的行为(我的最主要) 并且有一些目标检测和切割(我用不到) 视频和 imagefx 因为没 a…...
逻辑回归暴力训练预测金融欺诈
简述 「使用逻辑回归暴力预测金融欺诈,并不断增加特征维度持续测试」的做法,体现了一种逐步建模与迭代验证的实验思路,在金融欺诈检测中非常有价值,本文作为一篇回顾性记录了早年间公司给某行做反欺诈预测用到的技术和思路。百度…...
2025年低延迟业务DDoS防护全攻略:高可用架构与实战方案
一、延迟敏感行业面临的DDoS攻击新挑战 2025年,金融交易、实时竞技游戏、工业物联网等低延迟业务成为DDoS攻击的首要目标。攻击呈现三大特征: AI驱动的自适应攻击:攻击流量模拟真实用户行为,差异率低至0.5%,传统规则引…...
