• kdTree相关原理及c++实现


    kdTree概念

            kd-tree或者k维树是计算机科学中使用的一种数据结构,用来组织表示k维空间中点的集合。它是一种带有其他约束条件的二分查找树。Kd-tree对于区间和近邻搜索十分有用。一般位于三维空间中的邻域搜索常用kd-tree,因此本文中所有的kd-tree都是三维的kd-tree。

    图一 kdTree说明

    图一

            Kd-tree也是二叉树的一种,首先我们先选定一个维度用于第一次分类,如图一所示,我们先选择x维度方向作为分类方向,随机选取一个值使得小于该值的点位于左边,大于该值的点位于右边。在左右区域分别再对第二个维度进行分类,这里以y轴方向作为第二维度,同理根据y分类设置z轴方向为第三维度进行分类。

    Kd-tree数据结构定义

    Node-data:数据矢量,数据集中某个数据点,是n维矢量(总维度,unsigned int)

    Range:空间矢量,该节点所代表的的空间范围(二维数组)

    Split:整数,垂直于分割超平面的方向轴序号(int)

    Left:k-d树,由位于该节点分割超平面左侧子空间内所有点构成的k-d树(tuple<list,int>)

    Right:k-d树,由位于该节点分割超平面右侧子空间内所有点构成的k-d树(tuple<list,int>)

    Parent:k-d树,父节点(auto)

    Kd-tree优化

            方案一:Kd-tree通过不同维度划分数据,节点的选择显得尤为重要。我们可以想象一组点云,并不是完全随机离散的,只在某一维度上点云分布较为离散,其余维度相对集中。以三维空间为例,一组类似球状的点云在求每个方向的子节点能保证效率是最高的,但是数据接近一个平面时,在其中一个维度的划分就显得十分困难。

            解决方法:首先,对于点云分布不集中的那一维度来说,方差较大,我们可以通过最大方差法选择每次需要分类的维度,即在每次进行新的划分之前,我们通过判断方差选择在哪个维度上进行划分。

            方案二:为了保证每次选择的节点尽量位于中间位置,也就是让二叉树尽量为二叉平衡树,从而保证节点两侧的点云数目大致相等。

            解决方法:在选取节点前,我们对数据进行排序,选取中位数作为节点,这样就能保证两侧数据大致相等。

     PCL库c++源码

     1 #include <iostream>
     2 #include <pcl/point_types.h>
     3 #include <pcl/io/pcd_io.h>
     4 #include <pcl/kdtree/impl/kdtree_flann.hpp>
     5 #include <pcl/kdtree/kdtree_flann.h>
     6 #include <pcl/kdtree/kdtree.h>
     7 #include <pcl/kdtree/io.h>
     8 #include <pcl/kdtree/flann.h>
     9 #include <pcl/search/kdtree.h>
    10 #include <pcl/features/normal_3d.h>
    11 #include <pcl/kdtree/impl/io.hpp>
    12 #include <pcl/search/flann_search.h>
    13 #include <pcl/surface/gp3.h>
    14 //#include <pcl/visualization/pcl_visualizer.h>
    15 
    16 int main(int argc, char* argv[])
    17 {
    18     pcl::PointCloud<pcl::PointXYZ>::Ptr inCloud(new pcl::PointCloud<pcl::PointXYZ>);
    19     //construct a plane, the equation is x + y + z = 1
    20     for (float x = -1.0; x <= 1.0; x += 0.005)
    21     {
    22         for (float y = -1.0; y <= 1.0; y += 0.005)
    23         {
    24             pcl::PointXYZ cloud;
    25 
    26             cloud.x = x;
    27             cloud.y = y;
    28             cloud.z = 1 - x - y;
    29         
    30             inCloud->push_back(cloud);
    31         }
    32     }
    33 
    34     pcl::NormalEstimation<pcl::PointXYZ, pcl::Normal> ne;
    35     pcl::PointCloud<pcl::Normal>::Ptr pcNormal(new pcl::PointCloud<pcl::Normal>);
    36     pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>);
    37     tree->setInputCloud(inCloud);
    38     ne.setInputCloud(inCloud);
    39     ne.setSearchMethod(tree);
    40     ne.setKSearch(50);
    41     //ne->setRadiusSearch (0.03); 
    42     ne.compute(*pcNormal);
    43 
    44     pcl::PointCloud<pcl::PointXYZINormal>::Ptr cloud_with_normals(new pcl::PointCloud<pcl::PointXYZINormal>);
    45     pcl::concatenateFields(*inCloud, *pcNormal, *cloud_with_normals);
    46 
    47     pcl::io::savePCDFile("plane_cloud_out.pcd", *cloud_with_normals);
    48 
    49     return 0;
    50 }
    View Code

    【 结束 】

  • 相关阅读:
    Java JDK和IntelliJ IDEA 配置及安装
    来吧学学.Net Core之登录认证与跨域资源使用
    来吧学学.Net Core之项目文件简介及配置文件与IOC的使用
    【转载】任正非:我的父亲母亲
    HTTP协议中的短轮询、长轮询、长连接和短连接
    跨域资源共享CORS详解
    C#各个版本中的新增特性详解
    仓央嘉措不负如来不负卿
    Redis Sentinel实现的机制与原理详解
    Redis的发布订阅及.NET客户端实现
  • 原文地址:https://www.cnblogs.com/fujj/p/9691245.html
Copyright © 2020-2023  润新知