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

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

原理

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

  • 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

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

相关文章
|
2月前
|
机器学习/深度学习 算法
R语言超参数调优:深入探索网格搜索与随机搜索
【9月更文挑战第2天】网格搜索和随机搜索是R语言中常用的超参数调优方法。网格搜索通过系统地遍历超参数空间来寻找最优解,适用于超参数空间较小的情况;而随机搜索则通过随机采样超参数空间来寻找接近最优的解,适用于超参数空间较大或计算资源有限的情况。在实际应用中,可以根据具体情况选择适合的方法,并结合交叉验证等技术来进一步提高模型性能。
|
6月前
|
Windows
(文件[夹]批量分类整理_多级匹配_交叉匹配_路径结构交叉调整)文件[夹]批量复制
该文介绍了如何使用特定工具进行批量文件整理。首先,需要从提供的百度网盘和蓝奏云链接下载工具,并用提取码解锁。接着,打开工具的批量复制功能,将待整理的图片文件拖入“来源路径”,目标文件夹拖入“终点路径”。通过层级过滤排除不需要的路径。然后,利用多级匹配设置,提取文件名和路径中的关键词,如“动物”、“小型”、“食草”等,设置复制后的文件重命名规则。最后,执行批量复制,完成文件的智能分类与命名。整个过程旨在根据文件的原始分类信息,自动将其移动到相应的新目录结构下。
|
6月前
|
索引 Python
leetcode-307:区域和检索 - 数组可修改
leetcode-307:区域和检索 - 数组可修改
37 0
|
6月前
|
C++ 索引 Python
区域和检索 - 数组不可变(C++)
区域和检索 - 数组不可变(C++)
45 0
|
6月前
|
索引 Python
leetcode-303:区域和检索 - 数组不可变
leetcode-303:区域和检索 - 数组不可变
31 0
|
6月前
|
分布式计算 Java Hadoop
MapReduce编程:检索特定群体搜索记录和定义分片操作
MapReduce编程:检索特定群体搜索记录和定义分片操作
65 0
|
算法
一篇文章带你整体了解算法中的基本问题《查找》
查找 本章对算法中的基本问题--查找做了一个简要介绍,包含了一些基本算法思想以及评价,后续文章详细介绍一些算法,欢迎关注本系列。 可以转载,但请声明源链接:文章源链接justin3go.com(有些latex公式某些平台不能渲染可查看这个网站)
74 0
|
索引 Python
LeetCode 303. 区域和检索 - 数组不可变
给定一个整数数组 nums,求出数组从索引 i 到 j(i ≤ j)范围内元素的总和,包含 i、j 两点。
106 0
|
前端开发 程序员 开发者
搜索区域 | 学习笔记
快速学习搜索区域
搜索区域 | 学习笔记
|
索引 Python
303 区域和检索-数组不可变 leetcode
303 区域和检索-数组不可变 leetcode
68 0
下一篇
无影云桌面