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

PCL八叉树聚类

PCL八叉树聚类

  • 主要流程
  • 完整代码
  • 部分代码解析
    • 关键元素解析
      • `std::for_each`算法
      • Lambda表达式
      • 等价
  • 效果

主要流程

  1. 读取点云数据:从PCD文件中加载原始点云
  2. 构建八叉树:对点云进行八叉树空间划分
  3. 获取体素中心:提取八叉树中所有被占据的体素中心点
  4. 欧式聚类:对体素中心点进行欧式聚类
  5. 扩展聚类结果:将聚类结果从体素中心扩展到原始点云
  6. 可视化与保存:对聚类结果着色并可视化/保存

完整代码

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/octree/octree_search.h>
#include <pcl/octree/octree_pointcloud.h>
#include <pcl/segmentation/extract_clusters.h> // 欧式聚类分割
#include <pcl/visualization/pcl_visualizer.h>// 聚类结果分类渲染
void clusterColor(pcl::PointCloud<pcl::PointXYZRGB>::Ptr& ccloud)
{double R = rand() % (256) + 0;double G = rand() % (256) + 0;double B = rand() % (256) + 0;for_each(ccloud->begin(), ccloud->end(),[R, G, B](pcl::PointXYZRGB& point){ point.r = R, point.g = G, point.b = B; });};int main(int argc, char* argv[])
{// --------------------------------读取点云------------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ>("../../../data/000000.pcd", *cloud) == -1){PCL_ERROR("Couldn't read file test_pcd.pcd \n");return -1;}// 参数设置float leaf = 0.3f;     // 八叉树深度参数int minSize = 50;// --------------------------获取八叉树体素中心-------------------------------pcl::PointCloud<pcl::PointXYZ>::VectorType voxelCentroids;pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree(leaf);octree.setInputCloud(cloud);octree.addPointsFromInputCloud();octree.getOccupiedVoxelCenters(voxelCentroids);// 保存八叉树体素中心为点云pcl::PointCloud<pcl::PointXYZ>::Ptr v_cloud(new pcl::PointCloud<pcl::PointXYZ>);v_cloud->resize(voxelCentroids.size());transform(voxelCentroids.begin(), voxelCentroids.end(), v_cloud->begin(), [&](const auto& p)->pcl::PointXYZ{pcl::PointXYZ point;point.x = p.x;point.y = p.y;point.z = p.z;return point;});float dis_th = std::sqrt(3.0f * leaf * leaf); // 计算聚类深度阈值// ------------------------------欧式聚类------------------------------------pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);tree->setInputCloud(v_cloud);std::vector<pcl::PointIndices> cluster_indices;   // 聚类索引pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;// 欧式聚类对象ec.setClusterTolerance(dis_th);                   // 设置近邻搜索的搜索半径(也即两个不同聚类团点之间的最小欧氏距离)ec.setMinClusterSize(minSize);                    // 设置一个聚类需要的最少的点数ec.setMaxClusterSize(v_cloud->size());            // 设置一个聚类需要的最大点数ec.setSearchMethod(tree);                         // 设置点云的搜索机制ec.setInputCloud(v_cloud);                        // 设置输入点云ec.extract(cluster_indices);                      // 从点云中提取聚类,并将点云索引保存在cluster_indices中std::vector<pcl::PointCloud<pcl::PointXYZ>>label;// ---------------------------最终聚类结果----------------------------------for (int i = 0; i < cluster_indices.size(); i++){// 聚类完成后,重新找到八叉树内部所有点pcl::PointCloud<pcl::PointXYZ> voxel_cloud, cloud_copy;pcl::copyPointCloud(*v_cloud, cluster_indices[i].indices, cloud_copy);   // 按照索引提取点云数据for (int j = 0; j < cloud_copy.points.size(); ++j){std::vector<int> pointIdxVec;                           // 保存体素近邻搜索的结果向量if (octree.voxelSearch(cloud_copy.points[j], pointIdxVec)){for (size_t k = 0; k < pointIdxVec.size(); ++k){voxel_cloud.push_back(cloud->points[pointIdxVec[k]]);}}}if (voxel_cloud.points.size() > minSize){label.push_back(voxel_cloud);}}// -----------------------聚类结果分类保存---------------------------pcl::PointCloud<pcl::PointXYZRGB>::Ptr clusterResult(new pcl::PointCloud<pcl::PointXYZRGB>);int begin = 1;std::vector<int> idx;for (int i = 0; i < label.size(); ++i){pcl::PointCloud<pcl::PointXYZRGB>::Ptr clusterTemp(new pcl::PointCloud<pcl::PointXYZRGB>);clusterTemp->resize(label[i].size());for (int j = 0; j < clusterTemp->size(); ++j){clusterTemp->points[j].x = label[i][j].x;clusterTemp->points[j].y = label[i][j].y;clusterTemp->points[j].z = label[i][j].z;}clusterColor(clusterTemp);*clusterResult += *clusterTemp;// 聚类结果分类保存//pcl::io::savePCDFileBinary("lc_cluster_" + std::to_string(begin) + ".pcd", *clusterTemp);begin++;}pcl::io::savePCDFileBinary("LCclusterResult.pcd", *clusterResult);pcl::visualization::PCLVisualizer viewer("cloud viewer");viewer.setBackgroundColor(0, 0, 0);viewer.addPointCloud(clusterResult, "viewer");while (!viewer.wasStopped())//要想让自己所创窗口一直显示{viewer.spinOnce();}return 0;
}

部分代码解析

//聚类结果分类渲染

void clusterColor(pcl::PointCloud<pcl::PointXYZRGB>::Ptr& ccloud)
{double R = rand() % (256) + 0;double G = rand() % (256) + 0;double B = rand() % (256) + 0;for_each(ccloud->begin(), ccloud->end(),[R, G, B](pcl::PointXYZRGB& point){ point.r = R, point.g = G, point.b = B; });};

关键元素解析

std::for_each算法

  • 功能:遍历从ccloud->begin()ccloud->end()的所有点
  • 作用:对点云中的每个点执行指定的lambda函数
  • 特点
    • 标准模板库(STL)提供的遍历算法
    • 比传统for循环更简洁安全
    • 自动处理迭代器范围

Lambda表达式

[R, G, B](pcl::PointXYZRGB& point) { point.r = R, point.g = G, point.b = B; 
}

等价

void clusterColor(pcl::PointCloud<pcl::PointXYZRGB>::Ptr& ccloud) {uint8_t R = rand() % 256;uint8_t G = rand() % 256;uint8_t B = rand() % 256;for(size_t i = 0; i < ccloud->size(); ++i) {(*ccloud)[i].r = R;(*ccloud)[i].g = G; (*ccloud)[i].b = B;}
}

效果

在这里插入图片描述

相关文章:

  • Python基础语法2
  • 游戏代码编辑
  • 凸优化第2讲:凸优化建模
  • 一篇文章快速上手linux系统中存储多路径multipath的配置
  • MCP、RAG与Agent:下一代智能系统的协同架构设计
  • Cribl 中数据脱敏mask 的实验
  • 【HDFS】BlockPlacementPolicyRackFaultTolerant#getMaxNode方法的功能及具体实例
  • BufferedReader 终极解析与记忆指南
  • 使用python求函数极限
  • Java实现选择排序算法
  • 盛水最多的容器问题详解:双指针法与暴力法的对比与实现
  • vcast工具env环境问题二:<command-line>: error: stray ‘\’ in program
  • 深入解析 sklearn 中的 LabelEncoder:功能、使用场景与注意事项
  • 三、The C in C++
  • TV板卡维修技术【一】
  • 什么是GOTS认证,GOTS认证有什么要求?GOTS认证有什么作用
  • 基于动态注意力机制与双向融合的目标检测模型详解
  • 【树莓派 PICO 2 测评】采集 DS18B20 数据及 OLED 显示
  • Dockerfile项目实战-单阶段构建Vue2项目
  • vue动画
  • 孙颖莎4比1击败陈幸同,与蒯曼会师澳门世界杯女单决赛
  • 河南一季度GDP为14945.58亿元,同比增长5.9%
  • 秦洪看盘|A股缩量窄幅震荡,短线或延续有韧性、无弹性走势
  • 新消费观察 | 重点深耕,外资科技企业继续看好中国发展
  • 一图看懂|特朗普政府VS美国顶尖高校:这场风暴如何刮起?
  • 中共中央台办、国务院台办在南京举办台商代表座谈会