PCL - octTree八叉树

前言

在前几篇PCL学习文章中,我们搭建起相关环境,以及KD Tree的相关搜索算法。本篇将带大家学习相关八叉树相关内容,还是在上文的代码基础下,进行相关的修改。

1. 准备

1.1 oct-Tree基本概念

八叉树是一种用于描述三维空间的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,这八个子节点所表示的体积元素加在一起就等于父节点的体积。

  1. 一般中心点作为节点的分叉中心。
  2. 八叉树若不为空树的话,树中任一节点的子节点恰好只会有八个,或零个,也就是子节点不会有0与8以外的数目。
  3. 分割一直要进行到节点所对应的立方体或是完全空白,或是完全为V占据,或是其大小已是预先定义的体素大小,并且对它与V之交作一定的“舍入”,使体素或认为是空白的,或认为是V占据的。
    八叉树分割

1.2 添加按钮

依旧如上篇一样,在上面的代码基础上添加相关的按钮,以及对应的槽函数:如下

  // oct分割
  QPushButton *octTreeDivisionBtn;
  // oct 搜索
  QPushButton *octTreeSearchBtn;

octTreeDivisionBtn = new QPushButton(PCLView);
octTreeDivisionBtn->setObjectName(QString::fromUtf8("Oct Division Tree"));
octTreeDivisionBtn->setGeometry(QRect(50, 160, 120, 40));

// octTreeSearchBtn
octTreeSearchBtn = new QPushButton(PCLView);
octTreeSearchBtn->setObjectName(QString::fromUtf8("Oct Search Tree"));
octTreeSearchBtn->setGeometry(QRect(50, 210, 120, 40));

octTreeDivisionBtn->setText(QCoreApplication::translate("PCLView","Oct Tree Division", nullptr));
octTreeSearchBtn->setText(QCoreApplication::translate("PCLView","Oct Tree Search", nullptr));

// oct 按钮点击事件
void octTreePressed();
void octTreeSearchPressed();

运行如图所示:
octTree按钮

2. octTree 八叉树分割

八叉树的算法步骤逻辑如下:

  1. 设定最大递归深度。
  2. 找出场景的最大尺寸,并以此尺寸建立第一个立方体。
  3. 依序将单位元元素丢入能被包含且没有子节点的立方体。
  4. 若没达到最大递归深度,就进行细分八等份,再将该立方体所装的单位元元素全部分担给八个子立方体。
  5. 若发现子立方体所分配到的单位元元素数量不为零且跟父立方体是一样的,则该子立方体停止细分,因为跟据空间分割理论,细分的空间所得到的分配必定较少,若是一样数目,则再怎么切数目还是一样,会造成无穷切割的情形。
  6. 重复3,直到达到最大递归深度。

PCL库中实现相关的逻辑算法,我们只需调用相应的SDK即可,代码如下:

void UI::PclViewer::octTreePressed() {
    // 设置划分分辨率
    float resolution = .5f;
    pcl::octree::OctreePointCloudSearch<PointT> octree(resolution);
    octree.setInputCloud(pointCloud);
    
    // 进行对点云进行octTree的建立
    octree.addPointsFromInputCloud();
    // 显示分割后的点云
    for (auto branch:octree){
        if (branch->getNodeType() == pcl::octree::LEAF_NODE){
            auto children = dynamic_cast<pcl::octree::OctreeLeafNode<pcl::octree::OctreeContainerPointIndices> *>(branch);
            std::vector<int> pointIndexes;
            children->getContainer().getPointIndices(pointIndexes);
            auto r = random() % 155 + 100;
            auto g = random() % 155 + 100;
            auto b = random() % 155 + 100;
            for (auto i:pointIndexes){
                pointCloud->points[i].r = r ;
                pointCloud->points[i].g = g;
                pointCloud->points[i].b = b ;
            }
        }
    }
    // 重新更新点云
    updatePointCloud();
}

上面代码因为PCL库给我们完成很多地方,因此调用起来很简单。先申明一个octree对象在设置点云,并且构建octTree,最后将分割的结果进行展示。运行代码,其结果如下:
请添加图片描述

3. octTree 八叉树搜索

根据所建立的octree,对指定点进行收拾到分割到最小的单元体。其实现如下:

void UI::PclViewer::octTreeSearchPressed() {
    //建立octTree
    float resolution = .5f;
    pcl::octree::OctreePointCloudSearch<PointT> octree(resolution);
    octree.setInputCloud(pointCloud);
    octree.addPointsFromInputCloud();

    PointT searchPoint;
    
    // 搜索点
    searchPoint.x = 1024 * rand() / (RAND_MAX + 1.0f);
    searchPoint.y = 1024* rand() /(RAND_MAX + 1.0f);
    searchPoint.z = 1024 * rand() / (RAND_MAX + 1.0f);

    std::vector<int> pointIdxVec;
    
    // 搜索最近的单元体
    if (octree.voxelSearch(searchPoint,pointIdxVec)){
        for (int i: pointIdxVec) {
            // 修改搜索后点的颜色
            pointCloud->points[i].r = 255 ;
            pointCloud->points[i].g = 250 ;
            pointCloud->points[i].b = 250 ;
        }
    }
    updatePointCloud();
}

代码上依旧是先建立起octTree,在指定点去搜索最小分割单元,最后一个展示结果。其结果如下:
请添加图片描述

4.总结

本篇我们了解PCL相关八叉树的学习,后续将继续更新后续内容

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

myenjoy_1

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值