目录
一、概述
1.1原理
1.2实现步骤
1.3应用场景
二、代码实现
2.1关键函数
2.1.1 八叉树构建
2.1.2 获取体素中心
2.2完整代码
三、实现效果
PCL点云算法汇总及实战案例汇总的目录地址链接:
PCL点云算法与项目实战案例汇总(长期更新)
一、概述
在三维点云处理中,八叉树 是一种常用的数据结构,用来对三维空间进行递归划分。在 PCL 中,八叉树不仅可以用于搜索和变化检测,还可以用于计算每个体素(Voxel)的中心点,这对于空间划分、点云简化等应用十分有用。
1.1原理
八叉树通过递归地将三维空间划分为多个子区域(体素),每个体素的边界由其最小和最大坐标定义,体素的中心是该最小和最大边界的中点。通过计算体素的中心点,可以获得该体素的空间位置,用于后续的点云处理。
1.2实现步骤
- 读取点云数据。
- 使用 pcl::octree::OctreePointCloud 创建八叉树并构建体素。
- 遍历八叉树中的每个体素,获取其最小和最大边界。
- 计算每个体素的中心点,存储并可视化体素中心点。
1.3应用场景
- 空间划分可视化:通过计算体素的中心点,展示空间的分布。
- 点云简化:使用体素中心点作为简化后的点云代表点。
- 邻域搜索:通过体素中心点快速找到空间中的目标区域。
二、代码实现
2.1关键函数
2.1.1 八叉树构建
通过 pcl::octree::OctreePointCloud 构建八叉树,并根据点云数据生成体素。
#include <pcl/octree/octree_pointcloud.h>// 设置八叉树分辨率
float resolution = 0.05f; // 分辨率决定了体素的大小
pcl::octree::OctreePointCloud<pcl::PointXYZ> octree(resolution);// 构建八叉树
octree.setInputCloud(cloud); // cloud 是输入点云
octree.addPointsFromInputCloud(); // 生成八叉树
2.1.2 获取体素中心
通过 getVoxelBounds 获取每个体素的最小和最大边界,并计算其中心点。
Eigen::Vector3f min_pt, max_pt; // 用于存储体素的最小和最大边界
std::vector<Eigen::Vector3f> voxel_centers; // 存储体素中心点// 遍历八叉树的每个叶子节点(体素)
for (auto it = octree.leaf_begin(); it != octree.leaf_end(); ++it)
{octree.getVoxelBounds(it, min_pt, max_pt); // 获取体素的边界// 计算体素中心点Eigen::Vector3f center = (min_pt + max_pt) / 2.0f;voxel_centers.push_back(center); // 将中心点存储起来
}
2.2完整代码
#include <iostream>
#include <vector>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/octree/octree_pointcloud.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <Eigen/Dense>// 封装的可视化函数
void visualizePointCloudsWithOctree(pcl::PointCloud<pcl::PointXYZ>::Ptr cloud, // 原始点云pcl::PointCloud<pcl::PointXYZ>::Ptr voxel_center_cloud) // 体素中心点云
{// 创建可视化窗口pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Dual PointCloud Viewer"));// 设置视口1,显示原始点云int vp_1;viewer->createViewPort(0.0, 0.0, 0.5, 1.0, vp_1); // 左侧窗口viewer->setBackgroundColor(1.0, 1.0, 1.0, vp_1); // 白色背景viewer->addText("Original PointCloud", 10, 10, "vp1_text", vp_1); // 标题pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_color_handler(cloud, 0, 255, 0); // 绿色viewer->addPointCloud(cloud, cloud_color_handler, "original_cloud", vp_1);// 设置视口2,显示体素中心点云int vp_2;viewer->createViewPort(0.5, 0.0, 1.0, 1.0, vp_2); // 右侧窗口viewer->setBackgroundColor(1.0, 1.0, 1.0, vp_2); // 白色背景viewer->addText("Voxel Center PointCloud", 10, 10, "vp2_text", vp_2); // 标题pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> voxel_center_color_handler(voxel_center_cloud, 255, 0, 0); // 红色viewer->addPointCloud(voxel_center_cloud, voxel_center_color_handler, "voxel_center_cloud", vp_2);// 设置点的大小viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "original_cloud", vp_1);viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 4, "voxel_center_cloud", vp_2);// 添加坐标系viewer->addCoordinateSystem(0.1);viewer->initCameraParameters();// 可视化循环while (!viewer->wasStopped()){viewer->spinOnce(100);}
}int main(int argc, char** argv)
{// -----------------------------读取点云数据---------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);if (pcl::io::loadPCDFile<pcl::PointXYZ>("bunny.pcd", *cloud) == -1){PCL_ERROR("Couldn't read the PCD file!\n");return -1;}// -----------------------------构建八叉树---------------------------------float resolution = 0.01f; // 八叉树分辨率pcl::octree::OctreePointCloud<pcl::PointXYZ> octree(resolution);octree.setInputCloud(cloud); // 设置输入点云octree.addPointsFromInputCloud(); // 生成八叉树// -----------------------------计算体素中心---------------------------------Eigen::Vector3f min_pt, max_pt; // 用于存储体素的最小和最大边界pcl::PointCloud<pcl::PointXYZ>::Ptr voxel_center_cloud(new pcl::PointCloud<pcl::PointXYZ>); // 存储体素中心点云// 遍历八叉树的每个叶子节点(体素)for (auto it = octree.leaf_begin(); it != octree.leaf_end(); ++it){octree.getVoxelBounds(it, min_pt, max_pt); // 获取体素的边界pcl::PointXYZ point;point.x = (min_pt.x() + max_pt.x()) / 2.0f; // 计算中心点point.y = (min_pt.y() + max_pt.y()) / 2.0f;point.z = (min_pt.z() + max_pt.z()) / 2.0f;voxel_center_cloud->points.push_back(point); // 将中心点添加到点云}voxel_center_cloud->width = voxel_center_cloud->points.size();voxel_center_cloud->height = 1;voxel_center_cloud->is_dense = true;// -----------------------------可视化---------------------------------visualizePointCloudsWithOctree(cloud, voxel_center_cloud);return 0;
}