【PCL】教程conditional_euclidean_clustering 对输入的点云数据进行条件欧式聚类分析...

4ccccfc0f1340a58f60cb5daa0910890.png

[done, 3349.09 ms : 19553780 points]
Available dimensions: x y z intensity

源点云 Statues_4.pcd

becdbc15ee6f90f59ee3d380a39ba4fd.png

6afaafb5d309c2c0ce8965a184a6e045.png

d71f85639ee5bbf01816308d978fc890.png

a6983c7961f920447409c866299c9d76.png

不同条件函数output.pcd 【按5切换到强度通道可视化】

终端输出:

Loading...
>> Done: 1200.46 ms, 19553780 points
Downsampling...
>> Done: 411.366 ms, 202529 points
Computing normals...
>> Done: 717.815 ms
Segmenting to clusters...
>> Done: 1616.51 ms
Saving...
>> Done: 590.647 ms

点云下载:

https://sourceforge.net/projects/pointclouds/files/PCD%20datasets/Trimble/Outdoor1/

源码解析:

6bb52c40003fdd5c081be3262e0ec3ce.png

#include <pcl/point_types.h> // 包含PCL库中点云类型的头文件
#include <pcl/io/pcd_io.h> // 包含PCL库中用于点云读写的头文件
#include <pcl/console/time.h> // 包含PCL库中用于计时的头文件#include <pcl/filters/voxel_grid.h> // 包含PCL库中体素栅格滤波器的头文件
#include <pcl/features/normal_3d.h> // 包含PCL库中用于计算点云中点的法向量的头文件
#include <pcl/segmentation/conditional_euclidean_clustering.h> // 包含PCL库中条件欧几里得聚类算法的头文件typedef pcl::PointXYZI PointTypeIO; // 定义带有强度信息的3D点类型
typedef pcl::PointXYZINormal PointTypeFull; // 定义带有强度和法线信息的3D点类型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); // 如果两个点的强度相差小于5,认为它们相似elsereturn (false);
}bool
enforceNormalOrIntensitySimilarity2(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 (fabs(point_a.intensity - point_b.intensity) < 5.0f) // 如果a点的密度-b点的密度<5return (true);if (fabs(point_a_normal.dot(point_b_normal)) < 0.05) // 如果a点法线估计return (true);return (false);
}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); // 如果强度相差小于5,认为相似if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI)))return (true); // 如果法线方向的夹角小于30度,也认为相似return (false);
}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) // 距离小于10000{if (std::abs (point_a.intensity - point_b.intensity) < 8.0f) // 强度相差小于8return (true);if (std::abs (point_a_normal.dot (point_b_normal)) > std::cos (30.0f / 180.0f * static_cast<float> (M_PI))) // 法线夹角小于30度return (true);}else{if (std::abs (point_a.intensity - point_b.intensity) < 3.0f) // 距离大于10000时,强度相差小于3return (true);}return (false);
}int
main ()
{// 用于存储点云的数据容器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>); // Kd树搜索方法pcl::console::TicToc tt; // 用于计时// 加载输入的点云std::cerr << "Loading...\n", tt.tic ();pcl::io::loadPCDFile ("Statues_4.pcd", *cloud_in);std::cerr << ">> Done: " << tt.toc () << " ms, " << cloud_in->size () << " points\n";// 使用体素栅格类下采样点云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";// 设置法线估计类并合并数据到包含法线的点云中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); // 设置搜索方法为Kd树ne.setRadiusSearch (300.0); // 设置法线估计时的搜索半径为300.0ne.compute (*cloud_with_normals); // 计算输入点云的每个点的法线,并将结果存储到带有法线信息的点云容器中std::cerr << ">> Done: " << tt.toc () << " ms\n";// 设置条件欧几里得聚类类std::cerr << "Segmenting to clusters...\n", tt.tic ();pcl::ConditionalEuclideanClustering<PointTypeFull> cec (true);cec.setInputCloud (cloud_with_normals);cec.setConditionFunction (&customRegionGrowing); // 设置条件函数cec.setClusterTolerance (500.0); // 设置聚类容忍度cec.setMinClusterSize (cloud_with_normals->size () / 1000); // 设置最小聚类大小cec.setMaxClusterSize (cloud_with_normals->size () / 5); // 设置最大聚类大小cec.segment (*clusters); // 执行聚类cec.getRemovedClusters (small_clusters, large_clusters); // 获取移除的聚类结果std::cerr << ">> Done: " << tt.toc () << " ms\n";// 使用强度通道进行简单的可视化输出for (const auto& small_cluster : (*small_clusters))for (const auto& j : small_cluster.indices)(*cloud_out)[j].intensity = -2.0; // 较小的聚类强度设置为-2for (const auto& large_cluster : (*large_clusters))for (const auto& j : large_cluster.indices)(*cloud_out)[j].intensity = +10.0; // 较大的聚类强度设置为+10for (const auto& cluster : (*clusters)){int label = rand () % 8; // 为每个聚类随机分配一个标签for (const auto& j : cluster.indices)(*cloud_out)[j].intensity = label; // 设置对应的强度值}// 保存输出的点云std::cerr << "Saving...\n", tt.tic ();pcl::io::savePCDFile ("output.pcd", *cloud_out);std::cerr << ">> Done: " << tt.toc () << " ms\n";return (0);
}

这段代码使用了PCL(Point Cloud Library)库,其主要的功能是对输入的点云数据进行条件欧式聚类分析

主要步骤如下:

  1. 使用pcl::VoxelGrid类进行下采样:将输入点云的密度降低,用于提高后续操作的效率。这通过指定立方体体素的边长(80.0),将点云中处于同一立方体体素内的所有点替换为他们的质心。

  2. 计算点云中每一个点的法线:使用pcl::NormalEstimation类计算每一个点的法线,这将作为后续操作的一部分使用。setRadiusSearch用于指定查找近邻的半径。

  3. 使用pcl::ConditionalEuclideanClustering类进行条件欧式聚类:在这个过程中,每一个点都会被放入一个特定的群组(也就是聚类)。算法会根据定义的距离容忍度(在本代码中为500)和自定义的函数customRegionGrowing来确定点是否应属于当前的聚类。所定义的函数中,需要注意的是,据点之间的强度差异(小于8)和点法线之间的角度(小于或等于30度),或者强度差异小于3的情况下,两点可以被视为同一聚类。聚类的最大和最小大小也被定义为输入点的数量的五分之一和千分之一。

  4. 对每个生成的聚类(条件欧式聚类)进行可视化处理:通过将不同聚类的点置为不同强度来区分它们。此处,较小的聚类将被设置为强度-2,较大的聚类将被设置为强度+10

  5. 保存处理后的点云数据,以便于后续的分析和处理。

在这段代码中,定义了四个自定义函数(enforceIntensitySimilarityenforceNormalOrIntensitySimilaritycustomRegionGrowing),这些函数被用作聚类过程中的条件函数,以便在决定如何聚类点时,可以根据强度和法线等属性进行更精细控制。

4e090a6f08554fc5cb78620f18af7f4c.png

踩坑笔记

6c9a75c1b628ea12e1833e148164c97d.png

dfaf11a3e73dacf2d3697d30df22cf72.png

预处理器添加:PCL_NO_PRECOMPILE

31d5211f137d5098c3c9ef898fbe5632.png

添加flann.lib

pcl::console::TicToc

0d6ab198a78d1dd0b671878185ce77d4.png

pcl::NormalEstimation<PointTypeIO, PointTypeFull> ne;

693a3a70100ba8531a2f39f5796ee293.png

#include <pcl/point_types.h>
#include <pcl/features/normal_estimation.h>
#include <pcl/io/pcd_io.h>
#include <pcl/kdtree/kdtree_flann.h>int main() {// 加载点云pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);pcl::io::loadPCDFile("inputCloud.pcd", *cloud);// 创建法线估计对象pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;ne.setInputCloud(cloud);// 创建一个空的kdtree表示,并将其设置为法线估计对象的搜索方法pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());ne.setSearchMethod(tree);// 设置邻居搜索的参数ne.setKSearch(20);// 计算法线pcl::PointCloud<pcl::Normal>::Ptr cloud_normals(new pcl::PointCloud<pcl::Normal>);ne.compute(*cloud_normals);// cloud_normals 现在包含输入点云的法线
}
计算结果存储在之前复制的带有法线信息的点云数据结构中时,不会覆盖点坐标吗?

8c5e001a13d49d6dc137dd2e0216fa86.png

pcl::ConditionalEuclideanClustering<PointTypeFull>

214049c17df997361757038f0e493685.png

cec.getRemovedClusters (small_clusters, large_clusters);

28a568abf941fa4263ed7fda5c94757b.png

点云类型

c796b1c15f506c8be937630527c1b6ad.png

5eeca695efe9106c90ea257a3d846353.png

a1fce39f71222aa9dc0a0a3bf09dd8d3.png

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/pingmian/1188.shtml

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

相关文章

学习BOM

目录 前言: 1. BOM组成&#xff1a; 1.1Window 对象&#xff1a; 1.1Location 对象&#xff1a; 1.2Navigator 对象&#xff1a; 1.2.1 navigator 对象包含了关于浏览器的信息包括&#xff1a; 1.3History 对象&#xff1a; 1.4常用的history的方法和属性: 1.4Document…

力扣-LCP 02.分式化简

题解&#xff1a; class Solution:def fraction(self, cont: List[int]) -> List[int]:# 初始化分子和分母为 0 和 1n, m 0, 1# 从最后一个元素开始遍历 cont 列表for a in cont[::-1]:# 更新分子和分母&#xff0c;分别为 m 和 (m * a n)n, m m, (m * a n)# 返回最终的…

大型网站系统架构演化实例_9.分布式服务

1. 第十阶段&#xff1a;分布式服务 随着业务拆分越来越小&#xff0c;存储系统越来越庞大&#xff0c;应用系统的整体复杂度呈指数级增加&#xff0c;部署维护越来越困难。由于所有应用要和所有数据库系统连接&#xff0c;在数万台服务器规模的网站中&#xff0c;这些连接的数…

计算机网络 -- 多人聊天室

一 程序介绍和核心功能 这是基于 UDP 协议实现的一个网络程序&#xff0c;主要功能是 构建一个多人聊天室&#xff0c;当某个用户发送消息时&#xff0c;其他用户可以立即收到&#xff0c;形成一个群聊。 这个程序由一台服务器和n个客户端组成&#xff0c;服务器扮演了一个接受…

[Kubernetes] etcd的集群基石作用

文章目录 1. 配置存储2. 数据一致性3. 服务发现与协调4. 集群状态中枢5. 集群稳定性 1. 配置存储 etcd作为一个高度可靠的分布式键值存储系统&#xff0c;存储了Kubernetes集群的完整配置和状态数据。集群的元数据&#xff0c;包括节点信息、命名空间、部署、副本集、服务、持…

5.11 mybatis之returnInstanceForEmptyRow作用

文章目录 1. 当returnInstanceForEmptyRowtrue时2 当returnInstanceForEmptyRowfalse时 mybatis的settings配置中有个属性returnInstanceForEmptyRow&#xff0c;该属性新增于mybatis的3.4.2版本&#xff0c;低于此版本不可用。该属性的作用官方解释为&#xff1a;当返回行的所…

使用Python+opencv实现自动扫雷

大家好&#xff0c;相信许多人很早就知道有扫雷这么一款经典的游戏&#xff0c;更是有不少人曾听说过中国雷圣&#xff0c;也是中国扫雷第一、世界综合排名第二的郭蔚嘉的顶顶大名。扫雷作为一款在Windows9x时代就已经诞生的经典游戏&#xff0c;从过去到现在依然都有着它独特的…

汽车4S集团数据分析

派可数据分析--汽车4S集团。 派可数据汽车4S集团数据分析概述。派可数据汽车4S集团分析主题全面涵盖行业内各板块业务分析&#xff0c;具体包括&#xff1a;保险业务分析、客户关系分析、汽车保养情况分析、售后维修主题分析、整车销售分析、整车库存分析、装具销售分析、配件…

dbearver达梦连接

1、新建达梦驱动 新建驱动管理器 点击“数据库”&#xff0c;选择“驱动管理器” 配置 点击“新建”&#xff0c;出现配置界面 类名&#xff1a;dm.jdbc.driver.DmDriver #固定值&#xff0c;不能修改URL模板&#xff1a;jdbc:dm://{host}/DMHR #配置要连接的数据库信息默认…

【VIC水文模型】准备工作:平台软件安装

VIC水文模型所需平台软件安装 1 Arcgis安装2 Cygwin安装&#xff08;Linux系统&#xff09;3 Matlab/R/Fortran的安装Notepad 4 VIC模型程序代码获取参考 由于VIC模型的编程语言为C语言&#xff0c;交互方式为控制台输指令&#xff0c;需要在Linux系统上运行。Windows 上使用 …

Https网站接口被黑被恶意调取

背景&#xff1a; 维护的一个网站最近短信接口被黑&#xff0c;发送大量短信。起初以为是在网站内部操作&#xff0c;优化了发送短信前的操作&#xff0c;如添加图形验证码&#xff0c;屏蔽国外IP等。但后续还存在被调取情况&#xff0c;定位排查到是该接口在外部被恶意调取。 …

免费使用ChatGPT 4.0 和 文心一言 4.0

前言 今天给大家分享如何免费使用ChatGPT4.0 和 文心一言 4.0&#xff0c;废话就不多说了&#xff0c;我们直接入正题。 ChatGPT 4.0 先来看看如何免费使用ChatGPT 4.0 进入Coze登录 https://www.coze.com 选择大圣-GPT-4 文心一言 4.0 通过文心智能体平台&#xff0c;就…

Java 笔记 03:Java 基础知识,使用 IDEA 创建 Java 项目、设置注释颜色,以及自动生成 JavaDoc

一、前言 记录时间 [2024-04-21] 系列文章简摘&#xff1a; Java 笔记 01&#xff1a;Java 概述&#xff0c;MarkDown 常用语法整理 Java 笔记 02&#xff1a;Java 开发环境的搭建&#xff0c;IDEA / Notepad / JDK 安装及环境配置&#xff0c;编写第一个 Java 程序 本文讲述了…

OJ:数字三角形(搜索)

&#x1f381;个人主页&#xff1a;我们的五年 &#x1f50d;系列专栏&#xff1a;每日一练 &#x1f337;追光的人&#xff0c;终会万丈光芒 &#x1f337;1.问题描述&#xff1a; ⛳️题目描述&#xff1a; 示出了一个数字三角形。 请编一个程序计算从顶至底的某处的一条路…

对接浦发银行支付(六)-- 请求退款接口与查询退款结果接口

一、概述 本文介绍浦发银行支付的请求退款和查询退款结果两个接口&#xff0c;浦发银行的退款流水号是以5901开头。发起退款的时候&#xff0c;浦发银行返回浦发银行退款流水号给我们&#xff08;这里的我们是指对接浦发银行支付的一方&#xff0c;于浦发银行而言&#xff0c;…

面向对象设计模式之概念

设计模式系列的观点结合了《HeadFirst设计模式》(中文版)以及《设计模式&#xff1a;可复用面向对象软件的基础》两本书的知识&#xff0c;以及Sunny(刘伟)的博客 《HeadFirst设计模式》(中文版)&#xff1a; 百度网盘链接&#xff1a;https://pan.baidu.com/s/1osvnUGZZREm8Jb…

「GO基础」变量

&#x1f49d;&#x1f49d;&#x1f49d;欢迎莅临我的博客&#xff0c;很高兴能够在这里和您见面&#xff01;希望您在这里可以感受到一份轻松愉快的氛围&#xff0c;不仅可以获得有趣的内容和知识&#xff0c;也可以畅所欲言、分享您的想法和见解。 推荐:「stormsha的主页」…

python-自动化篇-终极工具-用GUI自动控制键盘和鼠标-pyautogui-键盘

文章目录 键盘键盘——记忆宫殿入门——通过键盘发送一个字符串——typewrite()常规——键名——typewrite()常规——按下键盘——keyDown()常规——释放键盘——keyUp()升级——热键组合——hotkey() 键盘 pyautogui也有一些函数向计算机发送虚拟按键&#xff0c;让你能够填充…

【介绍下WebStorm开发插件】

&#x1f3a5;博主&#xff1a;程序员不想YY啊 &#x1f4ab;CSDN优质创作者&#xff0c;CSDN实力新星&#xff0c;CSDN博客专家 &#x1f917;点赞&#x1f388;收藏⭐再看&#x1f4ab;养成习惯 ✨希望本文对您有所裨益&#xff0c;如有不足之处&#xff0c;欢迎在评论区提出…

深入了解PBKDF2:密码学中的关键推导函数

title: 深入了解PBKDF2&#xff1a;密码学中的关键推导函数 date: 2024/4/20 20:37:35 updated: 2024/4/20 20:37:35 tags: 密码学对称加密哈希函数KDFPBKDF2安全密钥派生 第一章&#xff1a;密码学基础 对称加密和哈希函数 对称加密&#xff1a;对称加密是一种加密技术&…