基于八叉树的空间划分及搜索操作-阿里云开发者社区

原理

建立空间索引在点云数据处理中有着广泛的应用,常见的空间索引一般 是自顶而下逐级划分空间的各种空间索引结构。
比较有代表性的包括

  • BSP树
  • KD树
  • KDB树
  • R树
  • 四叉树
  • 八叉树

这些结构中,KD树和八叉树使用比较广泛

八叉树定义: 八叉树(Octree)是一种用于描述三维空间的树状数据结构。八叉树的每个节点表示一个正方体的体积元素,每个节点有八个子节点,这八个子节点所表示的体积元素加在一起就等于父节点的体积。一般中心点作为节点的分叉中心。

八叉树算法思想

(1). 设定最大递归深度。

(2). 找出场景的最大尺寸,并以此尺寸建立第一个立方体。

(3). 依序将单位元元素丢入能被包含且没有子节点的立方体。

(4). 若没达到最大递归深度,就进行细分八等份,再将该立方体所装的单位元元素全部分担给八个子立方体。

(5). 若发现子立方体所分配到的单位元元素数量不为零且跟父立方体是一样的,则该子立方体停止细分,因为跟据空间分割理论,细分的空间所得到的分配必定较少,若是一样数目,则再怎么切数目还是一样,会造成无穷切割的情形。

(6). 重复3,直到达到最大递归深度。

下面实现用octree在点云数据中进行空间划分及近邻搜索
实现

  • 体素内近邻搜索(Neighbors within VOxel Search)
  • K近邻搜索(K Nearest Neighbor Search
  • 半径内近邻搜索”(Neighbors within Radius Search)

Code

CmakeList.txt


# 声明要求的 cmake 最低版本
cmake_minimum_required(VERSION 2.8 )

# 声明工程名称
project(octree_search)

# 添加c++ 11 标准支持
set(CMAKE_CXX_FLAGS "-std=c++11")


# 寻找PCL的库
find_package(PCL REQUIRED COMPONENT common io visualization)


# 添加头文件
include_directories(${PCL_INCLUDE_DIRS})
add_definitions( ${PCL_DEFINITIONS} )


#添加一个可执行程序
add_executable(Octree_Search octree_search.cpp)

#链接PCL 库
target_link_libraries(Octree_Search ${PCL_LIBRARIES})

CPP

#include <pcl/point_cloud.h>
#include <pcl/octree/octree.h>
#include <pcl/visualization/cloud_viewer.h>
#include <iostream>
#include <vector>
#include <ctime>

需要包含的头文件
cloud_viewer.h 这个文件如果不看 点云 的 话 可以不要

=======================================================

    //用系统时间初始化随机种子
    srand ((unsigned int) time (NULL));

    //声明一个点云指针 并分配空间
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);

    //定义点云大小  点云个数1000个,无序
    cloud->width =1000;
    cloud->height =1;
    cloud->points.resize (cloud->width * cloud->height);

    //循环给点云赋值 通过 随机数  点云的坐标 0-1024
    for(size_t i=0;i<cloud->points.size();++i)
    {
        cloud->points[i].x =1024.0f* rand () / (RAND_MAX +1.0f);
        cloud->points[i].y =1024.0f* rand () / (RAND_MAX +1.0f);
        cloud->points[i].z =1024.0f* rand () / (RAND_MAX +1.0f);            
    }

通过系统数据创建随机变量 。 创建一个1000个点的点云,为每个点的x,y,z坐标赋值 0-1024

显然 正常 就是一个 立方体。 把点云显示出来就是这样
在这里插入图片描述
显示的话 加上如下 代码 在最后面

    pcl::visualization::CloudViewer viewer("Cloud Viewer");
    
    viewer.showCloud(cloud);

    while (!viewer.wasStopped ())
        {

        }

=======================================================

    /* 设置分辨率 描述的是最低一级 八叉树 的 最小体素 的 尺寸*/
    float resolution =128.0f;

    /*创建 一个 八叉树 实例*/
    pcl::octree::OctreePointCloudSearch<pcl::PointXYZ> octree(resolution);

    /* 赋值八叉树的 点云 */
    octree.setInputCloud (cloud);//设置输入的点云
    octree.addPointsFromInputCloud ();//将输入的点云添加到八叉树

构建 八叉树 的部分

第一行 分辨率 的 参数 就是 八叉树 最小 的 体素的尺寸
然后就是 输入点云 和 构建 就可以了

=======================================================

    //构建一个  搜索点
    pcl::PointXYZ searchPoint;
    searchPoint.x=1024.0f* rand () / (RAND_MAX +1.0f);
    searchPoint.y=1024.0f* rand () / (RAND_MAX +1.0f);
    searchPoint.z=1024.0f* rand () / (RAND_MAX +1.0f);

构建一个 搜索点 x、y、z 取值 0-1024 随机

=======================================================
上面构建了 八叉树 一个搜索点 下面就可以搜索了

体素 近邻 搜索

    // 创建一个 搜索后 保存 的 点的索引值 的 向量
    std::vector<int>pointIdxVec;
 
    /*执行体素近邻搜索  函数很简单  参数 就是 搜索的点  和返回的索引值 向量*/
    if (octree.voxelSearch (searchPoint, pointIdxVec))
    {
        // 打印 搜索 的 点 的位置
        std::cout<<"Neighbors within voxel search at ("<<searchPoint.x
        <<" "<<searchPoint.y
        <<" "<<searchPoint.z<<")"
        <<std::endl;

            //打印搜索到的点 的 位置
        for (size_t i=0; i<pointIdxVec.size (); ++i)
        {
            std::cout<<"    "<< cloud->points[pointIdxVec[i]].x 
            <<" "<< cloud->points[pointIdxVec[i]].y 
            <<" "<< cloud->points[pointIdxVec[i]].z <<std::endl;
        }
    }

函数 octree.voxelSearch (searchPoint, pointIdxVec)
就是执行 体素近邻搜索 函数

  • 参数1 -----搜索的点
  • 参数2 ----- 返回的索引值 向量

=======================================================

K 近邻 搜索

   //设置K的个数
    int K = 10;
    // 创建一个 搜索后 保存 的 点的索引值 的 向量
    std::vector<int>pointIdxNKNSearch;
    // 创建一个 搜索后 保存 的 点的距离平方值 的 向量
    std::vector<float>pointNKNSquaredDistance;

    //打印 K近邻 搜索 的点  和 K个数
    std::cout<<"K nearest neighbor search at ("<<searchPoint.x
    <<" "<<searchPoint.y
    <<" "<<searchPoint.z
    <<") with K="<< K <<std::endl;

    /*执行 K近邻 搜索  函数 参数 搜索点  K个数  搜索结果的点索引值存放向量  搜索结果点距离平方存放向量*/
    if (octree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) >0)
    {
         //打印搜索到的点 的 位置 和距离
        for (size_t i=0; i<pointIdxNKNSearch.size (); ++i)
        {
            std::cout<<"    "<<   cloud->points[ pointIdxNKNSearch[i] ].x 
            <<" "<< cloud->points[pointIdxNKNSearch[i] ].y 
            <<" "<< cloud->points[pointIdxNKNSearch[i] ].z 
            <<" (squared distance: "<<pointNKNSquaredDistance[i] <<")"<<std::endl;
        }
    }

函数 octree.nearestKSearch (searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance)
执行 K近邻 搜索 函数

  • 参数1 ----- 搜索点
  • 参数2 ----- K个数
  • 参数3 ----- 搜索结果的点索引值存放向量
  • 参数4 ----- 搜索结果点距离平方存放向量

=======================================================

半径内 近邻 搜索

    // 创建一个 搜索后 保存 的 点的索引值 的 向量
    std::vector<int>pointIdxRadiusSearch;
    // 创建一个 搜索后 保存 的 点的距离平方值 的 向量
    std::vector<float>pointRadiusSquaredDistance;
    // 设置搜索的半径  随机0-256
    float radius =256.0f* rand () / (RAND_MAX +1.0f);

    //打印 半径搜索 的 点 的 位置  和  半径 
    std::cout<<"Neighbors within radius search at ("<<searchPoint.x
    <<" "<<searchPoint.y
    <<" "<<searchPoint.z
    <<") with radius="<< radius <<std::endl;

    /* 执行 半径 近邻 搜索  参数 搜索点  半径   搜索结果的点索引值存放向量  搜索结果点距离平方存放向量 */
    if (octree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) >0)
    {   
        //打印搜索到的点 的 位置 和距离
        for (size_t i=0; i<pointIdxRadiusSearch.size (); ++i)
        {
            std::cout<<"    "<<   cloud->points[ pointIdxRadiusSearch[i] ].x 
            <<" "<< cloud->points[pointIdxRadiusSearch[i] ].y 
            <<" "<< cloud->points[pointIdxRadiusSearch[i] ].z 
            <<" (squared distance: "<<pointRadiusSquaredDistance[i] <<")"<<std::endl;
        }
    }

函数 octree.radiusSearch (searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance)
执行 半径 近邻 搜索 函数

  • 参数1 ----- 搜索点
  • 参数2 ----- 半径
  • 参数3 ----- 搜索结果的点索引值存放向量
  • 参数4 ----- 搜索结果点距离平方存放向量

=======================================================

Result

在这里插入图片描述
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
八叉树网格划分是一种用于将三维空间划分为多个小方块的方法。它可以在计算机图形学、计算机视觉和计算机辅助设计等领域中用于表示复杂的三维数据和场景。Open3D是一个开源的计算机视觉库,提供了许多用于处理三维点云和网格的功能。 在Open3D中,八叉树网格划分可以通过Octree类来实现。它可以将给定的三维点云数据按照一定的规则划分为多个小方块,每个小方块称为一个八叉树节点。划分过程是递归的,通过不断划分每个节点来实现对整个点云数据的划分。每个八叉树节点都存储了一定数量的点云数据,并且可以继续划分成更小的节点,直到满足某个停止条件。 八叉树网格划分在Open3D中有很多应用场景,比如点云分割、点云压缩和三维重建等。通过八叉树网格划分,可以将点云数据分割成不同的部分,从而进行更精细的处理和分析。同时,通过八叉树网格划分,可以将大规模的点云数据压缩为较小的八叉树节点存储,从而节省存储空间。此外,八叉树网格划分还可以用于三维重建中的体素化和表面重建,从而更方便地进行后续的处理和分析。 总之,八叉树网格划分是Open3D中的一个重要功能,它可以将三维点云数据划分为多个小方块,并且可以应用于点云分割、点云压缩和三维重建等场景。通过八叉树网格划分,可以更方便地进行三维数据的处理和分析,提高计算效率和准确度。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值