PCL滤波—从一个点云中提取一个子集——ExtractIndices滤波器——索引滤波器 索引滤波的官方教程添加链接描述 使用该方法结合降采样和统计滤波可以很好的完成地面分离。 此处是索引滤波头文件
#include <pcl/filters/extract_indices.h>此处是重点,距离阈值的参数影响计算速度和地面分割精度,不同模型的参数不一样,一般是0.01-0.2之间取值
seg.setMaxIterations(100); //设置最大迭代次数 seg.setDistanceThreshold(0.15); //设置判断是否为模型内点的距离阈值此处是判断保留内点还是反向选取,false是保留内点,true是反选
extract.setIndices(inliers); extract.setNegative(false); extract.filter(*cloud_p);这里加了一个循环结构,当还有60%原始点云数据时退出循环
while (cloud_filtered->points.size() > 0.6 * nr_points)以下是原代码和最终效果,保留了汽车分割掉了地面。 本文参考了添加链接描述
//索引滤波 #include <iostream> #include <pcl/ModelCoefficients.h> #include <pcl/io/ply_io.h> #include <pcl/point_types.h> #include <pcl/sample_consensus/method_types.h> #include <pcl/sample_consensus/model_types.h> #include <pcl/segmentation/sac_segmentation.h> #include <pcl/filters/voxel_grid.h> #include <pcl/filters/extract_indices.h> #include<pcl/visualization/cloud_viewer.h> #include <pcl/filters/statistical_outlier_removal.h> int main(int argc, char** argv) { //sensor_msgs::PointCloud2::Ptr cloud_blob (new sensor_msgs::PointCloud2), cloud_filtered_blob (new sensor_msgs::PointCloud2); pcl::PCLPointCloud2::Ptr cloud_blob(new pcl::PCLPointCloud2); pcl::PCLPointCloud2::Ptr cloud_filtered_blob(new pcl::PCLPointCloud2); pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>), cloud_p(new pcl::PointCloud<pcl::PointXYZ>), cloud_f(new pcl::PointCloud<pcl::PointXYZ>); // 填入点云数据 pcl::PLYReader reader; reader.read("C:\\Users\\fhlhc\\Desktop\\car_left.ply", *cloud_blob); std::cerr << "PointCloud before filtering: " << cloud_blob->width * cloud_blob->height << " data points." << std::endl; // 创建滤波器对象:使用叶大小为1cm的下采样 pcl::VoxelGrid< pcl::PCLPointCloud2> sor; //体素栅格下采样对象 sor.setInputCloud(cloud_blob); //设置下采样原始点云数据 sor.setLeafSize(0.06f, 0.06f, 0.06f); //设置采样的体素大小 sor.filter(*cloud_filtered_blob); //执行采样保存数据cloud_filtered_blob 统计滤波器,删除离群点 pcl::StatisticalOutlierRemoval<pcl::PCLPointCloud2> Static; //创建滤波器对象 Static.setInputCloud(cloud_filtered_blob); //设置待滤波的点云 Static.setMeanK(50); //设置在进行统计时考虑查询点临近点数 Static.setStddevMulThresh(0.5); //设置判断是否为离群点的阀值 Static.filter(*cloud_filtered_blob); //存储 // 转化为模板点云 //pcl::fromROSMsg(*cloud_filtered_blob, *cloud_filtered); pcl::fromPCLPointCloud2(*cloud_filtered_blob, *cloud_filtered); std::cerr << "PointCloud after filtering: " << cloud_filtered->width * cloud_filtered->height << " data points." << std::endl; // 将下采样后的数据存入磁盘 pcl::PLYWriter writer; //writer.write<pcl::PointXYZ>("table_scene_lms400_downsampled.pcd", *cloud_filtered, false); pcl::ModelCoefficients::Ptr coefficients(new pcl::ModelCoefficients()); pcl::PointIndices::Ptr inliers(new pcl::PointIndices()); pcl::SACSegmentation<pcl::PointXYZ> seg; //创建分割对象 //可选 seg.setOptimizeCoefficients(true); //设置对估计的模型参数进行优化处理 //必选 seg.setModelType(pcl::SACMODEL_PLANE); //设置分割模型类别 seg.setMethodType(pcl::SAC_RANSAC); //设置用哪个随机参数估计方法 seg.setMaxIterations(100); //设置最大迭代次数 seg.setDistanceThreshold(0.15); //设置判断是否为模型内点的距离阈值 // 创建滤波器对象 pcl::ExtractIndices<pcl::PointXYZ> extract; int i = 0, nr_points = (int)cloud_filtered->points.size(); //为了处理点云中包含多个模型,在一个循环中执行该过程, //并在每次模型被提取后,我们保存剩余的点,进行迭代; //模型内点通过分割过程获取; //当还有60%原始点云数据时退出循环 while (cloud_filtered->points.size() > 0.6 * nr_points) { // 从余下的点云中分割最大平面组成部分 seg.setInputCloud(cloud_filtered); seg.segment(*inliers, *coefficients); if (inliers->indices.size() == 0) { std::cerr << "Could not estimate a planar model for the given dataset." << std::endl; break; } // 分离内层 extract.setInputCloud(cloud_filtered); extract.setIndices(inliers); extract.setNegative(false); extract.filter(*cloud_p); std::cerr << "PointCloud representing the planar component: " << cloud_p->width * cloud_p->height << " data points." << std::endl; std::stringstream ss; ss << "table_scene_lms400_plane_" << i << ".pcd"; // writer.write<pcl::PointXYZ>(ss.str(), *cloud_p, false); // 创建滤波器对象 extract.setNegative(true); extract.filter(*cloud_f); cloud_filtered.swap(cloud_f); i++; } cout << "迭代次数:"<<i << endl; pcl::visualization::CloudViewer viewer("Cloud Viewer"); //创建viewer对象 viewer.showCloud(cloud_f); // viewer.runOnVisualizationThreadOnce(viewerOneOff); while (!viewer.wasStopped()) { //在此处可以添加其他处理 } return (0); }