Python进行点云坡度滤波(Slope-based Filtering)算法

       本节我们介绍一个提取平面的好帮手——点云坡度滤波算法,简称SB算法。虽然名字很SB,但是话糙理不糙,在提取平面方面,真的hin好用。

       点云坡度滤波算法的核心思想是计算点云中每个点与邻域内拟合平面的法向量夹角(坡度),剔除坡度大于阈值的点。这个过程中需要两个参数,分别为邻域半径R(根据点云密度调整,如果你愿意,甚至可以动态调整)和坡度阈值\theta(根据点云平整程度判断,记住不是什么竖直角度)。

       这个过程中需要注意一点的是,边缘部分常常会当作跳变值去掉,可以加个邻域点数判断,避免边缘点的误删。如果还有离群值,加个统计滤波呗!

一、点云处理对象

       本次处理的对象我们的老朋友——窗帘(窗帘我爱你.jpg),可以看到侧边还有底部(其实是房顶)有多余的平面,另外还有一些杂点。我们的目的就是去除这些干扰,只提取窗帘部分。

二、点云坡度滤波程序

坡度滤波和统计滤波放一块辣,组合用效果嘎嘎香。

import open3d as o3d
import numpy as np


def slope_filter(pcd, radius, max_slope_deg, min_neighbors):
    """
    坡度滤波:剔除坡度大于阈值的点

    参数:
        pcd (o3d.geometry.PointCloud): 输入点云
        radius (float): 邻域搜索半径(单位与输入点云一致)
        max_slope_deg (float): 最大坡度阈值(角度,0~90)
        min_neighbors (int): 拟合平面所需的最小邻域点数

    返回:
        o3d.geometry.PointCloud: 滤波后的点云
    """
    points = np.asarray(pcd.points)
    tree = o3d.geometry.KDTreeFlann(pcd)
    mask = np.ones(len(points), dtype=bool)

    max_cos = np.cos(np.radians(max_slope_deg))  # 转换为余弦阈值

    for i, point in enumerate(points):
        # 搜索邻域
        [k, idx, _] = tree.search_radius_vector_3d(point, radius)
        if k < min_neighbors:
            continue  # 邻域点太少,跳过

        # 提取邻域点
        neighbors = points[idx[1:], :]

        # 计算邻域点的协方差矩阵
        centered = neighbors - np.mean(neighbors, axis=0)
        cov = np.cov(centered.T)
        eigenvalues, eigenvectors = np.linalg.eigh(cov)

        # 最小特征值对应的特征向量即法向量
        normal = eigenvectors[:, 0]  # 法向量
        normal = normal / np.linalg.norm(normal)

        # 计算与Z轴的夹角余弦(Z轴向上)
        cos_angle = abs(normal[2])  # 坡度越小,cos_angle越接近1

        # 坡度大于阈值则剔除
        if cos_angle < max_cos:
            mask[i] = False

    # 返回滤波后的点云
    filtered_pcd = pcd.select_by_index(np.where(mask)[0])
    return filtered_pcd


# ------------------- 示例用法 -------------------
if __name__ == "__main__":
    # 加载点云(替换为你的文件路径)
    pcd = o3d.io.read_point_cloud("E:/CSDN/规则点云/实拍/窗帘.ply")  # 或 "input.ply"

    # 执行坡度滤波
    filtered = slope_filter(pcd, radius=500, max_slope_deg=20, min_neighbors=10)

    cl, ind = filtered.remove_statistical_outlier(nb_neighbors=100, std_ratio=3.0)  # 设置邻域为100,滤波保留3*sigma以内的点
    sta_pcd = filtered.select_by_index(ind)  # 根据索引进行点云提取
    # 保存结果
    # o3d.io.write_point_cloud("filtered_slope.pcd", filtered)

    # 可视化
    o3d.visualization.draw_geometries([pcd])
    o3d.visualization.draw_geometries([sta_pcd])

三、坡度滤波结果

加统计滤波之前,可以看到还有少许杂点

加统计滤波之后,仅有的杂点也没辣!

就酱,下次再分享别的^-^

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值