【PCL常用滤波器】Uniform Sampling滤波器

一、算法原理

        均匀采样滤波器与体素滤波器类似,都需要将点云空间划分为规则的3D网格(体素voxel)。不同之处在于,均匀采样滤波器不是保留体素内所有点的质心,而是选择距离体素中心最近的点作为代表点输出,能在空间上实现更均匀的采样效果。在实现上,Uniform Sampling算法采用unordered_map数据结构来存储体素信息,算法流程如下所述:

1. 设置点云在空间维度上的采样半径r, 对应分辨率 l_{xyz}

2. 根据点云包围盒边界计算每个维度划分的网格数

\left\{\begin{matrix} n_{x} = \left \lfloor \frac{x_{max}- x_{min}}{l_{xyz}} \right \rfloor \\ n_{y} = \left \lfloor \frac{y_{max}- y_{min}}{l_{xyz}} \right \rfloor \\ n_{z} = \left \lfloor \frac{z_{max}- z_{min}}{l_{xyz}} \right \rfloor \end{matrix}\right.

3. 对于点云中的每个点,确定每个点的网格索引

\left\{\begin{matrix} i_{x} = \left \lfloor \frac{x- x_{min}}{l_{xyz}} \right \rfloor \\ i_{y} = \left \lfloor \frac{y- y_{min}}{l_{xyz}} \right \rfloor \\ i_{z} = \left \lfloor \frac{z- z_{min}}{l_{xyz}} \right \rfloor \\ i = i_{x} + i_{y} * n_{x} + i_{z} * n_{x} * n_{y} \end{matrix}\right.

4. 对于落在同一体素网格内的点,选择离网格中心最近的点输出

二、底层细节

1. 对于点云中的每个点计算网格索引后,将网格索引和累加器存储到unordered_map类型的leaves_变量中

struct Leaf
{
    Leaf() = default;
    int idx{ -1 };
    unsigned int count{ 0 };
};

/** \brief The 3D grid leaves. */
std::unordered_map<std::size_t, Leaf> leaves_;


Eigen::Vector4i ijk = Eigen::Vector4i::Zero();
ijk[0] = static_cast<int> (std::floor((*input_)[cp].x * inverse_leaf_size_[0]));
ijk[1] = static_cast<int> (std::floor((*input_)[cp].y * inverse_leaf_size_[1]));
ijk[2] = static_cast<int> (std::floor((*input_)[cp].z * inverse_leaf_size_[2]));

// Compute the leaf index
int idx = (ijk - min_b_).dot(divb_mul_);
Leaf& leaf = leaves_[idx];

// Increment the count of points in this voxel
++leaf.count;

2. 对于同一网格索引的点,选择最靠近体素中心的点输出

// Compute the voxel center
Eigen::Vector4f voxel_center = (ijk.cast<float>() + Eigen::Vector4f::Constant(0.5)) * search_radius_;
voxel_center[3] = 0;
// Check to see if this point is closer to the leaf center than the previous one we saved
float diff_cur = ((*input_)[cp].getVector4fMap() - voxel_center).squaredNorm();
float diff_prev = ((*input_)[leaf.idx].getVector4fMap() - voxel_center).squaredNorm();

// If current point is closer, copy its index instead
if (diff_cur < diff_prev)
{
    if (extract_removed_indices_)
        (*removed_indices_)[rii++] = leaf.idx;
    leaf.idx = cp;
}
else
{
    if (extract_removed_indices_)
        (*removed_indices_)[rii++] = cp;
}
  }
  removed_indices_->resize(rii);

  // Second pass: go over all leaves and copy data
  indices.resize(leaves_.size());
  for (const auto& leaf : leaves_)
  {
      if (leaf.second.count >= min_points_per_voxel_)
          indices[oii++] = leaf.second.idx;
  }

三、PCL代码示例

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/uniform_sampling.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <iostream>

int main(int argc, char** argv)
{
    // 1. 加载点云
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ>("truck.pcd", *cloud) == -1) {
        PCL_ERROR("无法读取 truck.pcd 文件\n");
        return -1;
    }
    std::cout << "原始点云数量: " << cloud->points.size() << std::endl;

    // 2. 均匀采样滤波
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::UniformSampling<pcl::PointXYZ> uniform;
    uniform.setInputCloud(cloud);
    uniform.setRadiusSearch(0.2f); // 半径 (单位: 米)
    uniform.filter(*cloud_filtered); // 直接生成输出点云

    std::cout << "滤波后点云数量: " << cloud_filtered->points.size() << std::endl;

    // 3. 可视化对比
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("Uniform Sampling Filter Demo"));

    int v1(0), v2(1);

    // 左窗口:原始点云
    viewer->createViewPort(0.0, 0.0, 0.5, 1.0, v1);
    viewer->setBackgroundColor(0, 0, 0, v1);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_orig(cloud, 255, 255, 255);
    viewer->addPointCloud(cloud, color_orig, "original_cloud", v1);

    // 右窗口:滤波后点云
    viewer->createViewPort(0.5, 0.0, 1.0, 1.0, v2);
    viewer->setBackgroundColor(0, 0, 0, v2);
    pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_uniform(cloud_filtered, 0, 255, 0);
    viewer->addPointCloud(cloud_filtered, color_uniform, "filtered_cloud", v2);

    // 设置点大小
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 2, "original_cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 3, "filtered_cloud");

    // 循环显示
    viewer->initCameraParameters();
    while (!viewer->wasStopped()) {
        viewer->spinOnce(100);
    }

    return 0;
}

四、效果展示

五、总结

        均匀采样滤波器通过在空间中规则采样,使点云分布更均匀,特别适合特征提取、配准和重建等对点分布要求较高的场景。

<think>好的,我现在需要帮助用户了解PCL库中关于Mesh采样的用法或实现。首先,我要回忆一下PCL的相关知识,特别是网格处理部分。PCL点云库)主要用于处理点云数据,但也支持网格处理,比如Mesh的采样、滤波等操作。用户提到的Mesh采样可能是指将Mesh表面采样生成点云,或者进行下采样简化网格结构。 接下来,我需要确认PCL中是否有直接的Mesh采样类或函数。记得PCL中的poisson模块可能涉及表面重建,但具体的采样方法可能需要查阅文档。另外,PCL的常见采样方法有VoxelGrid采样、随机采样等,但这些通常用点云数据,而不是网格。不过,网格采样可能涉及将Mesh转换为点云再进行采样,或者使用特定的网格采样算法。 然后,我应该考虑用户可能的实际需求。用户可能想从一个三维网格模型中生成均匀分布的点云数据,或者简化网格的顶点数量。这时候,可能需要使用PCL中的UniformSampling类,或者是Mesh的顶点采样方法。例如,UniformSampling可以通过设置半径来均匀采样点。 此外,代码示例对用户会有帮助,我需要回忆如何编写PCL的Mesh采样代码。可能需要加载Mesh文件,创建采样对象,设置参数,然后执行采样。需要注意的是,PCL的Mesh处理可能需要使用VTK库的支持,因为PCL的Mesh结构依赖于VTK的数据类型。 另外,用户可能遇到一些问题,比如编译时的依赖项缺失,或者采样结果不均匀。需要提醒用户安装必要的依赖,如VTK,并确保正确配置PCL。同时,参数设置如采样半径会影响结果,需要根据网格尺寸调整。 最后,应该生成相关问题,帮助用户深入理解Mesh采样的其他方面,比如不同采样方法的区别、参数优化、结果评估等。这些问题可以引导用户进一步探索PCL的功能和应用场景。</think>在PCL点云库)中,Mesh采样常用于将三维网格表面转换为点云数据或简化网格结构。以下是实现步骤和关键方法: ### 1. **PCL中的Mesh采样方法** PCL通过`UniformSampling`类实现网格表面均匀采样,其核心原理是基于空间体素化生成均匀分布的点云: $$ \text{采样密度} \propto \frac{1}{voxel\_size^3} $$ ### 2. **代码实现示例** ```cpp #include <pcl/io/vtk_lib_io.h> #include <pcl/surface/uniform_sampling.h> pcl::PolygonMesh mesh; pcl::io::loadPolygonFileVTK("input_mesh.vtk", mesh); // 读取网格文件 pcl::PointCloud<pcl::PointXYZ>::Ptr sampled_cloud(new pcl::PointCloud<pcl::PointXYZ>); pcl::UniformSampling<pcl::PointXYZ> sampler; sampler.setInputCloud(mesh.cloud); // 输入网格顶点数据 sampler.setRadiusSearch(0.02); // 设置采样半径(单位:米) sampler.filter(*sampled_cloud); // 执行采样 ``` ### 3. **关键参数说明** - `setRadiusSearch()`:决定采样密度,值越小采样点越密集 - 输入需为`pcl::PointCloud<T>`类型,需将网格顶点转换为点云结构[^1] ### 4. **进阶方法** - **泊松盘采样**:通过`pcl::Poisson`类实现非均匀但更自然的分布 - **顶点聚类简化**:使用`pcl::MeshQuadricSimplification`减少网格面片数量 ### 5. **注意事项** - 需安装VTK库支持网格文件读写 - 采样前建议使用`pcl::MeshSmoothing`进行预处理 - 输出点云可直接用于表面重建算法如MLS或RANSAC[^2]
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值