目录

一、背景知识

二、实现流程

三、实现方法

四、代码实现

五、结果展示

一、背景知识

1、VS2017+pcl1.9.1配置:

Win10下 pcl1.9.1 +vs2017配置教程 - 哔哩哔哩

二、实现流程

1、直通滤波;

2、统计滤波;

3、欧式聚类分割;

4、根据点云Z值提取最上层平面。

三、实现方法

1、直通滤波

直通滤波的作用是过滤掉指定维度上取值不在给定值范围内的点,算法原理如下:设定滤波维度(比如x维度、y维度、z维度)及该维度下的值域,遍历所有点,判断遍历到的点在指定维度上的取值是否在指定值域内,删除不在值域内的点。直通滤波主要用于消除目标物以外的背景。

在PCL中pcl::PassThrough类实现直通滤波操作,pcl::PassThrough主要函数如下:

void setFilterFieldName (const std : :string &field_name)

设置限定维度名称,如"x"、"y"、"z"、"intensity"等

void setFilterLimits (const double &limit_min, const double & limit_max)

设置指定维度的滤波条件,参数limit_min为指定维度的最小值,limit_max为指定维度的最大值。指定维度的最小值最大值获取方法:(1)可以使用pcl::getMinMax3D(*cloud,min,max)来获取,然后通过min.x可以获取维度x的最小值;但是更简单、更直观的方法是通过CloudCompare软件来看,相较于点云的方法,CloudCompare可以更直观的看到哪些部分要剔除,以及剔除点对应的xyz坐标值,

CloudCompare官网下载,软件如下,鼠标点击对应的点,会出现当前点的坐标值:

2、统计滤波

(1)算法背景

在点云采集过程中,会产生密度不均匀的点云,这些点在进行特征计算时运算复杂,更会导致错误的计算等。统计滤波的目的就是提出这些离群点,离群点往往由测量噪声引入,在点云空间中分布稀疏,所包含的信息量较少。考虑到离群点的这些特征,定义某点附近点云小于某个密度,则表示该处点云属于离群点。

(2)算法计算

计算某点到其最近的k个点的平均距离,点云中所有带你的距离构成高斯分布,形状有均值及标准差决定。设点云中第m个点的坐标为Pm(Xm,Ym,Zm),到任一点Pn(Xn,Yn,Zn)的距离为:

计算Pm到k领域内的任意点之间距离的平均值为:

标准差为:

在算法实现过程中,需要输入两个参数k和stddev,其中k为点云领域内的点云数,stddev为标准差的倍数,当某点附近k个点的平均距离在范围内则保留该点,否则剔除改点。

pcl中通过pcl::StatisticalOutlierRemoval类来实现统计滤波,主要函数如下:

void setMeanK (int nr_k)//设置点云领域的点个数
void setStddevMulThresh (double stddev_mult)//设置判断是否为离群点的阈值,表示标准差的倍数

3、欧式聚类分割

欧式聚类是一种基于欧式距离度量的聚类分割算法。对于空间中的某点P,首先通过KD_Tree近邻搜索算法找到距离P最近的点,如果这些点的距离小于设定的阈值便聚类到集合Q中。如果Q中元素数目不再增加,整个聚类过程结束;否则需在聚合Q中选取P以外的点,重复上述过程,知道Q中元素的额数目不再增加。

核心代码为:

pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;// 欧式聚类对象ec.setClusterTolerance(0.02);                     // 设置近邻搜索的搜索半径为2cm(也即两个不同聚类团点之间的最小欧氏距离)ec.setMinClusterSize(30000);                        // 设置一个聚类需要的最少的点数目为100ec.setMaxClusterSize(2500000);                      // 设置一个聚类需要的最大点数目为25000ec.setSearchMethod(tree);                         // 设置点云的搜索机制ec.setInputCloud(cloud_filtered);ec.extract(cluster_indices);                      // 从点云中提取聚类,并将点云索引保存在cluster_indices中

4、根据点云Z值提取最上层平面。

根据欧式聚类之后,点云被分成各个点云区域,计算每个点云区域中点的z轴均值,最小或最大均值对应的区域即为最上层点云区域。

四、代码实现

#pragma once
#include <iostream>
#include <string>
#include <vector>
#include <pcl/point_types.h>
#include <pcl/PCLPointCloud2.h>
#include <pcl/console/time.h>
#include <pcl/filters/passthrough.h>
#include <pcl/filters/statistical_outlier_removal.h>
#include <pcl/filters/extract_indices.h>
#include <pcl/features/normal_3d_omp.h>
#include <pcl/kdtree/kdtree.h>
#include <pcl/sample_consensus/model_types.h>
#include <pcl/segmentation/region_growing.h>
#include <pcl/segmentation/sac_segmentation.h>
#include <pcl/segmentation/extract_clusters.h>
#include <pcl/features/boundary.h>
#include <pcl/filters/morphological_filter.h>
#include <pcl/common/transforms.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/io/pcd_io.h>
#include <pcl/io/ply_io.h>
#include <pcl/point_types.h>int main(int argc, char** argv)
{double _top_layer_height = 0.0;pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_top_layer(new pcl::PointCloud<pcl::PointXYZ>);//------------------------------------读取点云数据----------------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_in(new pcl::PointCloud<pcl::PointXYZ>());pcl::io::loadPLYFile("./data/test.ply", *cloud_in);//------------------------------------直通滤波,提出无用边界------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr tmp_cloud_ptr = pcl::PointCloud<pcl::PointXYZ>().makeShared();pcl::PassThrough<pcl::PointXYZ> pass;//创建直通滤波器对象//对X方向直通滤波pass.setInputCloud(cloud_in);pass.setFilterFieldName("x");pass.setFilterLimits(-0.7, 1.0);pass.filter(*tmp_cloud_ptr);//对Y方向直通滤波pass.setInputCloud(tmp_cloud_ptr);pass.setFilterFieldName("y");pass.setFilterLimits(-0.8, 0.6);pass.filter(*tmp_cloud_ptr);//对Z方向直通滤波pass.setInputCloud(tmp_cloud_ptr);pass.setFilterFieldName("z");pass.setFilterLimits(1.5, 2.8);pass.filter(*tmp_cloud_ptr);//------------------------------------统计滤波,提出离群点---------------------------------//第一次统计滤波,主要是去除明显的离群点pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;sor.setInputCloud(tmp_cloud_ptr);sor.setMeanK(15);//查询点的近邻数sor.setStddevMulThresh(2.5);//设置判断是否为离群点的阈值,表示标准差的倍数sor.filter(*tmp_cloud_ptr);//第二次统计滤波sor.setInputCloud(tmp_cloud_ptr);sor.setMeanK(15);sor.setStddevMulThresh(0.5);sor.filter(*tmp_cloud_ptr);//------------------------------------欧式聚类,连通域点云分割---------------------------//欧式聚类,适用于没有连通性的点云聚类分割std::vector <pcl::PointCloud<pcl::PointXYZ>::Ptr> extracted_clouds;pcl::search::KdTree<pcl::PointXYZ>::Ptr tree(new pcl::search::KdTree<pcl::PointXYZ>());std::vector<pcl::PointIndices> cloud_indices;pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec;//创建欧式聚类对象tree->setInputCloud(tmp_cloud_ptr);ec.setClusterTolerance(0.003);//设置近邻搜索的半径ec.setMinClusterSize(30000);//设置聚类搜索最少的点数目ec.setMaxClusterSize(25000000);//设置聚类搜索最大的点数目ec.setSearchMethod(tree);//设置点云的搜索机制ec.setInputCloud(tmp_cloud_ptr);ec.extract(cloud_indices);//从点云中提取聚类,并将点云索引保存在cloud_indicesint segedClusterNum = 0;for (std::vector<pcl::PointIndices>::const_iterator it = cloud_indices.begin(); it != cloud_indices.end(); ++it){pcl::PointCloud<pcl::PointXYZ>::Ptr sub_cloud(new pcl::PointCloud<pcl::PointXYZ>);for (std::vector<int>::const_iterator pit = it->indices.begin(); pit != it->indices.end(); pit++){sub_cloud->points.push_back(tmp_cloud_ptr->points[*pit]);}sub_cloud->width = tmp_cloud_ptr->points.size();sub_cloud->height = 1;sub_cloud->is_dense = true;extracted_clouds.push_back(sub_cloud);segedClusterNum++;}//------------------------------------确定最上层平面---------------------------------pcl::PointCloud<pcl::PointXYZ>::Ptr seged_cloud;pcl::PointCloud<pcl::PointXYZ>::Ptr top_cloud;int j = 0;int top_index = 0;double average_z = 0;double min_z = 0;if (0 != extracted_clouds.size()){for (std::vector<pcl::PointCloud<pcl::PointXYZ>::Ptr>::const_iterator it = extracted_clouds.begin(); it != extracted_clouds.end(); ++it){seged_cloud = extracted_clouds[j];double sum_z = 0;for (int i = 0; i < seged_cloud->points.size(); i++)sum_z += seged_cloud->points[i].z;average_z = sum_z / seged_cloud->points.size();//计算每个提取点云的平均Z值if (j == 0){min_z = average_z;top_cloud = seged_cloud;j++;}else{if (min_z > average_z){top_cloud = seged_cloud;min_z = average_z;top_index++;}j++;}}top_cloud->width = top_cloud->points.size();top_cloud->height = 1;top_cloud->is_dense = true;_top_layer_height = min_z;cloud_top_layer = top_cloud;//------------------------点云显示------------------------------------pcl::visualization::PCLVisualizer viewer("3D Viewer");viewer.setBackgroundColor(0, 0, 0);//viewer.addCoordinateSystem (1.0);viewer.initCameraParameters();//--------------------平面上的点云 红色------------------------------pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_plane_handler(cloud_in, 255, 0, 0);viewer.addPointCloud(cloud_in, cloud_plane_handler, "plan point");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "plan point");//--------------------平面外的点云 绿色------------------------------pcl::visualization::PointCloudColorHandlerCustom<pcl::PointXYZ> cloud_cluster_handler(cloud_top_layer, 0, 255, 0);viewer.addPointCloud(cloud_top_layer, cloud_cluster_handler, "cloud_cluster point");viewer.setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "cloud_cluster point");while (!viewer.wasStopped()) {viewer.spinOnce(100);boost::this_thread::sleep(boost::posix_time::microseconds(100000));}return 0;}else{return -2;}
}

五、结果展示

上层点云分割(C++PCL)相关推荐

  1. 传统方法的点云分割以及PCL中分割模块

    点击上方"小白学视觉",选择加"星标"或"置顶" 重磅干货,第一时间送达 摘要 三维点云分割是将同属性的点云物体分割出来,以便于单独对该点云 ...

  2. 斯坦福的著名小兔子模型的点云数据_传统方法的点云分割以及PCL中分割模块

    之前在微信公众号中更新了以下几个章节 1,如何学习PCL以及一些基础的知识 2,PCL中IO口以及common模块的介绍 3,  PCL中常用的两种数据结构KDtree以及Octree树的介绍 有兴趣 ...

  3. PCL 点云分割与分类 Segmentation RANSAC随机采样一致性 平面模型分割 欧氏距离分割 区域聚类分割算法 最小分割算法 超体聚类 渐进式形态学滤波器

    点云分割 博文末尾支持二维码赞赏哦 _ 点云分割是根据空间,几何和纹理等特征对点云进行划分, 使得同一划分内的点云拥有相似的特征,点云的有效分割往往是许多应用的前提, 例如逆向工作,CAD领域对零件的 ...

  4. 【PCL自学:Segmentation1】基于PCL的点云分割:平面模型分割

    基于PCL的点云平面模型分割 1.什么是点云分割 2.如何使用PCL库对将点云中平面模型分割出来 1.什么是点云分割   顾名思义,点云分割就是将一团点云按照不同需求进行分割处理,一般是用在识别或测量 ...

  5. PCL点云分割(1)

    点云分割是根据空间,几何和纹理等特征对点云进行划分,使得同一划分内的点云拥有相似的特征,点云的有效分割往往是许多应用的前提,例如逆向工作,CAD领域对零件的不同扫描表面进行分割,然后才能更好的进行空洞 ...

  6. PCL—低层次视觉—点云分割(基于凹凸性)

    1.图像分割的两条思路 场景分割时机器视觉中的重要任务,尤其对家庭机器人而言,优秀的场景分割算法是实现复杂功能的基础.但是大家搞了几十年也还没搞定--不是我说的,是接下来要介绍的这篇论文说的.图像分割 ...

  7. PCL—点云分割(基于凹凸性) 低层次点云处理

    博客转载自:http://www.cnblogs.com/ironstark/p/5027269.html 1.图像分割的两条思路 场景分割时机器视觉中的重要任务,尤其对家庭机器人而言,优秀的场景分割 ...

  8. PCL之点云分割算法概述

    PCL中提供了点云分割的基础数据结构和部分通用算法,目前实现的算法主要是基于聚类分割思想和基于随机采样一致性的分割算法,以下对这两种方法的原理进行介绍: 1) 基于聚类分割算法 在聚类方法中每个点都与 ...

  9. 【PCL自学:Segmentation3】基于PCL的点云分割:区域增长分割

    基于PCL的点云区域增长分割 一.什么是区域增长分割 二.区域增长分割原理剖析 三.区域增长分割示例代码 一.什么是区域增长分割   在本文中,我们将学习如何使用pcl:: regiongrow类中实 ...

最新文章

  1. Linux下锁用户与解锁问题
  2. 在移动安全领域,人工智能未来该扮演怎样的角色?
  3. Python自动化开发学习的第十一周----WEB基础(jquery)
  4. java中生成不重复随机的数字
  5. 前端学习(1980)vue之电商管理系统电商系统之实现文本框和按钮的切换
  6. 【JDK1.8】JDK1.8集合源码阅读——Set汇总
  7. python抽取指定url页面的title_Python使用scrapy爬虫,爬取今日头条首页推荐新闻
  8. OpenCV基本函数使用--Python
  9. php pdo总结,php 总结(10) PDO 连接数据库 预处理
  10. Python 网页爬虫 文本处理 科学计算 机器学习 数据挖掘兵器谱 - 数客
  11. Internet路由之路由表查找算法概述-哈希/LC-Trie树/256-way-mtrie树
  12. java aapt linux_Android:linux下aapt使用 | 学步园
  13. android 串流 ps4,就想要玩游戏!PS4有线串流到笔记本电脑实战
  14. 软件测试实验二条件覆盖和条件组合覆盖
  15. python pandas 数据透视表_python 用pandas实现数据透视表功能
  16. 室内地图导航应用小程序-前端知识体系图
  17. Matlab中pause语句
  18. Android手机投影到电脑屏幕的神兵利器
  19. -1岁的产品经理日记——part3(面经篇)
  20. ANDROID 实现微信通讯录界面

热门文章

  1. 虫师 python_2019虫师自动化 Python接口自动化虫师 robotframework虫师 虫师接口自动化源码下载...
  2. 猿来小课Linux教程分享Shell脚本问题大全
  3. Spring框架学习笔记(三)(AOP,事务管理)
  4. 移动开发——音乐小程序服务器搭建
  5. 几种常见web 容器比较
  6. Arduino+2.4G模块做航模遥控器
  7. php下载图片excel过大,PHPExcel导出图片大小设置问题
  8. 创业实践案例课程报告
  9. android 蓝牙之数据传输
  10. 用模拟退火算法(simulated annealing / SA)求函数最小值