基于八叉树的空间划分及搜索操作

简介: 基于八叉树的空间划分及搜索操作

原理

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

  • 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

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

相关文章
|
3月前
|
机器学习/深度学习 算法
R语言超参数调优:深入探索网格搜索与随机搜索
【9月更文挑战第2天】网格搜索和随机搜索是R语言中常用的超参数调优方法。网格搜索通过系统地遍历超参数空间来寻找最优解,适用于超参数空间较小的情况;而随机搜索则通过随机采样超参数空间来寻找接近最优的解,适用于超参数空间较大或计算资源有限的情况。在实际应用中,可以根据具体情况选择适合的方法,并结合交叉验证等技术来进一步提高模型性能。
|
7月前
|
算法 前端开发 索引
前端算法-搜索插入位置
前端算法-搜索插入位置
|
7月前
|
C++ 索引 Python
区域和检索 - 数组不可变(C++)
区域和检索 - 数组不可变(C++)
46 0
|
7月前
|
分布式计算 Java Hadoop
MapReduce编程:检索特定群体搜索记录和定义分片操作
MapReduce编程:检索特定群体搜索记录和定义分片操作
70 0
|
存储 并行计算 算法
秒懂算法 | 搜索基础
本篇介绍了BFS和DFS的概念、性质、模板代码。
166 0
秒懂算法 | 搜索基础
|
前端开发 程序员 开发者
搜索区域 | 学习笔记
快速学习搜索区域
搜索区域 | 学习笔记
|
存储 小程序
小程序实现搜索历史记录,去重搜索字段以及限制展示字段数量
小程序实现搜索历史记录,去重搜索字段以及限制展示字段数量
1407 0
|
人工智能 安全 关系型数据库
【技巧】我是如何 "搜索" 到想要的信息的
关于“搜索”资源的一些见解
818 0
|
存储 网络协议 索引
搜索在线服务的存储计算分离
随着网络和存储硬件向着高吞吐低延迟的方向不断发展,存储计算分离成为了集团的一个重要技术方向,在节约成本、简化运维、提高混布能力有着重要的作用。本文将介绍搜索在线服务的存储计算分离架构设计与一些为了降低延迟、提高性能的努力。
3905 0