点云处理【二】(点云滤波)

news2025/1/11 0:32:54

点云滤波

第一章 点云数据采集
第二章 点云滤波


1. 为什么要滤波?

通常我们获取的点云数据中包含噪声,噪声会影响点云的特征提取、配准和语义处理。

点云需要处理的主要情况包括:
数据量过大,不易于处理,需要进行下采样
通常由遮挡引起的离群点,需要去除
点云数据的密度不均匀需要平滑
噪声数据需要去除

2.滤波算法

2.1 索引滤波

索引滤波就是设置索引选择区域,可用于超简单的区域初步筛选,算不上真正的滤波算法。
open3d

import open3d as o3d
import numpy as np
pcd = o3d.io.read_point_cloud("xxx.pcd")
idx = np.arange(100000)
# 索引对应的点
pIn = pcd.select_by_index(idx)
pIn.paint_uniform_color([1, 0, 0])
# 索引外的点云
pOut = pcd.select_by_index(idx, invert=True)
pOut.paint_uniform_color([0, 1, 0])
o3d.visualization.draw_geometries([pIn, pOut])

红色是索引内的点,绿色是索引外的点
pcl

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

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ> ("1695805751226.pcd", *cloud) == -1){
        PCL_ERROR("couldn't read file");
        return 0;
    }

    std::cout << "Loaded " << cloud->width * cloud->height
              << " data points" << std::endl;
              
    // 创建索引向量
    pcl::PointIndices::Ptr indices(new pcl::PointIndices());
    for (int i = 0; i <= 100000 && i < cloud->points.size(); ++i)
    {
        indices->indices.push_back(i);
    }
    // 创建提取对象
    pcl::ExtractIndices<pcl::PointXYZ> extract;
    extract.setInputCloud(cloud);
    extract.setIndices(indices);
    extract.setNegative(false); // set to true if you want to extract everything except the specified indices
    extract.filter(*cloud_filtered);
	//将PointXYZ改为PointXYZRGB时可实现彩色显示
	// for (size_t i = 0; i < cloud_filtered->points.size(); ++i)
    // {
    //     if (i <= 10000)
    //     {
    //         // Set color to red
    //         cloud_filtered->points[i].r = 255;
    //         cloud_filtered->points[i].g = 0;
    //         cloud_filtered->points[i].b = 0;
    //     }
    //     else
    //     {
    //         // Set color to green
    //         cloud_filtered->points[i].r = 0;
    //         cloud_filtered->points[i].g = 255;
    //         cloud_filtered->points[i].b = 0;
    //     }
    // }

    std::cout << "Filtered cloud size: " << cloud_filtered->width * cloud_filtered->height << std::endl;
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered, "sample cloud");

    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
    }
    return 0;
}

请添加图片描述

2.2 半径滤波

设置半径大小和半径内所需的点云数,用来去除稀疏处的噪声。
Open3d

import open3d as o3d
import numpy as np
pcd = o3d.io.read_point_cloud("second/1697165371469.pcd")
print(pcd)  # 输出点云点的个数
o3d.visualization.draw_geometries([pcd], window_name="原始点云",
                                  width=1024, height=768,
                                  left=50, top=50,
                                  mesh_show_back_face=True)
print("Radius oulier removal")
cl, ind = pcd.remove_radius_outlier(nb_points=160, radius=20)
radius_cloud = pcd.select_by_index(ind)
o3d.visualization.draw_geometries([radius_cloud], window_name="半径滤波",
                                  width=1024, height=768,
                                  left=50, top=50,
                                  mesh_show_back_face=True)
#o3d.io.write_point_cloud("second_radius_cloud.pcd",radius_cloud)

在这里插入图片描述
PCL

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

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ> ("1697165371469.pcd", *cloud) == -1){
        PCL_ERROR("couldn't read file");
        return 0;
    }

    std::cout << "Loaded " << cloud->width * cloud->height
              << " data points" << std::endl;
              
    // 创建滤波器对象
    pcl::RadiusOutlierRemoval<pcl::PointXYZ> outrem;
    outrem.setInputCloud(cloud);
    outrem.setRadiusSearch(20);  // 设置半径
    outrem.setMinNeighborsInRadius(160);  // 设置半径内最小的邻居数量
    outrem.filter(*cloud_filtered);

    std::cout << "Filtered cloud size: " << cloud_filtered->width * cloud_filtered->height << std::endl;


    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);  // 设置背景色
    viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered, "sample cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
    viewer->initCameraParameters();
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
    }

    return 0;
}

在这里插入图片描述

2.3 统计滤波

点云在空间中分布稀疏,定义某处点云小于某个密度,即点云无效。因此我们要计算每个点到其最近的K个点平均距离,则点云中所有点的距离应构成高斯分布,根据全部点集的均值和标准差,计算距离阈值,剔除阈值之外的点。
Open3d

import open3d as o3d
import numpy as np
pcd = o3d.io.read_point_cloud("second/1697165371469.pcd")
print(pcd)  # 输出点云点的个数
o3d.visualization.draw_geometries([pcd], window_name="原始点云",
                                  width=1024, height=768,
                                  left=50, top=50,
                                  mesh_show_back_face=True)

cl,index = pcd.remove_statistical_outlier(nb_neighbors = 26,std_ratio= 10)
new_cloud = pcd.select_by_index(index)
print(new_cloud)
o3d.visualization.draw_geometries([new_cloud], window_name="统计滤波",
                                  width=1024, height=768,
                                  left=50, top=50,
                                  mesh_show_back_face=True)
#o3d.io.write_point_cloud("second_radius_cloud.pcd",radius_cloud)

在这里插入图片描述
PCL

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

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ> ("1697165371469.pcd", *cloud) == -1){
        PCL_ERROR("couldn't read file");
        return 0;
    }

    std::cout << "Loaded " << cloud->width * cloud->height
              << " data points" << std::endl;
              
    pcl::StatisticalOutlierRemoval<pcl::PointXYZ> sor;
    sor.setInputCloud(cloud);
    sor.setMeanK(50);   // 考虑的邻近点的数量
    sor.setStddevMulThresh(100);  // 距离平均值1个标准差范围之外的点将被删除
    sor.filter(*cloud_filtered);

    std::cout << "Filtered cloud size: " << cloud_filtered->width * cloud_filtered->height << std::endl;

    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);  // 设置背景色
    viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered, "sample cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
    viewer->initCameraParameters();
    viewer->saveScreenshot("screenshot.png");
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
    }

    return 0;
}

在这里插入图片描述

2.4 双边滤波

双边滤波由空域和值域组成,降噪用高斯滤波,边缘用高斯方差。通过临近采样点加权平均,剔除差异大的点,同时保留边缘信息从而使数据更加平滑。

Open3d

import open3d as o3d
import numpy as np


# ----------------------------------加载点云------------------------------------
pcd = o3d.io.read_point_cloud("second/1697165371469.pcd")
o3d.visualization.draw_geometries([pcd])


sigma_s = 50  # 距离权重
sigma_r = 10    # 法向权重
searchNum = 30  # 近邻点数
# 计算法向量
pcd.estimate_normals(o3d.geometry.KDTreeSearchParamKNN(searchNum))
# 构建KD-tree
kdtree = o3d.geometry.KDTreeFlann(pcd)
BFilter = o3d.geometry.PointCloud(pcd)
# 双边滤波
for i in range(len(pcd.points)):
    [k, idx, _] = kdtree.search_knn_vector_3d(pcd.points[i], searchNum)
    curNormal = pcd.normals[i]
    searchPoint = pcd.points[i]

    BF = 0.0
    W = 0.0
    for j in idx[1:]:
        near_point = pcd.points[j]
        vec = near_point - pcd.points[i]
        dd = np.sqrt(np.sum(np.square(vec)))
        dn = np.dot(vec, curNormal)
        weight = np.exp(-dd * dd / (2 * sigma_s * sigma_s)) * np.exp(-dn * dn / (2 * sigma_r * sigma_r))
        BF = BF + weight * dn
        W = W + weight

    lamda = BF / W
    BFilter.points[i] = searchPoint + lamda * curNormal
# ---------------------------------结果可视化----------------------------------
o3d.visualization.draw_geometries([BFilter], window_name="基于法线的双边滤波",
                                  width=1024, height=768,
                                  left=50, top=50,
                                  mesh_show_back_face=False)

在这里插入图片描述

双边滤波需要强度信息(XYZI),我们的点云没有强度信息;快速双边滤波需要有序数据才能实现。
PCL

#include <pcl/io/pcd_io.h>
#include <pcl/point_types.h>
#include <pcl/visualization/pcl_visualizer.h>
#include <pcl/filters/bilateral.h>
#include <pcl/filters/fast_bilateral.h>
#include <pcl/filters/fast_bilateral_omp.h>

int main(int argc, char** argv) {
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud (new pcl::PointCloud<pcl::PointXYZ>);
    pcl::PointCloud<pcl::PointXYZ>::Ptr cloud_filtered(new pcl::PointCloud<pcl::PointXYZ>);
    if (pcl::io::loadPCDFile<pcl::PointXYZ> ("1697165371469.pcd", *cloud) == -1){
        PCL_ERROR("couldn't read file");
        return 0;
    }

    std::cout << "Loaded " << cloud->width * cloud->height
              << " data points" << std::endl;
              
     // 创建滤波器对象
    pcl::FastBilateralFilter<pcl::PointXYZ> fbf;
    //双边滤波器
    fbf.setInputCloud(cloud);  //设置输入点云
    //fbf.setSearchMethod(tree1);
    fbf.setSigmaS(100);      //高斯滤波器的一半窗口值
    fbf.setSigmaR(10);           //标准差
    fbf.applyFilter(*cloud_filtered);
    std::cout << "Filtered cloud size: " << cloud_filtered->width * cloud_filtered->height << std::endl;
    pcl::visualization::PCLVisualizer::Ptr viewer(new pcl::visualization::PCLVisualizer("3D Viewer"));
    viewer->setBackgroundColor(0, 0, 0);  // 设置背景色
    viewer->addPointCloud<pcl::PointXYZ>(cloud_filtered, "sample cloud");
    viewer->setPointCloudRenderingProperties(pcl::visualization::PCL_VISUALIZER_POINT_SIZE, 1, "sample cloud");
    viewer->initCameraParameters();
    while (!viewer->wasStopped())
    {
        viewer->spinOnce(100);
    }
    return 0;
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1100202.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL学习(四)——事务与存储引擎

文章目录 1. 事务1.1 概念1.2 事务操作1.2.1 未设置事务1.2.2 控制事务 1.3 事务四大特性1.4 并发事务问题1.5 事务隔离级别 2. 存储引擎2.1 MySQL体系结构2.2 存储引擎2.3 存储引擎的特点2.3.1 InnoDB2.3.2 MyISAM2.3.3 Memory2.3.4 区别和比较 1. 事务 1.1 概念 事务 是一组…

如何实现前端单页面应用(SPA)?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

(三十三)geoserver源码添加新的数据存储

1.添加新的数据存储 如下图所示&#xff0c;为我们经常操作的添加数据存储的界面。 可以看到这个代码在如下的位置。在这样的代码中实现跳转。header.add(new BookmarkablePageLink("addNew", NewDataPage.class)); public class StorePage extends GeoServerSecur…

Notes/Domino 14 Early Access Drop3发布

大家好&#xff0c;才是真的好。 其实上周&#xff0c;就是国庆假期的时候&#xff0c;HCL Notes/Domino 14 Early Access Drop3&#xff08;以下简称EA3&#xff09;就已经发布&#xff0c;而且和传说中的一样&#xff0c;带来了数项惊人的新特性。 我们先讲讲这一版本新特性…

正向代理——流量代理

文章目录 流量代理1. 正向代理2. 反向代理3. 流量转发工具4. 实验4.1 实验环境4.2 reGeorg工具 流量代理 1. 正向代理 正向代理是客户端和其他所有服务器&#xff08;重点&#xff1a;所有&#xff09;的代理者 2. 反向代理 反向代理是客户端和所要代理的服务器之间的代理。…

3.3 Tessellation Shader (TESS) Geometry Shader(GS)

一、曲面细分着色器的应用 海浪&#xff0c;雪地等 与置换贴图的结合 二、几何着色器的应用 几何动画 草地等&#xff08;与曲面着色器结合&#xff09; 三、着色器执行顺序 1.TESS的输入与输出 输入 Patch&#xff0c;可以看成是多个顶点的集合&#xff0c;包含每个顶点的属…

无线设备天线的选型及其安装注意事项

天线作为无线传输过程中一个必不可少的配件&#xff0c;因此天线的安装和选型对于无线传输的稳定性发挥着至关重要的作用。本文将介绍影响天线安装对于无线通信效果的影响。 一、天线的工作原理 天线是一种能量变换器&#xff0c;它把传输线上传播的导行波&#xff0c;变换成在…

innovus:antenna设置

我正在「拾陆楼」和朋友们讨论有趣的话题&#xff0c;你⼀起来吧&#xff1f; 拾陆楼知识星球入口 innovus和ICC2还不一样&#xff0c;ICC2需要读antenna rule&#xff0c;innovus只看antenna lef&#xff0c;所以要检查一下lef里antenna信息全不全。 然后设置如下option: s…

实验室超声波清洗机如何进行提取、乳化?

近年来&#xff0c;超声波清洗机已被广泛应用于实验室中&#xff0c;如提取、清洗、乳化等&#xff0c;由于其具有高效、节能和自动化程度高等其他技术不可比拟的优势&#xff0c;现已在各行各业广泛应用&#xff0c;本文主要就实验室超声波清洗机提取、乳化方面做个简单的介绍…

流量代理——正向代理

流量代理 正向代理和反向代理 正向代理就是客户端和其他所有服务器&#xff08;重点&#xff1a;所有&#xff09;的代理者。 反向代理是客户端和所要代理的服务器之间的代理。 流量转发工具 需要放在拿到shell的服务器上可使用 lcx&#xff1a;端口流量转发&#xff0c;不具…

百度百科词条编辑要求,怎样创建百度百科之实操篇

大部分人都不知道百度百科词条编辑有什么要求&#xff0c;也不知道百度百科词条内容到底是否靠谱&#xff0c;下面洛希爱做百科网将为大家带来百度百科创建实操技能分享。 1、百度一下【百度百科】找到百度词条的官网 2、打开百度百科的官网 我们就会发现 总共创建了多少个百度…

SpringCloud ---day1

认识微服务 单体架构 微服务架构 方便进行打包上线,版本的更新上线,降低项目之间的耦合度,减少代码量巨大导致的编译/打包时间长的问题 SpringCloud简介 项目熟悉 业务流程 项目模块划分 服务拆分原则 什么时候拆: 对于一个初创的项目&#xff0c;首先要做的是验证项目的可…

如何进行前端代码打包和压缩?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

优秀的推荐系统架构与应用:从YouTube到Pinterest、Flink和阿里巴巴

文章目录 &#x1f31f; 业界经典&#xff1a;YouTube深度学习推荐系统的经典架构长什么样&#xff1f;&#x1f34a; 基础架构&#x1f34a; 深度学习模型&#x1f34a; 额外组件 &#x1f31f; 图神经网络&#xff1a;Pinterest如何应用图神经网络的&#xff1f;&#x1f34a…

如何构建前端自动化测试套件?

聚沙成塔每天进步一点点 ⭐ 专栏简介 前端入门之旅&#xff1a;探索Web开发的奇妙世界 欢迎来到前端入门之旅&#xff01;感兴趣的可以订阅本专栏哦&#xff01;这个专栏是为那些对Web开发感兴趣、刚刚踏入前端领域的朋友们量身打造的。无论你是完全的新手还是有一些基础的开发…

PBootCMS解析、例子

一、分析以下程序 {pboot:nav num10 parent0}<li class"nav-item {pboot:if([nav:scode]{sort:tcode})}active{/pboot:if}"><a class"nav-link" href"[nav:link]">[nav:name]</a></li> {/pboot:nav} 当前栏目的顶级栏目…

ruoyi-cloud 升级mybatis plus 报错 Invalid bound statement (not found)

1.项目是用的ruoyi-cloud 2.项目自带mybatis 想升级为mybatis plus 3.mybatis plus集成后,启动正常,但是dao访问xml时,报错Invalid bound statement (not found) 4.试了好多次无果,后来又把application.yml的mybatis-plus换成mybatis,目的是查看是否mybatis能否正确关联到sq…

C++:超越C语言的独特魅力

W...Y的主页&#x1f60a; 代码仓库分享&#x1f495; &#x1f354;前言&#xff1a; 今天我们依旧来完善补充C&#xff0c;区分C与C语言的区别。上一篇我们讲了关键字、命名空间、C的输入与输出、缺省参数等知识点。今天我们继续走进C的世界。 目录 函数重载 函数重载概…

Linux常用命令——command命令

在线Linux命令查询工具 command 调用并执行指定的命令 补充说明 command命令调用指定的指令并执行&#xff0c;命令执行时不查询shell函数。command命令只能够执行shell内部的命令。 语法 command(参数)参数 指令&#xff1a;需要调用的指令及参数。 实例 使用command…

好奇喵 | Rust编程语言的简单了解~

前言 有时候会听到别人谈论小众的语言&#xff0c;最近经常听到rust语言&#xff0c;感觉很厉害的样子&#xff0c;就简单了解了一下。 Rust 语言是一种高效、可靠的通用高级语言。其高效不仅限于开发效率&#xff0c;它的执行效率也是令人称赞的&#xff0c;是一种少有的兼顾…