0.引言
\qquad
PCL的体素滤波器如果对超大容量点云进行降采样,要求降采样后的格点数目必须在整型的范围,不然就会报[pcl::VoxelGrid::applyFilter] Leaf size is too small for the input dataset. Integer indices would overflow
的错误。本文使用PCL中OcTree结构实现大容量点云的分块存储和分块体素降采样,以达到近似的全局体素降采样效果。
StackOverFlow 参考链接🔗
1.普通体素降采样
\qquad PCL普通的体素降采样只需要调用VoxelGrid库即可,这里给出了一个示例函数。只需要设置体素大小cell_x, cell_y, cell_z即可,其要求降采样后格点不能超过整型的最大值。对于激光雷达扫描的点云,一般原点云数超过10万就不能在再采用这个方法了。
#include <pcl/filters/extract_indices.h>
#include <pcl/filters/filter.h>
#include <pcl/filters/voxel_grid.h>
#include <pcl/point_types.h>
typedef pcl::PointXYZI PointType;
pcl::PointCloud<PointType>::Ptr FILTREexample(pcl::PointCloud<PointType>::Ptr pointcloud, pcl::IndicesPtr indices, float cell_x, float cell_y, float cell_z) {
pcl::PointCloud<PointType>::Ptr filtered_pointcloud(new pcl::PointCloud<PointType>);
pcl::VoxelGrid<PointType> sor;
sor.setInputCloud(pointcloud);
sor.setLeafSize(cell_x, cell_y, cell_z);
sor.filter(*filtered_pointcloud); // No problem :)
return filtered_pointcloud;
}
2.OcTree体素降采样
\qquad
PCL库中并没有给出直接的实例教程,所以本文在这里简要说明以下,VoxelGrid体素滤波器有一个函数sor.setIndices(indices);
,其中indices就是大体素点云拆分成一个个小点云团的分区序号数组,这个数组的构建通过OcrTree的近邻搜索加以构建,具体如下:
pcl::PointCloud<PointType>::Ptr subFilter(pcl::PointCloud<PointType>::Ptr pointcloud, pcl::IndicesPtr indices, float cell_x, float cell_y, float cell_z) {
pcl::PointCloud<PointType>::Ptr filtered_pointcloud(new pcl::PointCloud<PointType>);
pcl::VoxelGrid<PointType> sor;
sor.setInputCloud(pointcloud);
sor.setIndices(indices);
sor.setLeafSize(cell_x, cell_y, cell_z);
sor.filter(*filtered_pointcloud); // No problem :)
return filtered_pointcloud;
}
pcl::PointCloud<PointType>::Ptr OctFilter(pcl::PointCloud<PointType>::Ptr cloudIn, float cell_x, float cell_y, float cell_z) {
pcl::octree::OctreePointCloudSearch<PointType> octree(128); // // Octree resolution - side length of octree voxels
octree.setInputCloud(cloudIn);
octree.addPointsFromInputCloud();
pcl::PointCloud<PointType>::Ptr filtered_cloud(new pcl::PointCloud<PointType>);
for (auto it = octree.leaf_depth_begin(); it != octree.leaf_depth_end(); ++it)
{
pcl::IndicesPtr indexVector(new std::vector<int>);
pcl::octree::OctreeContainerPointIndices& container = it.getLeafContainer();
container.getPointIndices(*indexVector);
*filtered_cloud += *subFilter(cloudIn, indexVector, cell_x,cell_y,cell_z);
}
return filtered_cloud;
}
其中128是Octree的分辨率,一般较大的点云需要设的大一些,如果设的过小,还是有可能在调用子函数subFilter
产生相同的[pcl::VoxelGrid::applyFilter] Leaf size is too small for the input dataset. Integer indices would overflow
错误。一个简单的用法如下:
pcl::PointCloud<PointType>::Ptr laserCloudIn(new pcl::PointCloud<PointType>);
// TODO: Load PointCloud into laserCloudIN
pcl::PointCloud<PointType>::Ptr laserCloudOut(new pcl::PointCloud<PointType>);
*laserCloudOut = *OctFilter(laserCloudIn, 0.05f, 0.05f, 0.05f); // set your voxel size