目录
一、概述
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;
}