当前位置: 首页 > news >正文

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;
}

http://www.xdnf.cn/news/341767.html

相关文章:

  • mission planner烧录ardupilot固件报错死机
  • ESP32开发之freeRTOS的互斥量
  • 网络协议之DHCP和PXE分析
  • QT中多线程的实现
  • Rust包、crate与模块管理
  • 领域驱动设计(DDD)解析
  • 2025年4月AI算力领域热点事件全景报告
  • 配置Hadoop集群环境-使用脚本命令实现集群文件同步
  • 手撕基于AMQP协议的简易消息队列-1(项目介绍与开发环境的搭建)
  • uniapp|实现多终端聊天对话组件、表情选择、消息发送
  • onlyoffice 源码调试指南-ARM和x86双模式安装支持
  • 前端面试宝典---JavaScript import 与 Node.js require 的区别
  • uni-pages-hot-modules插件:uni-app的pages.json的模块化及模块热重载
  • JavaScript基础 (二)
  • 苍穹外卖(数据统计-图形报表)
  • QtGUI模块功能详细说明, 字体和文本渲染(四)
  • 单片机-STM32部分:8、外部中断
  • Mysql-OCP PPT课程讲解并翻译
  • 【并发编程】MySQL锁及单机锁实现
  • 【Android】动画原理解析
  • IT/OT 融合架构下的工业控制系统安全攻防实战研究
  • 【嵌入式开发-USB】
  • 王泫梓妍在户外拍摄的一组照片
  • 缓存套餐-03.功能测试
  • Spark缓存
  • 【前端基础】9、CSS的动态伪类(hover、visited、hover、active、focus)【注:本文只有几个粗略说明】
  • 5月8日星期四今日早报简报微语报早读
  • 【人工智能核心技术全景解读】从机器学习到深度学习实战
  • 什么是多模态大模型?为什么需要多模态大模型?
  • 兼具直连存储与分布式存储优势的混合存储方案