PCL—voxel点云网格化
在PCL(Point Cloud Library)中,Voxel(体素) 是一个核心概念,用于将三维点云数据离散化到规则的网格结构中。其意义主要体现在以下几个方面:
1. 点云降采样(Downsampling)
• 数据压缩:点云通常包含大量冗余数据(例如数百万个点),直接处理效率低。通过将点云划分为体素网格,每个体素内的点被合并为一个代表性点(如取中心点或平均值),可显著减少数据量,同时保留整体形状特征。
• 加速计算:降采样后的点云适用于需要快速迭代的场景(如配准、分割、目标检测),可降低算法复杂度。
代码示例。
pcl::VoxelGrid<pcl::PointXYZ> voxel;
voxel.setInputCloud(cloud);
voxel.setLeafSize(0.01f, 0.01f, 0.01f); // 设置体素边长(单位:米)
voxel.filter(*downsampled_cloud);
2. 去噪与平滑
• 统计滤波:结合体素内点的分布统计(如密度、方差),可过滤离群噪点。
• 均匀化分布:体素化可消除点云密度不均的问题(例如激光雷达近处密集、远处稀疏的特性)
3. 特征提取与结构表示
• 几何特征保留:体素化后的规则结构便于计算表面法线、曲率等特征。
• 深度学习输入:体素网格可直接转换为3D卷积神经网络(如VoxelNet)的输入张量,用于分类、分割等任务。
• 八叉树(Octree):基于体素的分层数据结构,支持快速空间查询(如近邻搜索、碰撞检测)
4. 点云配准(Registration)
• 粗配准加速:降采样后的点云可快速计算初始变换(如使用ICP算法的粗略对齐阶段)。
• 多分辨率配准:结合不同体素尺寸的层次化处理,提升配准精度和效率。
5. 三维重建与表面生成
• 隐式曲面重建:体素化后可通过TSDF(Truncated Signed Distance Function)等算法生成连续的表面模型(如用于SLAM或三维打印)。
• 体积渲染:在医学成像或科学可视化中,体素可直接表示密度、颜色等体数据。
6. 存储与索引优化
• 空间索引:体素将无序点云映射到规则网格,便于基于空间位置的快速检索(如查找某区域内的点)。
• 压缩存储:某些格式(如.pcd或.xyz)支持体素化后的紧凑存储。
注意事项
• 体素尺寸选择:过大的体素会丢失细节,过小则无法有效降采样。需根据应用场景和传感器精度调整(例如,激光雷达点云常用0.01-0.1米边长)。
• 权衡效率与精度:体素化是计算效率与几何保真度之间的折中方案,需根据任务需求调整策略。
总结
Voxel化通过将点云从无序散点转换为规则结构,解决了大规模点云处理中的效率、噪声和密度不均等问题,是3D计算机视觉、机器人感知和三维重建中的基础操作。
以下是个代码例子。
//摘自PCL(Point Cloud Library)学习记录(2025) · 语雀
/*
* @Description: 2VoxelGrid滤波器对点云进行下采样 https://www.cnblogs.com/li-yao7758258/p/6445831.html
* @Author: HCQ
* @Company(School): UCAS
* @Email: 1756260160@qq.com
* @Date: 2020-10-20 10:50:23
* @LastEditTime: 2020-10-20 11:00:48
* @FilePath: /pcl-learning/09filters滤波/2VoxelGrid滤波器对点云进行下采样/voxel_grid.cpp
*/
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
//#include "visual_.h"
int main(int argc, char** argv)
{
pcl::PCLPointCloud2::Ptr cloud(new pcl::PCLPointCloud2());
pcl::PCLPointCloud2::Ptr cloud_filtered(new pcl::PCLPointCloud2());
//点云对象的读取
pcl::PCDReader reader;
reader.read("D:/tool_s/PCL/pcl-pcl-1.11.1/test/office1.pcd", *cloud); //读取点云到cloud中
std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height
<< " data points (" << pcl::getFieldsList(*cloud) << ").";
//show//
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz0(new pcl::PointCloud<pcl::PointXYZ>);
pcl::fromPCLPointCloud2(*cloud, *cloud_xyz0);
//pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("03D_Viewer"));
//viewer->setBackgroundColor(0, 0, 0);
//viewer->addPointCloud<pcl::PointXYZ>(cloud_xyz0, "0sample_cloud");
//viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "0sample_cloud");
//viewer->addCoordinateSystem(1.0, "global");
//
// showCloud_sn(cloud_xyz0, 0);
/******************************************************************************
创建一个voxel叶大小为1cm的pcl::VoxelGrid滤波器,
**********************************************************************************/
pcl::VoxelGrid<pcl::PCLPointCloud2> sor; //创建滤波对象
sor.setInputCloud(cloud); //设置需要过滤的点云给滤波对象
sor.setLeafSize(0.1f, 0.1f, 0.1f); //设置滤波时创建的体素体积为1cm的立方体(0.01f, 0.01f, 0.01f)
sor.filter(*cloud_filtered); //执行滤波处理,存储输出
std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height
<< " data points (" << pcl::getFieldsList(*cloud_filtered) << ").";
//保存
//pcl::PCDWriter writer; //保存极慢!//
//writer.write("../table_scene_lms400_downsampled.pcd", *cloud_filtered,
// Eigen::Vector4f::Zero(), Eigen::Quaternionf::Identity(), false);
//pcl::io::savePCDFile("saveName.pcd", *cloud);
//show//
pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_xyz(new pcl::PointCloud<pcl::PointXYZ>);
pcl::fromPCLPointCloud2(*cloud_filtered, *cloud_xyz);
// showCloud_s0(cloud_xyz,"001");
return (0);
}
代码中的visual可视化部分可参考我的另一篇文章:PCL—点云加载、可视化-CSDN博客