PCL点云按指定方向进行聚类(指定类的宽度)
需指定方向和类的宽度。测试代码如下:
#include <iostream>
#include <fstream>
#include <vector>
#include <string>
#include <pcl/point_types.h>
#include <pcl/point_cloud.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/common/centroid.h> // 新增质心计算头文件
#include <pcl/common/common.h> //类型定义简化
typedef pcl::PointXYZ PointT;
typedef pcl::PointCloud<PointT> PointCloudT;/*** @brief 沿Z轴方向聚类点云,限制每类在Z轴的长度不超过thresh* @param cloud 输入点云* @param thresh Z轴方向的最大允许长度* @return 聚类结果的索引集合*/
std::vector<pcl::PointIndices> axisAlignedClustering(Eigen::Vector3f direction,const PointCloudT::Ptr& cloud, float thresh)
{std::vector<pcl::PointIndices> clusters;if (cloud->empty()) return clusters;auto p0 = cloud->points[0];direction.normalize();
auto project_dist = [&direction, &p0](PointT& p){return direction.dot(Eigen::Vector3f(p.x - p0.x, p.y - p0.y, p.z - p0.z));};std::vector<int> indices(cloud->size());for (int i = 0; i < indices.size(); ++i) indices[i] = i;std::sort(indices.begin(), indices.end(), [&](int a, int b) {return project_dist(cloud->points[a]) < project_dist(cloud->points[b]);});//2. 滑动窗口分割pcl::PointIndices current_cluster;float start_z = project_dist(cloud->points[indices[0]]);//cloud->points[indices[0]].z;current_cluster.indices.push_back(indices[0]);for (size_t i = 1; i < indices.size(); ++i) {float current_z = project_dist(cloud->points[indices[i]]);if (current_z - start_z <= thresh) {current_cluster.indices.push_back(indices[i]);}else {clusters.push_back(current_cluster);current_cluster.indices.clear();current_cluster.indices.push_back(indices[i]);start_z = current_z;}}if (!current_cluster.indices.empty()) {clusters.push_back(current_cluster);}return clusters;
}/*** @brief 可视化聚类结果* @param cloud 原始点云* @param clusters 聚类索引*/
void visualizeClusters(const PointCloudT::Ptr& cloud,const std::vector<pcl::PointIndices>& clusters, float cloud_size, Eigen::Vector4f centroid)
{pcl::visualization::PCLVisualizer viewer("Cluster Visualization");viewer.setBackgroundColor(0, 0, 0); //为每个聚类生成随机颜色std::vector<pcl::visualization::PointCloudColorHandlerCustom<PointT>> color_handlers;for (size_t i = 0; i < clusters.size(); ++i) {uint8_t r = rand() % 256;uint8_t g = rand() % 256;uint8_t b = rand() % 256;color_handlers.emplace_back(pcl::visualization::PointCloudColorHandlerCustom<PointT>(cloud, r, g, b));}//添加每个聚类的点云到可视化for (size_t i = 0; i < clusters.size(); ++i) {PointCloudT::Ptr cluster_cloud(new PointCloudT);pcl::ExtractIndices<PointT> extract;pcl::PointIndices::Ptr indices(new pcl::PointIndices(clusters[i]));extract.setInputCloud(cloud);extract.setIndices(indices);extract.filter(*cluster_cloud);std::string cluster_id = "cluster_" + std::to_string(i);viewer.addPointCloud<PointT>(cluster_cloud, color_handlers[i], cluster_id);viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, cluster_id);}// 关键参数设置const float camera_distance = 3.0 * cloud_size; // 观察距离为点云尺寸的3倍const Eigen::Vector3f camera_pos = {centroid[0],centroid[1],centroid[2] + camera_distance};
viewer.initCameraParameters();
viewer.setCameraPosition(camera_pos[0], camera_pos[1], camera_pos[2], // 相机位置centroid[0], centroid[1], centroid[2], // 焦点位置0, -1, 0 // 上方向向量(Y轴负方向)
);viewer.addCoordinateSystem(1.0);while (!viewer.wasStopped()) {viewer.spinOnce(100);}
}int main(int argc, char** argv) {//1. 创建点云对象
pcl::PointCloud<PointT>::Ptr cloud(new pcl::PointCloud<PointT>);//2. 打开并读取TXT文件
std::ifstream file("E:\\Data\\PathPlanning\\data.txt");
if (!file.is_open()) {std::cerr << "Error opening file: " << argv[1] << std::endl;return -1;
}std::string line;
while (std::getline(file, line)) {if (line.empty()) continue;std::istringstream iss(line);PointT point;//读取坐标 (x,y,z) 和法向量float nx, ny, nz;if (!(iss >> point.x >> point.y >> point.z >> nx >> ny >> nz)) {std::cerr << "Error parsing line: " << line << std::endl;continue;}cloud->push_back(point);
}
file.close();//3. 设置点云属性
cloud->width = cloud->size();
cloud->height = 1;
cloud->is_dense = false;// 计算点云质心
Eigen::Vector4f centroid;
if (pcl::compute3DCentroid(*cloud, centroid)){std::cout << "点云质心坐标: ("<< centroid[0] << ", "<< centroid[1] << ", "<< centroid[2] << ")" << std::endl;
}
else {std::cerr << "无法计算空点云的质心" << std::endl;return -1;
}// 计算点云尺寸范围
PointT min_pt, max_pt;
pcl::getMinMax3D(*cloud, min_pt, max_pt);
float cloud_size = std::max({max_pt.x - min_pt.x,max_pt.y - min_pt.y,max_pt.z - min_pt.z});//2. 沿Z轴聚类(设置Thresh = 1.0)
float thresh = 100.0f;
std::vector<pcl::PointIndices> clusters = axisAlignedClustering(Eigen::Vector3f(1, 1, 0), cloud, thresh);//3. 输出聚类信息
std::cout << "Found " << clusters.size() << " clusters." << std::endl;
for (size_t i = 0; i < clusters.size(); ++i) {std::cout << "Cluster " << i << ": " << clusters[i].indices.size()<< " points" << std::endl;
}//4. 可视化
visualizeClusters(cloud, clusters, cloud_size, centroid); return 0;
}
相关文章:

PCL点云按指定方向进行聚类(指定类的宽度)
需指定方向和类的宽度。测试代码如下: #include <iostream> #include <fstream> #include <vector> #include <string> #include <pcl/point_types.h> #include <pcl/point_cloud.h> #include <pcl/visualization/pcl_visu…...
复现nn-Unet模型 实验报告
目的是将 nn-Unet 模型应用到切割脑出血CT图像上 论文学习步骤为 1.学习Unet,Unet等模型作为复现nn-Unet模型的基础。 2.学习nn-Unet原论文,掌握nn-Unet的结构。 3.学习将nn-Unet模型应用到切割脑出血CT医学图像的相关论文。 这周学习了Unet&#x…...

C#对SQLServer增删改查
1.创建数据库 2.SqlServerHelper using System; using System.Collections.Generic; using System.Data.SqlClient; using System.Data; using System.Linq; using System.Text; using System.Threading.Tasks;namespace WindowsFormsApp1 {internal class SqlServerHelper{//…...

模拟太阳系(C#编写的maui跨平台项目源码)
源码下载地址:https://download.csdn.net/download/wgxds/90789056 本资源为用C#编写的maui跨平台项目源码,使用Visual Studio 2022开发环境,基于.net8.0框架,生成的程序为“模拟太阳系运行”。经测试,生成的程序可运行…...

蓝桥杯14届 数三角
问题描述 小明在二维坐标系中放置了 n 个点,他想在其中选出一个包含三个点的子集,这三个点能组成三角形。然而这样的方案太多了,他决定只选择那些可以组成等腰三角形的方案。请帮他计算出一共有多少种选法可以组成等腰三角形? 输…...
redis sentinel和redis cluster的主从切换选举过程
引言 redis sentinel和redis cluster的主从切换选举过程不同,本文将从选举机制、核心差异对比两者的不同。 一、Redis Sentinel的选举机制 监控与故障判定 Sentinel集群通过心跳检测(每秒一次PING)监控主节点状态: 主观下线&…...
C++自学笔记 makefile
本博客参考南科大于仕琪教授的讲解视频和这位同学的学习笔记: 参考博客 感谢两位的分享。 makefile 的作用 用于组织大型项目的编译,是一个一键编译项目的脚本文件。 本博客通过四个版本的makefile逐步说明makefile的使用 使用说明 四个演示文件 …...
前端密码加密:保护用户数据的第一道防线
引言 在当今互联网时代,用户数据安全至关重要,而密码作为用户身份验证的核心凭证,其安全性更是重中之重。传统的前端开发中,密码常常以明文形式传输到服务器,这带来了严重的安全隐患。本文将深入探讨前端密码加密的必…...

HTML12:文本框和单选框
表单元素格式 属性说明type指定元素的类型。text、password、 checkbox、 radio、submit、reset、file、hidden、image 和button,默认为textname指定表单元素的名称value元素的初始值。type为radio时必须指定一个值size指定表单元素的初始宽度。当type为text 或pas…...

机器人厨师上岗!AI在餐饮界掀起新风潮!
想要了解人工智能在其他各个领域的应用,可以查看下面一篇文章 《AI在各领域的应用》 餐饮业是与我们日常生活息息相关的行业,而人工智能(AI)正在迅速改变这个传统行业的面貌。从智能点餐到食材管理,再到个性化推荐&a…...

MySQL开篇
文章目录 一、前置知识1. MySQL的安装2. 前置一些概念知识 二、MySQL数据库操作2.1 概念2.2 数据库的操作2.2.1创建数据库命令2.2.2 查看数据库2.2.3 选中数据库2.2.4 删除数据库 三、MySQL数据表操作3.1 概念3.2 数据表的操作3.2.1 创建表 一、前置知识 1. MySQL的安装 MySQ…...

Linux电脑本机使用小皮面板集成环境开发调试WEB项目
开发调试WEB项目,有时开发环境配置繁琐,可以使用小皮面板集成环境。 小皮面板官网: https://www.xp.cn/1.可以使用小皮面板安装脚本一键安装。登陆小皮面板管理后台 2.在“软件商店”使用LNMP一键部署集成环境。 3.添加网站,本…...

问题及解决01-面板无法随着窗口的放大而放大
在MATLAB的App Designer中,默认情况下,组件的位置是固定的,不会随着父容器的大小变化而改变。问题图如下图所示。 解决: 为了让Panel面板能够随着UIFigure父容器一起缩放,需要使用布局管理器,我利用 MATLA…...

操作系统原理实验报告
操作系统原理课程的实验报告汇总 实验三:线程的创建与撤销 实验环境:计算机一台,内装有VC、office等软件 实验日期:2024.4.11 实验要求: 1.理解:Windows系统调用的基本概念,进程与线程的基…...

《Linux命令行大全(第2版)》PDF下载
内容简介 本书对Linux命令行进行详细的介绍,全书内容包括4个部分,第一部分由Shell的介绍开启命令行基础知识的学习之旅;第二部分讲述配置文件的编辑,如何通过命令行控制计算机;第三部分探讨常见的任务与必备工具&…...

Java高频面试之并发编程-15
hello啊,各位观众姥爷们!!!本baby今天又来报道了!哈哈哈哈哈嗝🐶 面试官:as-if-serial 是什么?单线程的程序一定是顺序执行的吗? as-if-serial 规则 定义: …...
Python-86:奇妙货币交易问题
问题描述 小R住在一个名为 X 国的国家,这里的货币非常特殊,面值为 V0,V1,V2,...,VnV0,V1,V2,...,Vn,并且 nn 可以无限大。该国的交易规则也很特别:在一次交易中,双方只能对每种面值的货币使用不超过两次。 例如&…...
Selenium的driver.get_url 和 手动输入网址, 并点击的操作,有什么不同?
我在搞爬取的时候,发现有些网站直接用driver.get(url) 跳转到目标特定的网址的时候,会被强制跳转到其他的网址上,但是如果是自己手动,在网址栏那里输入网址,并点回车,却能完成跳转。 这是在使用 Selenium …...
kotlin @JvmStatic注解的作用和使用场景
1. JvmStatic 的作用 JvmStatic 是 Kotlin 提供的一个注解,用于在 JVM 上将伴生对象(companion object)中的方法或属性暴露为 Java 静态方法或字段。 作用对象:只能用在 companion object 中的函数或属性。效果: 在 …...
GitHub中多个PR时,如何协同合并和管理
在 GitHub 中,当多个开发者同时提交多个 Pull Request(PR)时,合理的管理流程与协作策略能够确保代码库稳定、审查高效,并减少冲突与重工。总体而言,你需要: 1)统一分支与命名策略&a…...

无人甘蔗小车履带式底盘行走系统的研究
1.1 研究背景与意义 1.1.1 研究背景 甘蔗作为全球最重要的糖料作物之一,在农业经济领域占据着举足轻重的地位。我国是甘蔗的主要种植国家,尤其是广西、广东、云南等地,甘蔗种植面积广泛,是当地农业经济的重要支柱产业。甘蔗不仅…...

通俗易懂版知识点:Keepalived + LVS + Web + NFS 高可用集群到底是干什么的?
实验开始前,先搞懂为什么要部署该集群? 这个方案的目标是让网站 永不宕机,即使某台服务器挂了,用户也感觉不到。它主要涉及 负载均衡(LVS) 高可用(Keepalived) 共享存储ÿ…...
各类有关NBA数据统计数据集大合集
这些数据我已上传大家在CSDN上直接搜索就可以! 一、【2022-2023 NBA球员统计】数据集 关键词: 篮球 描述: 语境 该数据集每场比赛包含2022-2023常规赛NBA球员统计数据。 请注意,由团队更改产生了重复的球员名称。 * [2021-2022 NBA播放器统计]&#…...
《社交应用架构生存战:React Native与Flutter的部署容灾决胜法则》
React Native和Flutter作为当下热门的跨平台开发框架,在社交应用开发领域各显神通。今天,我们深入探索它们在高可用架构中的部署与容灾策略。 React Native凭借其独特优势,在社交应用开发中拥有一席之地。它基于JavaScript和React࿰…...

https,http1,http2,http3的一些知识
温故知新,突然有人问我项目中🤔有使用http3么,一下不知从何说起,就有了这篇文章的出现。 https加密传输,ssltls https 验证身份 提供加密,混合加密 : 对称加密 非对称加密 原理:…...

go 通过汇编学习atomic原子操作原理
文章目录 概要一、原理1.1、案例1.2、关键汇编 二、LOCK汇编指令2.1、 LOCK2.2、 原理2.2.1、 缓存行2.2.2、 缓存一致性之MESI协议2.2.3、lock原理 三、x86缓存发展四、x86 DMA发展参考 概要 在并发操作下,对一个简单的aa2的操作都会出错,这是因为这样…...

WebRTC 源码原生端Demo入门-1
1、概述 我的代码是比较新的,基于webrtc源码仓库的main分支的,在windows下把源码仓库下载好了后,用visual stdio 2022打开进行编译调试src/examples/peerconnection_client测试项目,主要是跑通这个demo来入手和调试,纯看代码很难…...
Nipype 简单使用教程
Nipype 简单使用教程 基础教程**一、Nipype 核心概念与工作流构建****1. 基本组件****2. 工作流构建步骤** **二、常用接口命令速查表****1. FSL 接口****2. FreeSurfer 接口****3. ANTS 接口****4. 数据处理接口** **三、高级特性与最佳实践****1. 条件执行(基于输…...
股票回购、股票减持和股票解禁对股票价格影响的综合分析
以下是关于股票回购、股票减持和股票解禁对股票价格影响的综合分析,结合了市场机制、财务指标及投资者行为等多维度因素: 一、股票回购对股价的影响 1. 正面影响 • 提升财务指标:回购减少流通股数量,在净利润不变的情况下&#…...
linux 三剑客命令学习
grep Grep 是一个命令行工具,用于在文本文件中搜索打印匹配指定模式的行。它的名称来自于 “Global Regular Expression Print”(全局正则表达式打印),它最初是由 Unix 系统上的一种工具实现的。Grep 工具在 Linux 和其他类 Unix…...