ROS::点云PCL(2)八叉树

理解

建立空间索引在点云数据处理中已被广泛应用,常见空间索引一般是自顶向下逐级划分空间的各种空间索引结构,比较有代表性的包括 BSP 树、KD 树、KDB 树、 R树、R+树、CELL 树、四叉树和八叉树等索引结构,而在这些结构中 KD 树和八叉树在 3D点云数据排列中应用较为广泛。 PCL 对八叉树的数据结构建立和索引方法进行了实现,以方便在此基础上对点云进行处理操作 。
在这里插入图片描述
八叉树(Octree)的定义是:若不为空树的话,树中任一节点的子节点恰好只会有八个,或零个,也就是子节点不会有0与8以外的数目。那么,这要用来做什么?想象一个立方体,我们最少可以切成多少个相同等分的小立方体?答案就是8个。再想象我们有一个房间,房间里某个角落藏着一枚金币,我们想很快的把金币找出来,聪明的你会怎么做?我们可以把房间当成一个立方体,先切成八个小立方体,然后排除掉没有放任何东西的小立方体,再把有可能藏金币的小立方体继续切八等份….如此下去,平均在log8(n)
(n表示房间内的所有物体数)的时间内就可找到金币。因此,八叉树就是用在3D空间中的场景管理,可以很快地知道物体在3D场景中的位置,或侦测与其它物体是否有碰撞以及是否在可视范围内。

-这里引入了一个概念:Voxel翻译为体积元素,简称体素。描述了一个预设的最小单位的正方体
pcl的octree库提供了从点云数据创建具有层次的数据结构的方法。这样就可以对点数据集进行空间分区,下采样和搜索操作。每个八叉树节点有八个子节点或没有子节点。根节点描述了一个包围所有点的3维包容盒子。

pcl_octree实现提供了有效的最近邻居搜索(邻域搜索)API,例如“ 体素(Voxel)邻居搜索”,“ K最近邻居搜索”和“半径搜索邻居”。叶子节点类也提供其他功能,例如空间“占用率”和“每个体素(Voxel)的点密度”检查;序列化和反序列化功能可将八叉树结构有效地编码为二进制格式;此外,内存池实现减少了昂贵的内存分配和释放操作,以便快速创建八叉树。

在这里插入图片描述

方式一:“体素近邻搜索”

#include <ros/ros.h> 
#include <pcl/point_cloud.h> 
#include <pcl_conversions/pcl_conversions.h> 
#include <sensor_msgs/PointCloud2.h> 
#include <pcl/io/io.h>
#include <pcl/io/pcd_io.h>
#include <iostream>
#include <vector>
#include <ctime>
#include <pcl/octree/octree_search.h>



main (int argc, char **argv) 
{ 

    ros::init (argc, argv, "pcl_create"); 

    ros::NodeHandle nh; 
    ros::Publisher pcl_pub = nh.advertise<sensor_msgs::PointCloud2> ("pcl_output", 1);  
    
    // 用系统时间初始化随机种子
    srand(time(NULL));
    //pcl::PointCloud<pcl::PointXYZ> cloud2; 
    //pcl::PointCloud<pcl::PointXYZRGBA> cloud;
    pcl::PointCloud<pcl::PointXYZRGBA>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZRGBA>);
    //pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    sensor_msgs::PointCloud2 output; 

    int point_num;
    float table[8]={-2,-1.5,-1,-0.5,0.5,1,1.5,2};

    cloud->width = 512;
    cloud->height = 1; 
    cloud->points.resize(cloud->width * cloud->height); 

    for(int a=0;a<8;++a){
        float width = table[a];
        for(int i=0;i<8;++i){
			float length = table[i];
	  	    for(int c=0;c<8;++c){
				point_num = a*64+i*8+c;
				cloud->points[point_num].x = width; 
				cloud->points[point_num].y = length; 
				cloud->points[point_num].z = table[c];
				//std::cout <<"x="<< cloud->points[point_num].x <<"   y="<< cloud->points[point_num].y <<"   z="<< cloud->points[point_num].z  << std::endl;
				if(width==-0.5 && length==-0.5 && table[c]==-0.5){
					cloud->points[point_num].r=0;
					cloud->points[point_num].g=255;
					cloud->points[point_num].b=255;
				}else{
				   cloud->points[point_num].r=0;
				   cloud->points[point_num].g=0;
				   cloud->points[point_num].b=255;
		   		}

			}
		}
	}



    // 设置分辨率为2
    float resolution = 3.0f;
    // resolution该参数描述了octree叶子leaf节点的最小体素尺寸。
    pcl::octree::OctreePointCloudSearch<pcl::PointXYZRGBA> octree(resolution);
    // 设置输入点云
    octree.setInputCloud(cloud);
    // 通过点云构建octree
    octree.addPointsFromInputCloud();
    
    pcl::PointXYZRGBA searchPoint;

	searchPoint.x = -0.5;
    searchPoint.y = -0.5;
    searchPoint.z = -0.5;

// Neighbors within voxel search
    // 方式一:“体素近邻搜索”,它把查询点所在的体素中其他点的索引作为查询结果返回,
    // 结果以点索引向量的形式保存,因此搜索点和搜索结果之间的距离取决于八叉树的分辨率参数
    std::vector<int> pointIdxVec;
    //通过searchPoint确定其所在的体素,返回体素中所有的点的索引保存在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){
			if(cloud->points[pointIdxVec[i]].x==-0.5 && cloud->points[pointIdxVec[i]].y==-0.5 && cloud->points[pointIdxVec[i]].z==-0.5){
			    cloud->points[pointIdxVec[i]].r=0;
			    cloud->points[pointIdxVec[i]].g=255;
			    cloud->points[pointIdxVec[i]].b=0; 
			}else{
			    cloud->points[pointIdxVec[i]].r=255;
			    cloud->points[pointIdxVec[i]].g=0;
			    cloud->points[pointIdxVec[i]].b=0; 
			} 
            std::cout << "    " << cloud->points[pointIdxVec[i]].x
                      << " " << cloud->points[pointIdxVec[i]].y
                      << " " << cloud->points[pointIdxVec[i]].z << std::endl;
		}

    }


    pcl::toROSMsg(*cloud, output); 
    output.header.frame_id = "odom"; 
    ros::Rate loop_rate(1); 

    while (ros::ok()) { 
	pcl_pub.publish(output);
	ros::spinOnce(); 
	loop_rate.sleep(); 
    } 
    return 0;
}

在这里插入图片描述

方式二:K 近邻搜索

 	// 方式二:K 近邻搜索,本例中K被设置成10, "K 近邻搜索”方法把搜索结果写到两个分开的向量中,
    // 第一个pointIdxNKNSearch 包含搜索结果〈结果点的索引的向量〉
    // 第二个pointNKNSquaredDistance 保存相应的搜索点和近邻之间的距离平方。
    int K = 20;

    std::vector<int> pointIdxNKNSearch;
    std::vector<float> pointNKNSquaredDistance;

    std::cout << "K nearest neighbor search at (" << searchPoint.x
              << " " << searchPoint.y
              << " " << searchPoint.z
              << ") with K=" << K << std::endl;
    //searchPoint为搜索的点云对象、K为搜索返回的近邻个数、pointIdxNKNSearch返回近邻索引向量、pointNKNSquaredDistance 存储近邻点对应的距离平方向量
    if (octree.nearestKSearch(searchPoint, K, pointIdxNKNSearch, pointNKNSquaredDistance) > 0) {
        for (size_t i = 0; i < pointIdxNKNSearch.size(); ++i){
			if(cloud->points[pointIdxNKNSearch[i]].x==-0.5 && cloud->points[pointIdxNKNSearch[i]].y==-0.5 && cloud->points[pointIdxNKNSearch[i]].z==-0.5){
			    cloud->points[pointIdxNKNSearch[i]].r=0;
			    cloud->points[pointIdxNKNSearch[i]].g=255;
			    cloud->points[pointIdxNKNSearch[i]].b=0; 
			}else{
			    cloud->points[pointIdxNKNSearch[i]].r=255;
			    cloud->points[pointIdxNKNSearch[i]].g=0;
			    cloud->points[pointIdxNKNSearch[i]].b=0; 
			} 
            std::cout << "    " << cloud->points[pointIdxNKNSearch[i]].x
                      << " " << cloud->points[pointIdxNKNSearch[i]].y
                      << " " << cloud->points[pointIdxNKNSearch[i]].z
                      << " (squared distance: " << pointNKNSquaredDistance[i] << ")" << std::endl;
		}

    }
K nearest neighbor search at (-0.5 -0.5 -0.5) with K=20
    -0.5 -0.5 -0.5 (squared distance: 0)
    -0.5 -0.5 -1 (squared distance: 0.25)
    -0.5 -1 -0.5 (squared distance: 0.25)
    -1 -0.5 -0.5 (squared distance: 0.25)
    -1 -1 -0.5 (squared distance: 0.5)
    -0.5 -1 -1 (squared distance: 0.5)
    -1 -0.5 -1 (squared distance: 0.5)
    -1 -1 -1 (squared distance: 0.75)
    -0.5 -0.5 0.5 (squared distance: 1)
    -0.5 0.5 -0.5 (squared distance: 1)
    0.5 -0.5 -0.5 (squared distance: 1)
    -1.5 -0.5 -0.5 (squared distance: 1)
    -0.5 -0.5 -1.5 (squared distance: 1)
    -0.5 -1.5 -0.5 (squared distance: 1)
    -1 -0.5 -1.5 (squared distance: 1.25)
    -1.5 -1 -0.5 (squared distance: 1.25)
    0.5 -1 -0.5 (squared distance: 1.25)
    0.5 -0.5 -1 (squared distance: 1.25)
    -0.5 -1 0.5 (squared distance: 1.25)
    -1 -1.5 -0.5 (squared distance: 1.25)

在这里插入图片描述

方式三:半径内近邻搜索

    // 方式三:半径内近邻搜索
    // “半径内近邻搜索”原理和“K 近邻搜索”类似,它的搜索结果被写入两个分开的向量中,
    // 这两个向量分别存储结果点的索引和对应的距离平方
    std::vector<int> pointIdxRadiusSearch;
    std::vector<float> pointRadiusSquaredDistance;

    float radius = 1;

    std::cout << "Neighbors within radius search at (" << searchPoint.x
              << " " << searchPoint.y
              << " " << searchPoint.z
              << ") with radius=" << radius << std::endl;

    //searchPoint要搜索的点、radius半径、pointIdxRadiusSearch结果索引、pointRadiusSquaredDistance距离平方
    if (octree.radiusSearch(searchPoint, radius, pointIdxRadiusSearch, pointRadiusSquaredDistance) > 0) {
        for (size_t i = 0; i < pointIdxRadiusSearch.size(); ++i){
			if(cloud->points[pointIdxRadiusSearch[i]].x==-0.5 && cloud->points[pointIdxRadiusSearch[i]].y==-0.5 && cloud->points[pointIdxRadiusSearch[i]].z==-0.5){
			    cloud->points[pointIdxRadiusSearch[i]].r=0;
			    cloud->points[pointIdxRadiusSearch[i]].g=255;
			    cloud->points[pointIdxRadiusSearch[i]].b=0; 
			}else{
			    cloud->points[pointIdxRadiusSearch[i]].r=255;
			    cloud->points[pointIdxRadiusSearch[i]].g=0;
			    cloud->points[pointIdxRadiusSearch[i]].b=0; 
			} 
            std::cout << "    " << cloud->points[pointIdxRadiusSearch[i]].x
                      << " " << cloud->points[pointIdxRadiusSearch[i]].y
                      << " " << cloud->points[pointIdxRadiusSearch[i]].z
                      << " (squared distance: " << pointRadiusSquaredDistance[i] << ")" << std::endl;
		}

    }
Neighbors within radius search at (-0.5 -0.5 -0.5) with radius=1
    -1.5 -0.5 -0.5 (squared distance: 1)
    -1 -1 -1 (squared distance: 0.75)
    -1 -1 -0.5 (squared distance: 0.5)
    -1 -0.5 -1 (squared distance: 0.5)
    -1 -0.5 -0.5 (squared distance: 0.25)
    -0.5 -1.5 -0.5 (squared distance: 1)
    -0.5 -1 -1 (squared distance: 0.5)
    -0.5 -1 -0.5 (squared distance: 0.25)
    -0.5 -0.5 -1.5 (squared distance: 1)
    -0.5 -0.5 -1 (squared distance: 0.25)
    -0.5 -0.5 -0.5 (squared distance: 0)
    -0.5 -0.5 0.5 (squared distance: 1)
    -0.5 0.5 -0.5 (squared distance: 1)
    0.5 -0.5 -0.5 (squared distance: 1)

在这里插入图片描述

  • 4
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
八叉树路径规划是一种常用的算法,用于在给定环境中规划机器人的路径。RRT(Rapidly-exploring Random Tree,快速扩展随机树)是一种基于树的路径规划算法,适用于复杂的非完整环境。 在ROS(Robot Operating System,机器人操作系统)中,可以使用八叉树路径规划算法和RRT算法进行机器人的路径规划。ROS提供了强大的路径规划库,如move_base,可以方便地实现路径规划功能。 八叉树路径规划算法在ROS中的实现过程如下:首先,通过传感器获取机器人所在环境的地图信息,并将其转化为八叉树地图表示。然后,在八叉树中,以机器人当前位置为起始点,在地图中随机选择一个点作为目标点。接下来,在八叉树中利用RRT算法进行快速扩展,通过不断将树向目标点扩展,直到找到一条可行的路径。 在ROS中实现八叉树路径规划可以使用近似最近邻搜索算法,如KD-树,来加速RRT算法的扩展过程,并提高路径规划的效率。 八叉树路径规划的优势在于能够在复杂的环境中找到有效的路径,充分考虑机器人的运动限制和环境的障碍物分布情况。同时,通过RRT算法的随机性,可以有效避免陷入局部最优解的问题。 总之,八叉树路径规划和RRT算法是在ROS中常用的路径规划方法,能够实现机器人的自主导航和路径规划功能,提高机器人的移动效率和安全性。

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值