pcl点云库的使用05:提取点云数据中的非地面点的方法

1 几个主要的类

1.1 StatisticalOutlierRemoval类

基于统计方法移除点云中的离散点的类,对每个点,我们计算它到它的所有临近点的平均距离。假设得到的结果是一个高斯分布,其形状由均值和标准差决定,平均距离在标准范围(由全局距离平均值和方差定义)之外的点,可被定义为离群点并可从数据集中去除掉。

//读取点云
pcl::PCDReaderreader;//定义读取对象
reader.read<pcl::PointXYZ>("table_scene_lms400.pcd",*cloud);//读取点云文件

///点云滤波//
pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;// 创建滤波器对象
sor.setInputCloud(cloud);                        //设置待滤波的点云
sor.setMeanK(50);                                //设置在进行统计时考虑查询点邻近点数
sor.setStddevMulThresh(1.0);                    //设置判断是否为离群点的阈值
sor.filter(*cloud_filtered);                    //执行滤波处理保存内点到cloud_filtered

//如果要提取外点
//sor.setNegative(true);
//sor.filter(*cloud_filtered);

//输出滤波后的点云个数
cout << sor_cloud->size() << endl;

//输出滤波结果
writer.write<pcl::PointXYZ>("table_scene_lms400_outliers.pcd",*cloud_filtered,false);

1.2 SACSegmentation分割类

几个重要的成员函数

函数功能
inline void setModelType (int model)

所提取目标模型的属性(平面、球、圆柱等等)。

enum SacModel
  {
    SACMODEL_PLANE,
    SACMODEL_LINE,
    SACMODEL_CIRCLE2D,
    SACMODEL_CIRCLE3D,
    SACMODEL_SPHERE,
    SACMODEL_CYLINDER,
    SACMODEL_CONE,
    SACMODEL_TORUS,
    SACMODEL_PARALLEL_LINE,
    SACMODEL_PERPENDICULAR_PLANE,
    SACMODEL_PARALLEL_LINES,
    SACMODEL_NORMAL_PLANE,
    SACMODEL_NORMAL_SPHERE,
    SACMODEL_REGISTRATION,
    SACMODEL_PARALLEL_PLANE,
    SACMODEL_NORMAL_PARALLEL_PLANE,
    SACMODEL_STICK
  };

inline voidsetMethodType (int method)

采样方法

namespace pcl
{
  const static int SAC_RANSAC  = 0;
  const static int SAC_LMEDS   = 1;
  const static int SAC_MSAC    = 2;
  const static int SAC_RRANSAC = 3;
  const static int SAC_RMSAC   = 4;
  const static int SAC_MLESAC  = 5;
  const static int SAC_PROSAC  = 6;
}

inline void setDistanceThreshold (doublethreshold)

查询点到目标模型的距离阈值

(如果大于此阈值,则查询点不在目标模型上,默认值为0)。

inline void setMaxIterations (intmax_iterations)最大迭代次数(默认值为50)。
inline void setProbability (double probability)至少一个样本不包含离群点的概率(默认值为0.99)
virtual void segment (PointIndices &inliers,ModelCoefficients &model_coefficients)

输出提取点的索引和目标模型的参数

inline void setInputCloud (const PointCloudConstPtr &cloud) 

设置输入点云

一个分割代码片段

SACSegmentation<PoinT> sac;//创建分割对象
PointIndices::Ptr inliner(new PointIndices);
ModelCoefficients::Ptr coefficients(new ModelCoefficients);
PointCloud<PoinT>::Ptr sac_cloud(new PointCloud<PoinT>);
sac.setInputCloud(sor_cloud);//设置输入点云
sac.setMethodType(SAC_RANSAC);//选择随机抽样一致性算法
sac.setModelType(SACMODEL_PLANE);//提取的是平面
sac.setMaxIterations(100);//最大迭代次数为100
sac.setDistanceThreshold(0.01);//距离阈值为0.01
sac.setProbability(0.95);
sac.segment(*inliers, *coefficients);

1.3 ExtractIndices根据点云索引提取点云子集

ExtractIndices<PoinT>ext;//创建提取点云索引对象
ext.setInputCloud(sor_cloud);//设置输入点云数据
ext.setIndices(inliner);//设置点云索引
ext.setNegative(false);//保留内点
ext.filter(*ext_cloud);//滤波


ext.setNegative(true);//保留外点
ext.filter(*ext_cloud_rest);//滤波

//内点的分层可视化
visualization::PointCloudColorHandlerCustom<PoinT> rgb1(ext_cloud, rand() % 255, rand() % 255, rand() % 255);//提取的平面不同随机彩色展示
visualization::PCLVisualizer viewer;
viewer.addPointCloud(ext_cloud, rgb1, ss.str());

2 分离的示例代码及结果

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/ModelCoefficients.h>
#include <pcl/filters/extract_indices.h>
#include<ctime>
#include<cstdlib>
#include <windows.h>
#include "deal.h"
using namespace pcl;
using namespace std;
//显示点云
void cloudShow(string cloudFileName)
{
	pcl::PointCloud<pcl::PointXYZ> cloud1;
	int ret = pcl::io::loadPCDFile(cloudFileName, &cloud1);
	pcl::visualization::CloudViewer viewer("Cloud Viewer");
	viewer.showCloud(&cloud1);
    viewer.runOnVisualizationThreadOnce(viewerOneOff);//设置控制台的背景色
    while(!viewer.wasStopped()){
    
    }
}
//设置显示的背景色
void viewerOneOff(pcl::visualization::PCLVisualizer& viewer)
{
    viewer.setBackgroundColor(0,0,1);
}

//剔除地面点
void splitGround()
{
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PCDReader reader;
    // 读入点云PCD文件
    reader.read("desk.pcd",*cloud);
 
    std::cerr << "Point cloud data: " << cloud->points.size () << " points" << std::endl;
    
    pcl::ModelCoefficients::Ptr coefficients (new pcl::ModelCoefficients);
    pcl::PointIndices::Ptr inliers (new pcl::PointIndices);
    // Create the segmentation object
    pcl::SACSegmentation<pcl::PointXYZ> seg;
    // Optional
    seg.setOptimizeCoefficients (true);
    // Mandatory
    seg.setModelType (pcl::SACMODEL_PLANE);
    seg.setMethodType (pcl::SAC_RANSAC);
    // 距离阈值 单位m
    seg.setDistanceThreshold (0.15);
    seg.setInputCloud (cloud);
    seg.segment (*inliers, *coefficients);
    if (inliers->indices.size () == 0)
    {
        PCL_ERROR ("Could not estimate a planar model for the given dataset.");
        return;
    }
 
 
    // 提取地面
    pcl::ExtractIndices<pcl::PointXYZ> extract;
    extract.setInputCloud (cloud);
    extract.setIndices (inliers);
    extract.filter (*cloud_filtered);
 
    std::cerr << "Ground cloud after filtering: " << std::endl;
    std::cerr << *cloud_filtered << std::endl;
 
    pcl::PCDWriter writer;
    writer.write<pcl::PointXYZ> ("3dpoints_ground.pcd", *cloud_filtered, false);
 
    // 提取除地面外的物体
    extract.setNegative (true);
    extract.filter (*cloud_filtered);
 
    std::cerr << "Object cloud after filtering: " << std::endl;
    std::cerr << *cloud_filtered << std::endl;
 
    writer.write<pcl::PointXYZ> ("3dpoints_object.pcd", *cloud_filtered, false);
 
    // 点云可视化
    pcl::visualization::CloudViewer viewer("Filtered");
    viewer.showCloud(cloud_filtered);
    viewer.runOnVisualizationThreadOnce(viewerOneOff);
    while(!viewer.wasStopped()){
    
    }
	system("pause");
    return;
}

int main()
{
	splitGround();
	return 0;
}

原始点云

滤波结果(地面点已经被过滤掉):

参考阅读

PCL: Segmentation模块之SACSegmentation点云分割

如果你需要其他测试数据,可查阅该网址

 

  • 8
    点赞
  • 46
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 4
    评论
如果你想使用PCL(Point Cloud Library)来对数据进行物体提取,以下是一个示例代码: ```cpp <iostream> #include <pcl/iopcd_io.h> #include <pcl/point_types.h> #include <pcl/segmentation/extract_clusters.h> int() { // 读取点云数据 pcl::PointCloud<pcl::PointXYZ>::Ptr cloud(new pcl::PointCloud<pcl::PointXYZ>); if (pcl::io::loadPCDFile<pcl::PointXYZ>("point_cloud.pcd", *cloud) == -1) { PCL_ERROR("Couldn't read file"); return -1; } // 进行点云分割 pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>); tree->setInputCloud(cloud); std::vector<pcl::PointIndices> cluster_indices; pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec; ec.setClusterTolerance(0.2); // 簇的距离容差 ec.setMinClusterSize(10); // 最小簇的数 ec.setMaxClusterSize(25000); // 最大簇的数 ec.setSearchMethod(tree); ec.setInputCloud(cloud); ec.extract(cluster_indices); // 进行物体提取 std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr> objects; for (const auto &indices : cluster_indices) { pcl::PointCloud<pcl::PointXYZ>::Ptr object(new pcl::PointCloud<pcl::PointXYZ>); for (const auto &index : indices.indices) { object->points.push_back(cloud->points[index]); } object->width = object->points.size(); object->height = 1; object->is_dense = true; objects.push_back(object); } // 可视化结果 pcl::visualization::PCLVisualizer viewer("Objects"); int color = 0; for (const auto &object : objects) { pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> color_handler(object, color % 256, (color + 128) % 256, (color + 64) % 256); viewer.addPointCloud(object, color_handler, "object" + std::to_string(color)); color++; } viewer.spin(); return 0; } ``` 在这个示例,我们首先使用`pcl::io::loadPCDFile`函数读取点云数据。然后,我们设置点云分割的参数,并使用`pcl::EuclideanClusterExtraction`类进行点云分割。我们可以通过调整`setClusterTolerance`、`setMinClusterSize`和`setMaxClusterSize`等函数来控制分割的精度和簇的大小。 接下来,我们遍历每个簇的索引,将对应的点云提取出来,并存储在`objects`向量。 最后,我们使用PCL的可视化模块`pcl::visualization::PCLVisualizer`来可视化提取出的物体。 请注意,此示例仅提供了一个简单的实现,实际应用可能需要根据具体情况进行参数调整和算法优化。同时,还可以使用其他PCL的功能来进一步处理和分析提取出的物体。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

小薛引路

喜欢的读者,可以打赏鼓励一下

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值