首页 > 其他分享 >Open3D 基于法线的双边滤波

Open3D 基于法线的双边滤波

时间:2024-09-13 09:53:45浏览次数:6  
标签:法线 滤波 邻域 Open3D 点云 sigma pcd points

目录

一、概述

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

        # 对权重进行归一化,使得权重总和为1
        weights /= 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 np



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

        # 对权重进行归一化,使得权重总和为1
        weights /= 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


def 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,点云,sigma,pcd,points
From: https://blog.csdn.net/qq_47947920/article/details/142046528

相关文章

  • Open3D 基于法向量夹角的特征点提取
    目录一、概述1.1原理1.2实现步骤1.3应用场景二、代码实现三、实现效果3.1原始点云3.2提取后点云Open3D点云算法汇总及实战案例汇总的目录地址:Open3D点云算法与点云深度学习案例汇总(长期更新)-CSDN博客一、概述        基于法向量夹角的特征点提取是一种......
  • OpenCV(低通滤波、高通滤波)
    目录1.低通滤波(Low-PassFiltering)1.1概念1.2作用1.3常见类型1.4应用场景1.5频域中的表现2.高通滤波(High-PassFiltering)2.1概念2.2作用2.3常见类型2.4应用场景2.5频域中的表现3.频域滤波的操作过程4.高通滤波与低通滤波的对比5.总结在图像处理领域,低通滤波和高......
  • 关于粒子滤波的解析
    粒子滤波流程基本原理:随机选取预测域的NNN个点,称为粒子。以此计算出预测值,并算出在测量域的概率,即权重,加权平均就是最优估计。之后按权重比例,重采样,进行下次迭代。初始状态:用大量粒子模拟X(t),粒子在空间内均匀分布;预测阶段:根据状态转移方程,每一个粒子得到一个预测粒子;校正阶段:对预......
  • qt5.15.2+opencv4.10+VS2019_64 均值滤波,高斯滤波算法详细分析
    目录 一.加载图像二.灰度图像三.均值滤波1.均值滤波均值滤波算法(MeanFiltering):    参数含义:    一句话总结:均值滤波特点:应用场景:缺点:2.高斯滤波高斯滤波算法(GaussianBlur):        高斯滤波计算过程:    参数含义:    ......
  • MATLAB卡尔曼|卡尔曼滤波的公式【线性】
    卡尔曼滤波卡尔曼滤波(KalmanFilter)是一种用于估计系统状态的数学算法,不是类似于高通、低通滤波器那样的频域滤波。卡尔曼滤波基于线性动态系统的假设,它将系统的状态表示为均值和协方差矩阵,通过递归地更新和预测这些值来实现对系统状态的估计。卡尔曼滤波有两个主要的步......
  • STM32常用数据采集滤波算法
    例如,STM32进行滤波处理时,主要目的是处理数据采集过程中可能产生的噪声和尖刺信号。这些噪声可能来自电源干扰、传感器自身的不稳定性或其他外部因素。1.一阶互补滤波方法:取a=0~1,本次滤波结果=(1-a)本次采样值+a上次滤波结果优点:对周期性干扰具有良好的抑制作用适用于波动频率......
  • 深度解析卡尔曼滤波:原理、作用与应用
    目录一、卡尔曼滤波的基本概念二、卡尔曼滤波的数学原理三、卡尔曼滤波的作用四、卡尔曼滤波的应用五、扩展:扩展卡尔曼滤波和无迹卡尔曼滤波六、总结卡尔曼滤波(KalmanFilter)是一种用于动态系统状态估计的数学算法,尤其适用于存在噪声和不确定性的环境。其广泛应用于......
  • 法线纹理
    切线空间法线纹理用来呈现物体表面的凹凸细节,模型顶点自身的法线定义于模型空间(ObjectSpace)中,模型的法线纹理一般存储在模型顶点的切线空间(TangentSpace)中,一般的,顶点本身为切线空间原点,选择顶点法线方向\(n\)为切线空间的正方向\(z\),法线贴图的\(u\)方向为切线方向\(t\),法线贴......
  • [open3d]点云投影2D图像
    输入:三维点云输出:2DDSMimportopen3daso3dimportnumpyasnpimportcv2#读取点云,转换为栅格图像#将栅格图像分块resolution=0.2save_path=r"dsm.png"print("->正在加载点云...")m_pc=o3d.io.read_point_cloud("WHU.ply")print(m_pc)print('......
  • 图像去噪:基于混合噪声处理的 UNF 滤波器与中值滤波器比较
       在图像处理领域,去噪是一个非常重要的步骤。噪声会严重影响图像的质量,使得图像难以被理解或分析。本文将演示如何使用混合噪声处理技术和两种常见的滤波器(UNF滤波器与中值滤波器)来去除图像中的噪声,并比较它们的性能。1.添加噪声   首先,我们通过impulseNoise......