《点云处理》 点云去噪
前言
通常从传感器(3D相机、雷达)中获取到的点云存在噪点(杂点、离群点、孤岛点等各种叫法)。噪点产生的原因有不同,可能是扫描到了不想要扫描的物体,可能是待测工件表面反光形成的,也可能是相机内部的原因。在进行其他算法处理之前,通常需要先去除噪声,避免带来干扰。去噪的方法有很多,效率和效果也是各不相同,应用场景也不太一样,本篇内容就是想要将不同的去噪方法进行归纳。
环境:
Windows + VS2019 + PCL1.11.1
在开始之前,先贴出用于测试的点云,可以看出来空间中漂浮了很多噪点。原始点云总数为5882482个点,x和y方向间距为0.05。
1.半径滤波
PCL中集成有半径滤波,可以用于噪点的去除。主要需要设定两个参数,一个是搜索半径,另一个是在搜索半径内近邻点的最小数量。这两个参数需要根据点云的x,y,z方向上的点间距来设定(或者说分辨率)。一般使用线扫相机或者结构光相机这类3D相机得到的点在x,y方向上间距都比较均匀。假设点间距是0.05,那么将搜索半径设置为0.1,则搜索半径内理论上在上下左右方向上分别有2个点,共8个点,所以近邻点最起码也有8个。
头文件:
#include <pcl/filters/radius_outlier_removal.h>
代码如下:
/// <summary>
/// 使用半径滤波进行点云噪点去除
/// </summary>
/// <param name="cloud">输入点云</param>
/// <param name="cloud_out">输出除噪后的点云</param>
/// <param name="radius">搜索半径</param>
/// <param name="neighbors">单个搜索内近邻点数</param>
/// <returns>return true表示去噪成功,return false表示失败</returns>
bool NoiseRemoveROR(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, const float& radius,const int& neighbors)
{if (cloud == nullptr) return false;if (cloud->points.size() < 10) return false;pcl::RadiusOutlierRemoval<pcl::PointXYZ> rorfilter(true); // 初始化为true以获取被移除的索引rorfilter.setInputCloud(cloud);rorfilter.setRadiusSearch(radius); // 设置搜索半径rorfilter.setMinNeighborsInRadius(neighbors); // 设置搜索半径内满足的点数//rorfilter.setUserFilterValue(1); // 将不符合要求的点更改为新的值,而不是去去除它们,与setKeepOrganized一起使用//rorfilter.setKeepOrganized(false); // 保证有序点云的结构,与setUserFilterValue一起使用rorfilter.filter(*cloud_out); // 进行离群点去除return true;
}
一般近邻点的数量设置与搜索半径有直接关系。而经过测试发现,搜索的近邻点数量需要越多则耗时越长。较小的搜索半径只需要设置较小数量的近邻点,但是这样可能会导致有的噪点去除不干净。稍大一点的搜索半径以及近邻点数量适当调大可以得到更稳定的去噪效果。因此,效果和效率之间需要找到一个平衡点。
测试及结果:搜索半径设置为0.2,近邻点数量为20,耗时10.94s。效果如下:
针对于半径滤波耗时问题其实可以将点云使用直通滤波分成若干份,然后使用OpenMP对这几份点云并行处理进行半径滤波,将结果再合并成一个点云,这个方法可能能够起到加速的作用。
有一篇论文《Fast Radius Outlier Filter Variant for Large Point Clouds》,更快速的半径滤波,还未找到源码,若有人找到请联系我,感谢。
2.统计学滤波
统计学滤波也是一种比较常见的去噪算法。其官方解释如下:
The statistical outlier removal process is a bit more refined. First, for every point, the mean distance to its K neighbors is computed. Then, if we asume that the result is a normal (gaussian) distribution with a mean μ and a standard deviation σ, we can deem it safe to remove all points with mean distances that fall out of the global mean plus deviation. Basically, it runs a statistical analysis of the distances between neighboring points, and trims all which are not considered “normal” (you define what “normal” is with the parameters of the algorithm).
个人理解就是遍历点云,对于每个点,都先搜索与其最相近的k个点,计算这k个点与该点的距离,并得到一个平均距离和一个平均距离的标准差。然后比较距离是否是大于μ+stddev*σ,如果大于则表示是离群点。
头文件:#include <pcl/filters/statistical_outlier_removal.h>
代码如下:
/// <summary>
/// 使用PCL中集成的统计学滤波进行去噪
/// </summary>
/// <param name="cloud">输入点云</param>
/// <param name="cloud_out">输出点云</param>
/// <param name="k">搜索近邻点的个数</param>
/// <param name="stddev">平均距离标准差的乘数</param>
/// <returns>return true表示去噪成功,return false表示失败</returns>
bool NoiseRemoveSOR(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_out, const int& k, const double& stddev)
{if (cloud == nullptr) return false;if (cloud->points.size() < 10) return false;pcl::StatisticalOutlierRemoval<pcl::PointXYZ> filter; // Filter object.filter.setInputCloud(cloud);filter.setMeanK(k); // Set number of neighbors to consider to K.filter.setStddevMulThresh(stddev); // Points with a distance larger than stddev standard deviation of the mean distance will be outliers.filter.filter(*cloud_out);return true;
}
使用这个统计学滤波感觉还是十分耗时,但是效果确实是不错的。
测试及结果:近邻点k值的数量为20,系数设定为1.0,耗时11.07s。效果如下:
有一篇论文《Fast statistical outlier removal based method for large 3d point clouds of outdoor environments》,根据其题目理解来说是一种更快的统计学滤波方法去除离群点,论文还没看,源码也没找到,谁能找到麻烦联系我,感谢!
3.RANSAC
没错,就是RANSAC。使用RANSAC去去噪需要满足条件,那就是目标点云是具有几何特征的。如果目标点云是一个平面,那么就可以使用RANSAC拟合一个平面,并且将距离平面较远的点(外点)去除。这样当然也可以达到去噪的效果,而且速度还比较快。
头文件:
#include <pcl/kdtree/kdtree.h>
#include <pcl/segmentation/sac_segmentation.h>
/// <summary>
/// 使用PCL中集成的用于点云分割的RANSAC方法进行平面拟合
/// </summary>
/// <param name="cloud_in">输入待拟合的点云</param>
/// <param name="inliers">RANSAC拟合得到的内点</param>
/// <param name="coefficients">得到的平面方程参数</param>
/// <param name="iterations">平面拟合最大迭代次数</param>
/// <param name="threshold">RANSAC拟合算法距离阈值</param>
void SEG_RANSAC(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud_in, pcl::PointIndices::Ptr& inliers, Eigen::VectorXf& coefficients,const int& iterations, const double& threshold)
{if (inliers == nullptr) inliers.reset(new pcl::PointIndices);pcl::ModelCoefficients::Ptr coefficients_m(new pcl::ModelCoefficients);pcl::shared_ptr<pcl::search::KdTree<pcl::PointXYZ>> tree(new pcl::search::KdTree<pcl::PointXYZ>);tree->setInputCloud(cloud_in);pcl::SACSegmentation<pcl::PointXYZ> seg;seg.setOptimizeCoefficients(true);seg.setModelType(pcl::SACMODEL_PLANE);seg.setMethodType(pcl::SAC_RANSAC);seg.setMaxIterations(iterations); // 设置最大迭代次数seg.setDistanceThreshold(threshold); // 设定阈值seg.setNumberOfThreads(10); // 设置线程数量seg.setSamplesMaxDist(3, tree);seg.setInputCloud(cloud_in);seg.segment(*inliers, *coefficients_m);coefficients.resize(4);coefficients[0] = coefficients_m->values[0]; coefficients[1] = coefficients_m->values[1];coefficients[2] = coefficients_m->values[2]; coefficients[3] = coefficients_m->values[3];std::cout << "SEG coefficients: " << coefficients[0] << ", " << coefficients[1] << ", " << coefficients[2] << ", " << coefficients[3] << std::endl;
}
运行时间只需要1.5s,迭代了200次。速度比半径滤波和统计学滤波要快很多。但是这个方法也是很有局限性的,只适合特定点云才能用,而且如下图所示,距离平面较近的噪点无法去除,所以是存在去除噪点不干净的情况,如果追求速度,而对去噪要求没那么高,则可以考虑使用该方法。
4.欧式聚类
欧式聚类既可以用于分割,也可以用于去噪,其实跟上述半径滤波区别不大。噪点肯定是距离想要的点云比较“远”的,设置好minSize,把想要的点聚成一个类,噪点自然就去除了。
代码如下:
/// <summary>
/// PCL中集成的欧式聚类
/// </summary>
/// <param name="cloud">输入点云</param>
/// <param name="cluster_indices">聚类索引的数组</param>
/// <param name="tolerance ">距离阈值</param>
/// <param name="MinClusterSize">单个类最少的点数</param>
/// <param name="MaxClusterSize">单个类最大的点数</param>
/// <returns>return true表示有聚类结果,return false表示聚类失败</returns>
bool NoiseRemoveEC(const pcl::PointCloud<pcl::PointXYZ>::Ptr& cloud, std::vector<pcl::PointIndices>& cluster_indices, const double& tolerance,const int& MinClusterSize, const int& MaxClusterSize)
{if (cloud == nullptr) return false;if (cloud->points.size() < 10) return false;int maxSize = MaxClusterSize;if (maxSize < 0) maxSize = cloud->points.size();if (MinClusterSize > maxSize) return false;pcl::shared_ptr<pcl::search::KdTree<pcl::PointXYZ>> tree(new pcl::search::KdTree<pcl::PointXYZ>); // Creating the KdTree object for the search method of the extractiontree->setInputCloud(cloud);cluster_indices.clear();pcl::EuclideanClusterExtraction<pcl::PointXYZ> ec; // 欧式聚类对象ec.setClusterTolerance(tolerance); // 设置近邻搜索的搜索半径为 单位是mec.setMinClusterSize(MinClusterSize); // 设置一个聚类需要的最少的点数目ec.setMaxClusterSize(maxSize); // 设置一个聚类需要的最大点数目ec.setSearchMethod(tree); // 设置点云的搜索机制ec.setInputCloud(cloud); // 输入聚类点云ec.extract(cluster_indices); // 从点云中提取聚类,并将点云索引保存在cluster_indices中if (cluster_indices.empty()) return false;return true;
}
设置的距离阈值为0.1,是两倍的点距大小(x,y方向点距都是0.05)。耗时10.9s。当距离阈值tolerance设置的比较大时,就会特别耗时,该方法就几乎不可用了。
相关文章:

《点云处理》 点云去噪
前言 通常从传感器(3D相机、雷达)中获取到的点云存在噪点(杂点、离群点、孤岛点等各种叫法)。噪点产生的原因有不同,可能是扫描到了不想要扫描的物体,可能是待测工件表面反光形成的,也可能是相…...

npm login报错:Public registration is not allowed
npm login报错:Public registration is not allowed 1.出现场景2.解决 1.出现场景 npm login登录时,出现 2.解决 将自己的npm镜像源改为npm的https://registry.npmjs.org/这个,解决!...

OpenHarmony 启动流程优化
目前rk3568的开机时间有21s,统计的是关机后从按下 power 按键到显示锁屏的时间,当对openharmony的系统进行了裁剪子系统,系统app,禁用部分服务后发现开机时间仅仅提高到了20.94s 优化微乎其微。在对init进程的log进行分析并解决其…...

解决腾讯云CentOS 6硬盘空间不足问题:从快照到数据迁移
引言: 随着数据的不断增加,服务器硬盘空间不足变成了许多运维人员必须面对的问题。此主机运行了httpd(apache服务),提供对外web访问服务,web资源挂载在**/data/wwwroot目录下,http日志存放在/data/wwwlogs目录下&…...

org.slf4j日志组件实现日志功能
slf4j 全称是Simple Logging Facade for Java。facade是一种设计模式。 slf4j 是一个抽象程度更高的日志组件,本身并不提供实际的日志功能。实际的日志功能是通过log4j等日志组件实现,而使用者只需要关心 slf4j 给出的API。 slf4j 仅仅是一个为Java程序提…...

3D小球跑酷
目录 一、前言 二、开发环境 三、场景搭建 1. 创建项目 2. 创建场景内物体 2.1 创建跑道 2.2 创建玩家 2.3 创建障碍物 2.4 改变跑道和障碍物的颜色 2.4.1 创建材质 2.4.2 给跑道和障碍物更换材质 四、功能脚本实现 1. 创建玩家脚本 2. 相机跟随 3. 胜负的判定 3.1 …...

PyQt6 QInputDialog输入对话框控件
锋哥原创的PyQt6视频教程: 2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~_哔哩哔哩_bilibili2024版 PyQt6 Python桌面开发 视频教程(无废话版) 玩命更新中~共计50条视频,包括:2024版 PyQt6 Python桌面开发 视频教程(无废话版…...

ASP.NET Core MVC依赖注入理解(极简个人版)
依赖注入 文献来源:《Pro ASP.NET Core MVC》 Adam Freeman 第18章 依赖注入 1 依赖注入原理 所有可能变化的地方都用接口在使用接口的地方用什么实体类通过在ConfigureService中注册解决注册的实体类需要指定在何种生命周期中有效 TransientScopedSingleton 2…...

美光将于 2025 年推出 1γ DRAM,并在日本生产HBM
美国内存巨头美光正准备从 2025 年开始在其位于日本广岛的晶圆厂生产最先进的“1γ”DRAM。同时,公司计划在同一晶圆厂生产高带宽存储器(HBM),以满足对生成式人工智能应用日益增长的需求。 据《日经亚洲》12月13日报道࿰…...
【Docker】以service形式离线安装卸载的docker、compose服务
CentOS7离线卸载Docker步骤 移除开机自启 [rootCenOS-1 system]# systemctl disable docker移除注册文件 rm -rf /etc/systemd/system/docker.service删除相关安装目录 rm -rf $(find / -name docker)CentOS7离线安装Docker、Compose步骤 资源地址:docker_20.10…...
Dubbo RPC-Redis协议
Redis协议 特性说明 Redis 是一个高效的 KV 存储服务器。基于 Redis 实现的 RPC 协议。 2.3.0 以上版本支持。 使用场景 缓存,限流,分布式锁等 使用方式 引入依赖 从 Dubbo 3 开始,Redis 协议已经不再内嵌在 Dubbo 中,需要单…...
展开说说:Android之常用的延时执行策略
总结了以下六种常用的Android延时执行策略,以此记录: 1、TimerTask 2、Handler.postDelayed 3、Handler.sendEnptyMessageDelayeed 4、Thread.sleep线程休眠-需要在子线程 5、使用AlarmManager-全局定时器或者闹钟 6、Wait 首先定义一个时间常量&…...
Jenkins在window下配置Android打包配置
在Windows下配置Jenkins进行Android打包的步骤如下: 安装Jenkins:从Jenkins官网下载适用于Windows的安装包,并按照安装向导的指示完成安装。 启动Jenkins服务:启动Jenkins服务,确保服务正常运行。 配置Jenkins&#…...

云原生系列2-GitLab和Jenkins
1、GitLab类似github,是个私有仓库 1、GitLab安装,至少8G内存4核cpu # 查找Gitlab镜像 docker search gitlab/gitlab-ce # gitlab镜像拉取 docker pull gitlab/gitlab-ce # 查看镜像 docker images # 本机先建3个目录,为了gitlab容器通过挂…...

xcode无线真机调试详细图文步骤
步骤一、 步骤二: 步骤三: 配置完到这里,点击真机右键,菜单栏并未出现connect via ip address 选项,也没出现无线连接的小地球图标,别慌,接着进行下一步操作即可。 步骤四: 1.打开…...

EasyExcel合并相同内容单元格及动态标题功能的实现
一、最初版本 导出的结果: 对应实体类代码: import com.alibaba.excel.annotation.ExcelProperty; import com.alibaba.excel.annotation.write.style.ColumnWidth; import com.alibaba.excel.annotation.write.style.ContentLoopMerge; import com.al…...

【论文解读】Comparing VVC, HEVC and AV1 using Objective and Subjective Assessments
时间:2020 级别:IEEE 机构: IEEE 组织 摘要: 对3种最新的视频编码标准HEVC (High Efficiency video Coding)测试模型HM (High Efficiency video Coding)、amedia video 1 (AV1)和Versatile video Coding测试模型 (VTM)进行了客观和…...
动态窗口法Dynamic Window Approach在动态环境中避障
以这个博主的代码为基础,加了一个碰撞检测,但是这个碰撞检测目前还不完善,思路应该是这个思路,以后有时间再完善吧。 动态窗口法:【路径规划】局部路径规划算法——DWA算法(动态窗口法)|&#…...

2023.12.15 FineBI与kettle
1.结构化就是可以用schema描述的数据,就是结构化数据,能转为二维表格, 如CSV,Excel, 2.半结构化就是部分可以转换为二维表格,如JSON,XML 3.非结构化数据,就是完全无法用二维表格表示的数据,如Word文档,Mp4,图片,等文件. kettle的流程 新建转换-构建流图-配置组件-保存运行 使…...

【人工智能】神经网络的优化器optimizer(二):Adagrad自适应学习率优化器
一.自适应梯度算法Adagrad概述 Adagrad(Adaptive Gradient Algorithm)是一种自适应学习率的优化算法,由Duchi等人在2011年提出。其核心思想是针对不同参数自动调整学习率,适合处理稀疏数据和不同参数梯度差异较大的场景。Adagrad通…...
Frozen-Flask :将 Flask 应用“冻结”为静态文件
Frozen-Flask 是一个用于将 Flask 应用“冻结”为静态文件的 Python 扩展。它的核心用途是:将一个 Flask Web 应用生成成纯静态 HTML 文件,从而可以部署到静态网站托管服务上,如 GitHub Pages、Netlify 或任何支持静态文件的网站服务器。 &am…...

学习STC51单片机31(芯片为STC89C52RCRC)OLED显示屏1
每日一言 生活的美好,总是藏在那些你咬牙坚持的日子里。 硬件:OLED 以后要用到OLED的时候找到这个文件 OLED的设备地址 SSD1306"SSD" 是品牌缩写,"1306" 是产品编号。 驱动 OLED 屏幕的 IIC 总线数据传输格式 示意图 …...
Mobile ALOHA全身模仿学习
一、题目 Mobile ALOHA:通过低成本全身远程操作学习双手移动操作 传统模仿学习(Imitation Learning)缺点:聚焦与桌面操作,缺乏通用任务所需的移动性和灵活性 本论文优点:(1)在ALOHA…...

RSS 2025|从说明书学习复杂机器人操作任务:NUS邵林团队提出全新机器人装配技能学习框架Manual2Skill
视觉语言模型(Vision-Language Models, VLMs),为真实环境中的机器人操作任务提供了极具潜力的解决方案。 尽管 VLMs 取得了显著进展,机器人仍难以胜任复杂的长时程任务(如家具装配),主要受限于人…...
django blank 与 null的区别
1.blank blank控制表单验证时是否允许字段为空 2.null null控制数据库层面是否为空 但是,要注意以下几点: Django的表单验证与null无关:null参数控制的是数据库层面字段是否可以为NULL,而blank参数控制的是Django表单验证时字…...
Python 高效图像帧提取与视频编码:实战指南
Python 高效图像帧提取与视频编码:实战指南 在音视频处理领域,图像帧提取与视频编码是基础但极具挑战性的任务。Python 结合强大的第三方库(如 OpenCV、FFmpeg、PyAV),可以高效处理视频流,实现快速帧提取、压缩编码等关键功能。本文将深入介绍如何优化这些流程,提高处理…...

JDK 17 序列化是怎么回事
如何序列化?其实很简单,就是根据每个类型,用工厂类调用。逐个完成。 没什么漂亮的代码,只有有效、稳定的代码。 代码中调用toJson toJson 代码 mapper.writeValueAsString ObjectMapper DefaultSerializerProvider 一堆实…...

如何把工业通信协议转换成http websocket
1.现状 工业通信协议多数工作在边缘设备上,比如:PLC、IOT盒子等。上层业务系统需要根据不同的工业协议做对应开发,当设备上用的是modbus从站时,采集设备数据需要开发modbus主站;当设备上用的是西门子PN协议时…...
深度解析云存储:概念、架构与应用实践
在数据爆炸式增长的时代,传统本地存储因容量限制、管理复杂等问题,已难以满足企业和个人的需求。云存储凭借灵活扩展、便捷访问等特性,成为数据存储领域的主流解决方案。从个人照片备份到企业核心数据管理,云存储正重塑数据存储与…...