PCL八叉树聚类

打印 上一主题 下一主题

主题 1607|帖子 1607|积分 4821

主要流程


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

  1. #include <pcl/io/pcd_io.h>
  2. #include <pcl/point_types.h>
  3. #include <pcl/octree/octree_search.h>
  4. #include <pcl/octree/octree_pointcloud.h>
  5. #include <pcl/segmentation/extract_clusters.h> // 欧式聚类分割
  6. #include <pcl/visualization/pcl_visualizer.h>
  7. // 聚类结果分类渲染
  8. void clusterColor(pcl::PointCloud<pcl::PointXYZRGB>::Ptr& ccloud)
  9. {
  10.         double R = rand() % (256) + 0;
  11.         double G = rand() % (256) + 0;
  12.         double B = rand() % (256) + 0;
  13.         for_each(ccloud->begin(), ccloud->end(),
  14.                 [R, G, B](pcl::PointXYZRGB& point)
  15.                 { point.r = R, point.g = G, point.b = B; });
  16. };
  17. int main(int argc, char* argv[])
  18. {
  19.         // --------------------------------读取点云------------------------------------
  20.         pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
  21.         if (pcl::io::loadPCDFile<pcl::PointXYZ>("../../../data/000000.pcd", *cloud) == -1)
  22.         {
  23.                 PCL_ERROR("Couldn't read file test_pcd.pcd \n");
  24.                 return -1;
  25.         }
  26.         // 参数设置
  27.         float leaf = 0.3f;     // 八叉树深度参数
  28.         int minSize = 50;
  29.         // --------------------------获取八叉树体素中心-------------------------------
  30.         pcl::PointCloud<pcl::PointXYZ>::VectorType voxelCentroids;
  31.         pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree(leaf);
  32.         octree.setInputCloud(cloud);
  33.         octree.addPointsFromInputCloud();
  34.         octree.getOccupiedVoxelCenters(voxelCentroids);
  35.         // 保存八叉树体素中心为点云
  36.         pcl::PointCloud<pcl::PointXYZ>::Ptr v_cloud(new pcl::PointCloud<pcl::PointXYZ>);
  37.         v_cloud->resize(voxelCentroids.size());
  38.         transform(voxelCentroids.begin(), voxelCentroids.end(), v_cloud->begin(), [&](const auto& p)->pcl::PointXYZ
  39.                 {
  40.                         pcl::PointXYZ point;
  41.                         point.x = p.x;
  42.                         point.y = p.y;
  43.                         point.z = p.z;
  44.                         return point;
  45.                 });
  46.         float dis_th = std::sqrt(3.0f * leaf * leaf); // 计算聚类深度阈值
  47.         // ------------------------------欧式聚类------------------------------------
  48.         pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
  49.         tree->setInputCloud(v_cloud);
  50.         std::vector<pcl::PointIndices> cluster_indices;   // 聚类索引
  51.         pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;// 欧式聚类对象
  52.         ec.setClusterTolerance(dis_th);                   // 设置近邻搜索的搜索半径(也即两个不同聚类团点之间的最小欧氏距离)
  53.         ec.setMinClusterSize(minSize);                    // 设置一个聚类需要的最少的点数
  54.         ec.setMaxClusterSize(v_cloud->size());            // 设置一个聚类需要的最大点数
  55.         ec.setSearchMethod(tree);                         // 设置点云的搜索机制
  56.         ec.setInputCloud(v_cloud);                        // 设置输入点云
  57.         ec.extract(cluster_indices);                      // 从点云中提取聚类,并将点云索引保存在cluster_indices中
  58.         std::vector<pcl::PointCloud<pcl::PointXYZ>>label;
  59.         // ---------------------------最终聚类结果----------------------------------
  60.         for (int i = 0; i < cluster_indices.size(); i++)
  61.         {
  62.                 // 聚类完成后,重新找到八叉树内部所有点
  63.                 pcl::PointCloud<pcl::PointXYZ> voxel_cloud, cloud_copy;
  64.                 pcl::copyPointCloud(*v_cloud, cluster_indices[i].indices, cloud_copy);   // 按照索引提取点云数据
  65.                 for (int j = 0; j < cloud_copy.points.size(); ++j)
  66.                 {
  67.                         std::vector<int> pointIdxVec;                           // 保存体素近邻搜索的结果向量
  68.                         if (octree.voxelSearch(cloud_copy.points[j], pointIdxVec))
  69.                         {
  70.                                 for (size_t k = 0; k < pointIdxVec.size(); ++k)
  71.                                 {
  72.                                         voxel_cloud.push_back(cloud->points[pointIdxVec[k]]);
  73.                                 }
  74.                         }
  75.                 }
  76.                 if (voxel_cloud.points.size() > minSize)
  77.                 {
  78.                         label.push_back(voxel_cloud);
  79.                 }
  80.         }
  81.         // -----------------------聚类结果分类保存---------------------------
  82.         pcl::PointCloud<pcl::PointXYZRGB>::Ptr clusterResult(new pcl::PointCloud<pcl::PointXYZRGB>);
  83.         int begin = 1;
  84.         std::vector<int> idx;
  85.         for (int i = 0; i < label.size(); ++i)
  86.         {
  87.                 pcl::PointCloud<pcl::PointXYZRGB>::Ptr clusterTemp(new pcl::PointCloud<pcl::PointXYZRGB>);
  88.                 clusterTemp->resize(label[i].size());
  89.                 for (int j = 0; j < clusterTemp->size(); ++j)
  90.                 {
  91.                         clusterTemp->points[j].x = label[i][j].x;
  92.                         clusterTemp->points[j].y = label[i][j].y;
  93.                         clusterTemp->points[j].z = label[i][j].z;
  94.                 }
  95.                 clusterColor(clusterTemp);
  96.                 *clusterResult += *clusterTemp;
  97.                 // 聚类结果分类保存
  98.                 //pcl::io::savePCDFileBinary("lc_cluster_" + std::to_string(begin) + ".pcd", *clusterTemp);
  99.                 begin++;
  100.         }
  101.         pcl::io::savePCDFileBinary("LCclusterResult.pcd", *clusterResult);
  102.         pcl::visualization::PCLVisualizer viewer("cloud viewer");
  103.         viewer.setBackgroundColor(0, 0, 0);
  104.         viewer.addPointCloud(clusterResult, "viewer");
  105.         while (!viewer.wasStopped())//要想让自己所创窗口一直显示
  106.         {
  107.                 viewer.spinOnce();
  108.         }
  109.         return 0;
  110. }
复制代码
部分代码剖析

//聚类结果分类渲染
  1. void clusterColor(pcl::PointCloud<pcl::PointXYZRGB>::Ptr& ccloud)
  2. {
  3.         double R = rand() % (256) + 0;
  4.         double G = rand() % (256) + 0;
  5.         double B = rand() % (256) + 0;
  6.         for_each(ccloud->begin(), ccloud->end(),
  7.                 [R, G, B](pcl::PointXYZRGB& point)
  8.                 { point.r = R, point.g = G, point.b = B; });
  9. };
复制代码
关键元素剖析

std::for_each算法



  • 功能:遍历从ccloud->begin()到ccloud->end()的所有点
  • 作用:对点云中的每个点执行指定的lambda函数
  • 特点

    • 标准模板库(STL)提供的遍历算法
    • 比传统for循环更简洁安全
    • 自动处置惩罚迭代器范围

Lambda表达式

  1. [R, G, B](pcl::PointXYZRGB& point) {
  2.     point.r = R,
  3.     point.g = G,
  4.     point.b = B;
  5. }
复制代码
等价

  1. void clusterColor(pcl::PointCloud<pcl::PointXYZRGB>::Ptr& ccloud) {
  2.     uint8_t R = rand() % 256;
  3.     uint8_t G = rand() % 256;
  4.     uint8_t B = rand() % 256;
  5.    
  6.     for(size_t i = 0; i < ccloud->size(); ++i) {
  7.         (*ccloud)[i].r = R;
  8.         (*ccloud)[i].g = G;
  9.         (*ccloud)[i].b = B;
  10.     }
  11. }
复制代码
结果



免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?立即注册

x
回复

使用道具 举报

0 个回复

倒序浏览

快速回复

您需要登录后才可以回帖 登录 or 立即注册

本版积分规则

羊蹓狼

论坛元老
这个人很懒什么都没写!
快速回复 返回顶部 返回列表