转自:https://blog.csdn.net/Small_Munich/article/details/108348164
VoxelGrid体素采样
pcl库中的VoxelGrid对点云进行体素化,主要就是创建一个三维体素栅格(就是每个比较小的立方体组成的体素栅格)。在每个体素(三维立方体)里面,求取该立方体内的所有点云重心点来代表这个立方体的表示,以此达到下采样的目的。
class pcl::ApproximateVoxelGrid<PointT>
class pcl::VoxelGrid<PointT>
class pcl::VoxelGird<pcl::PCLPointCloud2>
对于体素下采样接口功能函数pcl提供了两种方式: pcl::ApproximateVoxelGrid和pcl::VoxelGrid。两种区别主要在于第一种是用每个体素栅格的中心点来近似该体素内的点,提升了速度,但是也损失了原始点云的局部形态精细度。
主要应用函数
// 设置每个体素的大小, leaf_size没别为lx ly lz的长 宽 高 inline void setLeafSize (const Eigen::Vector3f &leaf_size); // 不同的接口输入方式 inline void setLeafSize (float lx, float ly, float lz);
<span class="token comment">// 获取每个体素的大小</span> <span class="token keyword">inline</span> Eigen<span class="token operator">::</span>Vector3f getLeafSize <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 设置下采样的维度,默认false, 只对XYZ进行下采样;true为对所有下采样</span> <span class="token keyword">inline</span> <span class="token keyword">void</span> setDownsampleAllData <span class="token punctuation">(</span><span class="token keyword">bool</span> downsample<span class="token punctuation">)</span><span class="token punctuation">;</span> <span class="token comment">// 获取下采样的方式是否为XYZ还是全部下采样</span> <span class="token keyword">inline</span> <span class="token keyword">bool</span> getDownsampleAllData <span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
VoxelGrid / ApproximateVoxelGrid的Demo代码
#include <iostream>
#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/filters/approximate_voxel_grid.h>
#include <chrono>
int main(int argc, char argv)
{
// pcl::PCLPointCloud2::Ptr cloud(new pcl::PCLPointCloud2());
// pcl::PCLPointCloud2::Ptr cloud_filtered(new pcl::PCLPointCloud2());
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>);
pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZI>);
<span class="token keyword">auto</span> startTime <span class="token operator">=</span> std<span class="token operator">::</span>chrono<span class="token operator">::</span>steady_clock<span class="token operator">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Fill in the cloud data</span>
pcl<span class="token operator">::</span>PCDReader reader<span class="token punctuation">;</span>
<span class="token comment">// Replace the path below with the path where you saved your file </span>
reader<span class="token punctuation">.</span><span class="token function">read</span><span class="token punctuation">(</span><span class="token string">"table_scene_lms400.pcd"</span><span class="token punctuation">,</span> <span class="token operator">*</span>cloud<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// Create the filtering object</span>
<span class="token comment">// pcl::VoxelGrid<pcl::PCLPointCloud2> sor;</span>
<span class="token comment">// pcl::VoxelGrid<pcl::PointXYZI> sor;</span>
pcl<span class="token operator">::</span>ApproximateVoxelGrid<span class="token operator"><</span>pcl<span class="token operator">::</span>PointXYZI<span class="token operator">></span> sor<span class="token punctuation">;</span>
sor<span class="token punctuation">.</span><span class="token function">setInputCloud</span><span class="token punctuation">(</span>cloud<span class="token punctuation">)</span><span class="token punctuation">;</span>
sor<span class="token punctuation">.</span><span class="token function">setLeafSize</span><span class="token punctuation">(</span><span class="token number">0.02f</span><span class="token punctuation">,</span> <span class="token number">0.02f</span><span class="token punctuation">,</span> <span class="token number">0.02f</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token comment">// sor.setDownsampleAllData(true);</span>
sor<span class="token punctuation">.</span><span class="token function">filter</span><span class="token punctuation">(</span><span class="token operator">*</span>cloud_filtered<span class="token punctuation">)</span><span class="token punctuation">;</span>
std<span class="token operator">::</span>cerr <span class="token operator"><<</span> <span class="token string">"PointCloud before filtering: "</span> <span class="token operator"><<</span> cloud<span class="token operator">-</span><span class="token operator">></span>width <span class="token operator">*</span> cloud<span class="token operator">-</span><span class="token operator">></span>height
<span class="token operator"><<</span> <span class="token string">" data points ( "</span> <span class="token operator"><<</span> pcl<span class="token operator">::</span><span class="token function">getFieldsList</span><span class="token punctuation">(</span><span class="token operator">*</span>cloud<span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">" )."</span> <span class="token operator"><<</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
std<span class="token operator">::</span>cerr <span class="token operator"><<</span> <span class="token string">"PointCloud after filtering: "</span> <span class="token operator"><<</span> cloud_filtered<span class="token operator">-</span><span class="token operator">></span>width <span class="token operator">*</span> cloud_filtered<span class="token operator">-</span><span class="token operator">></span>height
<span class="token operator"><<</span> <span class="token string">" data points ( "</span> <span class="token operator"><<</span> pcl<span class="token operator">::</span><span class="token function">getFieldsList</span><span class="token punctuation">(</span><span class="token operator">*</span>cloud_filtered<span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">" )."</span> <span class="token operator"><<</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
<span class="token keyword">auto</span> endTime <span class="token operator">=</span> std<span class="token operator">::</span>chrono<span class="token operator">::</span>steady_clock<span class="token operator">::</span><span class="token function">now</span><span class="token punctuation">(</span><span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">auto</span> ellapsedTime <span class="token operator">=</span> std<span class="token operator">::</span>chrono<span class="token operator">::</span>duration_cast<span class="token operator"><</span>std<span class="token operator">::</span>chrono<span class="token operator">::</span>milliseconds<span class="token operator">></span><span class="token punctuation">(</span>endTime <span class="token operator">-</span> startTime<span class="token punctuation">)</span><span class="token punctuation">;</span>
std<span class="token operator">::</span>cerr <span class="token operator"><<</span> <span class="token string">"Ellapse-Time: "</span> <span class="token operator"><<</span> ellapsedTime<span class="token punctuation">.</span><span class="token function">count</span><span class="token punctuation">(</span><span class="token punctuation">)</span> <span class="token operator"><<</span> <span class="token string">" milliseconds."</span> <span class="token operator"><<</span> std<span class="token operator">::</span>endl<span class="token punctuation">;</span>
pcl<span class="token operator">::</span>PCDWriter writer<span class="token punctuation">;</span>
writer<span class="token punctuation">.</span><span class="token function">write</span><span class="token punctuation">(</span><span class="token string">"2000line_downsampled.pcd"</span><span class="token punctuation">,</span> <span class="token operator">*</span>cloud_filtered<span class="token punctuation">)</span><span class="token punctuation">;</span>
<span class="token keyword">return</span> <span class="token number">0</span><span class="token punctuation">;</span>
}
示例性代码,比较简单就不多做解释了。下面看一看跑这个代码对比一下VoxelGrid与ApproximateVoxelGrid的实验结果:



Filter | ApproximateVoxelGrid | VoxelGrid |
---|---|---|
点云滤波前/滤波后 | 460400/29186 | 460400/11598 |
时间/milliseconds | 93 | 107 |
不知你是否注意到这两种方法下采样后的点云个数不一致,主要原因在于ApproximateVoxelGrid是依据每一个体素的中心点来获取点云的,并不是依赖每个体素里面是否存在点云。所以会导致两种方式的处理结果又偏差,VoxelGrid的方式更加精确但是耗时相对于ApproximateVoxelGrid更高。
小结
点云体素下采样针对大量点云时候能够有效的保存点云空间结构同时提升算法的运行效率。基于体素的点云编码方式也是当下应用较多的一种点云处理方法。
参考
https://pointclouds.org/documentation/classpcl_1_1_approximate_voxel_grid.html
https://pcl.readthedocs.io/projects/tutorials/en/latest/voxel_grid.html#voxelgrid