谈及点云体素化是一种点云比较普遍的处理方式,之前的一篇博文【pcl入门教程滤波系列】之VoxelGrid有讲解点云体素化与近似体素化的情况。主要涉及两个函数pcl::VoxelGrid与pcl::ApproximateVoxelGrid的体素化方式,其中第一个是通过划分体素栅格求取每个栅格里面的点云重心来作为这个栅格的点云代表,而第二个则是依据栅格的中心点来代表该栅格的点云。当然,各有各的用在不同的场景。不知道你是否想过,为什么没有求取栅格中最低点的方法?这样对于划分体素栅格后获取最低点,有助于对地面点分割求取比较重要的一步。很庆幸,pcl::GridMinimum就是用来满足这个需求的。
点云划分网格可视化类pcl::GridMinimum就是通过将三维点云在X-Y平面划分网格,然后寻找每个网格中最小的z点云代表该网格。如果网格没有点云,那么不会像pcl::ApproximateVoxelGrid产生中心点代表该网格点云。
下面的代码就是通过pcl::GridMinimum实现网格化求取最小高程点云的算法示例,比较简单就不多做解释啦。
#include <iostream> #include <pcl/io/pcd_io.h> #include <pcl/point_types.h> #include <pcl/filters/grid_minimum.h> #include <chrono> int main(int argc, char** argv) { pcl::PointCloud<pcl::PointXYZI>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZI>); pcl::PointCloud<pcl::PointXYZI>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZI>); auto startTime = std::chrono::steady_clock::now(); // Fill in the cloud data pcl::PCDReader reader; // Replace the path below with the path where you saved your file reader.read("apollo.pcd", *cloud); // Create the filtering object pcl::GridMinimum<pcl::PointXYZI> sor(0.25); sor.setInputCloud(cloud); sor.filter(*cloud_filtered); std::cerr << "PointCloud before filtering: " << cloud->width * cloud->height << " data points ( " << pcl::getFieldsList(*cloud) << " )." << std::endl; std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points ( " << pcl::getFieldsList(*cloud_filtered) << " )." << std::endl; auto endTime = std::chrono::steady_clock::now(); auto ellapsedTime = std::chrono::duration_cast<std::chrono::milliseconds>(endTime - startTime); std::cerr << "Ellapse-Time: " << ellapsedTime.count() << " milliseconds." << std::endl; pcl::PCDWriter writer; writer.write("apollo_downsampled0.25.pcd", *cloud_filtered); return 0; }grid_minimum.h源码头文件分析
namespace pcl { /** \brief GridMinimum assembles a local 2D grid over a given PointCloud, and downsamples the data. * * The GridMinimum class creates a *2D grid* over the input point cloud * data. Then, in each *cell* (i.e., 2D grid element), all the points * present will be *downsampled* with the minimum z value. This grid minimum * can be useful in a number of topographic processing tasks such as crudely * estimating ground returns, especially under foliage. * * \author Bradley J Chambers * \ingroup filters */ template <typename PointT> class GridMinimum: public FilterIndices<PointT> { protected: using Filter<PointT>::filter_name_; using Filter<PointT>::getClassName; using Filter<PointT>::input_; using Filter<PointT>::indices_; using PointCloud = typename FilterIndices<PointT>::PointCloud; public: /** \brief Empty constructor. */ GridMinimum (const float resolution) { setResolution (resolution); filter_name_ = "GridMinimum"; } /** \brief Destructor. */ ~GridMinimum () { } /** \brief Set the grid resolution. * \param[in] resolution the grid resolution */ inline void setResolution (const float resolution) { resolution_ = resolution; // Use multiplications instead of divisions inverse_resolution_ = 1.0f / resolution_; } /** \brief Get the grid resolution. */ inline float getResolution () { return (resolution_); } protected: /** \brief The resolution. */ float resolution_; /** \brief Internal resolution stored as 1/resolution_ for efficiency reasons. */ float inverse_resolution_; /** \brief Downsample a Point Cloud using a 2D grid approach * \param[out] output the resultant point cloud message */ void applyFilter (PointCloud &output) override; /** \brief Filtered results are indexed by an indices array. * \param[out] indices The resultant indices. */ void applyFilter (std::vector<int> &indices) override { applyFilterIndices (indices); } /** \brief Filtered results are indexed by an indices array. * \param[out] indices The resultant indices. */ void applyFilterIndices (std::vector<int> &indices); }; }我们从上述源码头文件可以清晰的看出class GridMinimum类的唯一设置参数是resolution_ ,它可以通过构造函数显示进行初始化。当然,可以通过setResolution()函数进行设置分辨率。这个是与网格的大小有关,分辨率越小网格划分越密集,分辨率设置越大,网格划分越稀疏。类class GridMinimum 继承FilterIndices<PointT>因此只需要在构造函数初始化时候设置分辨率,就可以获取网格最小化后的点云结果。
下面我们看下不同分辨率情况下的网格化GridMinimum结果:
原始点云 分辨率0.5网格化后点云 分辨率1.0网格化后点云 分辨率2.0网格化后点云从上面实验结果来看,分辨率设置越小点云网格划分越密集,这样输出的网格后点云也更多。例如:分辨率为0.5时候,仔细发现中心周围车辆会出现一些蓝色的点。分辨率过大的话,网格会过于稀疏,例如分辨率为2.0的可视化效果。当然,不同分辨率计算的时间也会有一定的差距,需要依据实际场景来进行设置。pcl::GridMinimum能够有效的过滤高程信息间断的情况,例如车辆停在树下等,可以有效的找出最低点,为后续分割做准备。但是,如果树下没有车辆或者也没能够扫描出地面点,那么该网格的点可能就是扫描出树叶的最低点。这需要后续更进一步的处理。本篇博文主要介绍一下pcl::GridMinimum的应用,如有错误,还请批评指正。
https://pointclouds.org/documentation/classpcl_1_1_grid_minimum.html#a1ea51d3b624cbaf1dcba3af90d67c292