Open3D 基于法线的双边滤波

2024-09-09 17:36
文章标签 法线 滤波 双边 open3d

本文主要是介绍Open3D 基于法线的双边滤波,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

目录

一、概述

1.1原理

1.2实现步骤

1.3应用场景

二、代码实现

2.1关键函数

输入参数:

输出参数:

参数影响:

2.2完整代码

三、实现效果

3.1原始点云

3.2滤波后点云


Open3D点云算法汇总及实战案例汇总的目录地址:

Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客


一、概述

        基于法线的双边滤波是一种用于点云平滑的技术,它结合了点与其邻域点之间的几何距离和法线方向的相似性,从而在去除噪声的同时保留几何特征。这种滤波方法广泛应用于点云处理领域,尤其是在需要保留表面细节和边缘的场景中。

1.1原理

        双边滤波是一种非线性滤波方法,它在计算点云中某个点的加权平均值时,同时考虑了几何距离和法线方向的相似性。对于点云中的每个点,其滤波结果是其邻域点的加权平均值,权重由两个因素决定:

  1. 空间权重 (spatial weight): 反映点与邻域点之间的几何距离,距离越近的点权重越大。空间权重通常使用高斯函数来计算。
  2. 法线权重 (normal weight): 反映点与邻域点之间的法线差异,法线方向越相似的点权重越大。法线权重也通常使用高斯函数来计算。

1.2实现步骤

  1. 加载点云数据: 使用 Open3D 加载原始点云。
  2. 估计法向量: 计算点云中每个点的法向量,为双边滤波提供参考信息。
  3. 自定义双边滤波: 使用自定义的双边滤波函数,对点云进行平滑处理,保留边缘和几何特征。
  4. 可视化结果: 显示原始点云和滤波后的点云,便于对比滤波效果。

1.3应用场景

  • 降噪: 在点云数据中减少噪声,同时保留几何结构,适用于点云数据的预处理。
  • 边缘保留平滑: 在保持边缘特征的同时,平滑点云表面。
  • 点云表面重建: 提高点云表面重建的精度,保留表面细节

二、代码实现

2.1关键函数

bilateral_filter 函数的作用是通过结合点的几何距离和法线方向的差异,对点云进行双边滤波,保留边缘特征的同时减少噪声。

def bilateral_filter(pcd, radius, sigma_s, sigma_r):"""对点云进行双边滤波,使用点的邻域几何距离和法线差异来平滑点云并保留结构特征。参数:pcd (open3d.geometry.PointCloud): 输入的点云。radius (float): 搜索邻域的半径,定义邻域的范围。sigma_s (float): 空间域参数,控制几何距离的影响。sigma_r (float): 强度域参数,控制法线差异的影响。返回:open3d.geometry.PointCloud: 滤波后的点云。"""# 计算法向量,法向量用于在双边滤波过程中考虑法线差异pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=radius, max_nn=30))# 建立 KD 树用于快速邻域搜索kdtree = o3d.geometry.KDTreeFlann(pcd)# 获取点云的点坐标和法向量数据points = np.asarray(pcd.points)normals = np.asarray(pcd.normals)# 准备一个空数组存储滤波后的点filtered_points = np.zeros_like(points)num_points = len(points)  # 点云中点的数量# 遍历每个点,对其进行双边滤波处理for i in range(num_points):# 在给定半径内搜索当前点的邻域点[k, idx, _] = kdtree.search_radius_vector_3d(points[i], radius)# 如果邻域点少于3个,则跳过当前点的滤波处理if k < 3:filtered_points[i] = points[i]continue# 获取邻域点的坐标和法向量neighbors = points[idx]neighbor_normals = normals[idx]# 计算邻域点与当前点的几何距离spatial_distances = np.linalg.norm(neighbors - points[i], axis=1)# 计算邻域点与当前点的法线方向差异normal_distances = np.linalg.norm(neighbor_normals - normals[i], axis=1)# 计算空间域的高斯权重spatial_weights = np.exp(-0.5 * (spatial_distances / sigma_s) ** 2)# 计算法线域的高斯权重normal_weights = np.exp(-0.5 * (normal_distances / sigma_r) ** 2)# 结合空间权重和法线权重,计算最终的权重weights = spatial_weights * normal_weights# 对权重进行归一化,使得权重总和为1weights /= np.sum(weights)# 根据权重对邻域点进行加权平均,得到滤波后的点位置filtered_points[i] = np.sum(neighbors * weights[:, np.newaxis], axis=0)# 创建新的点云对象,并更新点的位置filtered_pcd = o3d.geometry.PointCloud()filtered_pcd.points = o3d.utility.Vector3dVector(filtered_points)filtered_pcd.normals = o3d.utility.Vector3dVector(normals)return filtered_pcd

输入参数:

  • pcd (open3d.geometry.PointCloud): 输入的点云对象,用于执行滤波操作。
  • radius (float): 搜索邻域的半径,定义了每个点在进行滤波时考虑的邻域范围。较大的半径会使得更多的邻域点参与滤波,适合较大尺度的点云,而较小的半径则更适合细节丰富的点云。
  • sigma_s (float): 控制空间距离影响的参数。这个值越大,几何距离对滤波结果的影响越小,反之亦然。如果设定得过小,则只有非常接近的邻域点才会对当前点产生显著影响,可能会过度平滑点云。
  • sigma_r (float): 控制法线差异影响的参数。这个值越大,法线方向差异对滤波结果的影响越小,反之亦然。较小的值会更加强调保留法线相似的邻域点,有助于保留边缘特征。

输出参数:

  • filtered_pcd (open3d.geometry.PointCloud): 滤波后的点云对象,保留了原始点云的几何结构,同时减少了噪声。

参数影响:

  • radius: 影响邻域的大小。较大的半径会平滑更多的点,但也可能导致细节丢失;较小的半径则可能保留更多细节,但平滑效果不明显。
  • sigma_s: 控制空间距离的影响。较大的 sigma_s 会使得远离当前点的邻域点也有较大权重,适合处理平滑的大区域。较小的 sigma_s 则会更关注于局部区域,适合处理具有较多细节的点云。
  • sigma_r: 控制法线差异的影响。较大的 sigma_r 会使得法线差异对权重的影响减小,适合处理表面变化较缓的点云。较小的 sigma_r 则有助于保留边缘等具有明显法线变化的特征区域。

通过合理调整 radius、sigma_s 和 sigma_r 的数值,可以在平滑点云与保留几何特征之间找到一个平衡点,确保滤波后的点云既减少了噪声又保留了关键的几何特征。

2.2完整代码

import open3d as o3d
import numpy as npdef bilateral_filter(pcd, radius, sigma_s, sigma_r):"""对点云进行双边滤波,使用点的邻域几何距离和法线差异来平滑点云并保留结构特征。参数:pcd (open3d.geometry.PointCloud): 输入的点云。radius (float): 搜索邻域的半径,定义邻域的范围。sigma_s (float): 空间域参数,控制几何距离的影响。sigma_r (float): 强度域参数,控制法线差异的影响。返回:open3d.geometry.PointCloud: 滤波后的点云。"""# 计算法向量,法向量用于在双边滤波过程中考虑法线差异pcd.estimate_normals(search_param=o3d.geometry.KDTreeSearchParamHybrid(radius=radius, max_nn=30))# 建立 KD 树用于快速邻域搜索kdtree = o3d.geometry.KDTreeFlann(pcd)# 获取点云的点坐标和法向量数据points = np.asarray(pcd.points)normals = np.asarray(pcd.normals)# 准备一个空数组存储滤波后的点filtered_points = np.zeros_like(points)num_points = len(points)  # 点云中点的数量# 遍历每个点,对其进行双边滤波处理for i in range(num_points):# 在给定半径内搜索当前点的邻域点[k, idx, _] = kdtree.search_radius_vector_3d(points[i], radius)# 如果邻域点少于3个,则跳过当前点的滤波处理if k < 3:filtered_points[i] = points[i]continue# 获取邻域点的坐标和法向量neighbors = points[idx]neighbor_normals = normals[idx]# 计算邻域点与当前点的几何距离spatial_distances = np.linalg.norm(neighbors - points[i], axis=1)# 计算邻域点与当前点的法线方向差异normal_distances = np.linalg.norm(neighbor_normals - normals[i], axis=1)# 计算空间域的高斯权重spatial_weights = np.exp(-0.5 * (spatial_distances / sigma_s) ** 2)# 计算法线域的高斯权重normal_weights = np.exp(-0.5 * (normal_distances / sigma_r) ** 2)# 结合空间权重和法线权重,计算最终的权重weights = spatial_weights * normal_weights# 对权重进行归一化,使得权重总和为1weights /= np.sum(weights)# 根据权重对邻域点进行加权平均,得到滤波后的点位置filtered_points[i] = np.sum(neighbors * weights[:, np.newaxis], axis=0)# 创建新的点云对象,并更新点的位置filtered_pcd = o3d.geometry.PointCloud()filtered_pcd.points = o3d.utility.Vector3dVector(filtered_points)filtered_pcd.normals = o3d.utility.Vector3dVector(normals)return filtered_pcddef main():# 加载点云数据pcd = o3d.io.read_point_cloud("bunny_nosiy.pcd")# 显示原始点云print("Displaying original point cloud...")o3d.visualization.draw_geometries([pcd], window_name="Original Point Cloud", width=800, height=600)# 应用自定义的双边滤波filtered_pcd = bilateral_filter(pcd, radius=0.01, sigma_s=0.3, sigma_r=0.3)# 显示滤波后的点云print("Displaying bilateral filtered point cloud...")o3d.visualization.draw_geometries([filtered_pcd], window_name="Bilateral Filtered Point Cloud", width=800,height=600)if __name__ == '__main__':main()

三、实现效果

3.1原始点云

3.2滤波后点云

这篇关于Open3D 基于法线的双边滤波的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1151826

相关文章

6.4双边滤波

目录 实验原理 示例代码1 运行结果1 实验代码2 运行结果2 实验原理 双边滤波(Bilateral Filtering)是一种非线性滤波技术,用于图像处理中去除噪声,同时保留边缘和细节。这种滤波器结合了空间邻近性和像素值相似性的双重加权,从而能够在去噪(平滑图像)的同时保留图像的边缘细节。双边滤波器能够在的同时,保持边缘清晰,因此非常适合用于去除噪声和保持图像特征。在Op

6.3中值滤波

目录 实验原理 示例代码1 运行结果1 示例代码2 运行结果2 实验原理 中值滤波(Median Filtering)是一种非线性滤波技术,常用于图像处理中去除噪声,特别是在保留边缘的同时减少椒盐噪声(salt-and-pepper noise)。OpenCV中的cv::medianBlur函数可以实现中值滤波。 函数原型 void medianBlur( InputAr

通信工程学习:什么是SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制

SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制        SSB单边带调制、VSB残留边带调制、DSB抑制载波双边带调制是三种不同的调制方式,它们在通信系统中各有其独特的应用和特点。以下是对这三种调制方式的详细解释: 一、SSB单边带调制 1、SSB单边带调制的定义:        单边带调制(Single Sideband Modulation,SSB)是

【控制算法 数据处理】一阶滤波算法

简单介绍: 一阶滤波算法是比较常用的滤波算法,它的滤波结果=a*本次采样值+(1-a)*上次滤波结果,其中,a为0~1之间的数。一阶滤波相当于是将新的采样值与上次的滤波结果计算一个加权平均值。a的取值决定了算法的灵敏度,a越大,新采集的值占的权重越大,算法越灵敏,但平顺性差;相反,a越小,新采集的值占的权重越小,灵敏度差,但平顺性好。优点是对周期干扰有良好的抑制作用,适用于波动频率比较高的场合,它

图形API学习工程(25):实现法线贴图

工程GIT地址:https://gitee.com/yaksue/yaksue-graphics 目标 在《图形API学习工程(10):基础光照》中,我实现了最基础的光照,同时也表现了法线的作用。 在《图形API学习工程(11):使用纹理》中,工程已经能够加载纹理贴图。 这样,法线贴图 所需的准备已经完成,可以在工程里实现这个技术了。 (关于法线贴图的意义,可见上一篇博客《从“法线贴图的意义

从“法线贴图的意义”到“切线空间公式的推导与验证”

目录 目标1. 法线贴图1.1 “法线”的意义1.2 “法线贴图”的意义 2. 切线空间2.1 法线贴图中数据的含义2.2 “切线空间”的定义 3. 切线空间计算公式3.1 构造几何关系等式3.2 切线空间计算公式 4. 代码5. 验证——与其他美术软件计算的结果进行比较总结 目标 本篇的重点是 讨论法线贴图的意义讨论切线空间的意义推导切线空间的计算公式根据公式编写代码将其计算

RSSI滤波方法

文章目录 一、均值滤波二、递推平均滤波三、中位值滤波四、狄克逊检验法滤波五、高斯滤波六、速度滤波七、卡尔曼滤波 一、均值滤波 均值滤波是指节点接收到另一节点的多个RSSI值之后,求其算式平均值,作为测试结果 R S S I ‾ = 1 n ∙ ∑ i = 1 n R S S I i \overline{RSSI} = \frac {1}{n} \bullet \sum_{i=1

CUDAPCL ROR点云滤波

文章目录 一、简介二、实现代码三、实现效果参考资料 一、简介 该方法的具体原理为输入的点云中每一个点设定一个范围(半径为r的圆),如果在该范围内没有达到某一个设定的点数值,则该数据点将会被删除,重复上述此过程直到最后一个数据点,即完成该滤波过程。 二、实现代码 ROR.cuh #ifndef ROR_GPU_CUH#define ROR_GPU_CU

matlab频域滤波

步骤: (1)计算原图像f(x,y)的DFT, (2) 讲频谱的零频点移动到频谱图的中心位置; (3)计算滤波器函数H(U,V)与F(U,V)的乘积G(U,V); (4)讲频谱G(U,V)的零频点移回到频谱图的坐上角。 (5)计算(4)的结果的傅立叶反变换g(x,y); (6)取g(x,y)的实部作为最终的滤波后的结果图像。   代码: 大家别激动的啦   代

工控常用滤波方法(限幅+中值+算术平均+滑动平均)

工控常用滤波方法 简介限幅滤波法中值滤波法算术平均滤波法滑动平均滤波 简介 在实际的工程应用中,实际反馈的信号由于是通过电压及电流转换而来的数字量信号,在现场可能会受到比较大的干扰问题,这样的扰动会影响控制系统的输出精度,也会使其产生比较大的偏差。 故在实际应用中,通常不会直接将反馈的信号作为信号输入,会在之前加一个滤波器以使数据更平滑,在此,非常有必要引入数字滤波的概念。