Python点云处理——统计滤波算法

一、算法原理

        与之前的几种滤波算法相比,统计滤波的原理较为抽象和复杂。对三维点云而言,统计滤波和半径滤波一样,以滤除“离群点”为目的。而统计滤波中离群点的定义比半径滤波更为复杂。在统计滤波中,认为点云整体应呈现出较为均匀的分布,即点云内每个点与和它近邻的K个点之间的平均距离不会超过阈值,超过的则视为离群点。而这一阈值由以下公式决定:

D_{max}=\mu +std\times \sigma

        其中,\mu为某个点到所有点距离的平均值,即

        \mu=\frac{1}{n} \sum_{i=1}^{n}D_{i},

        而\sigma表示的是距离的标准差,即

   \sigma=\sqrt{\frac{1}{n}\sum_{i=1}^{n}(D_i-\mu})^2

        std表示的则是自定义的一个标准差系数,用来控制距离标准差对距离阈值的影响。

        因此,进行统计滤波时,需要先计算出所有点之间的平均距离和标准差,得到距离阈值,然后计算每个点与其近邻的K个点的平均距离,如果大于阈值,说明这个点周围的邻近点都比较”分散“,所以视为离群点。

二、代码示例

        下图的代码会生成一片随机点云,然后对其创建KDtree,遍历整个点云,做最近邻搜索,求出每个点的K个近邻点的平均距离,然后计算所有点的平均距离和标准差,滤出符合要求的点,同时用Open3D的内置统计滤波函数,设置一样的参数进行对比,最后在可视化界面和控制台输出中都可以看到两者的效果是一样的。

fig = plt.figure()
ax= fig.add_subplot(131, projection='3d')
ax2= fig.add_subplot(132, projection='3d')
ax3= fig.add_subplot(133, projection='3d')
# -------- Create KDTtree for X1 and X2. --------
point= np.random.rand(100,3)
ratio=0.0001
ax.scatter3D(point[:,0],point[:,1],point[:,2],c='r',marker=".")
pcd = o3d.geometry.PointCloud()
pcd.points = o3d.utility.Vector3dVector(point)
cl,idx=pcd.remove_statistical_outlier(10,ratio)
point1=point[idx]
ax2.scatter3D(point1[:,0],point1[:,1],point1[:,2],c='g',marker=".")
# tree1 = KDTree(point)
idx1=np.asarray(range(0,len(point)))
idx3=np.empty(1,int)
k_dist = np.zeros(len(point))
tree = sp.spatial.KDTree(point[:,:3])
for i in range(0,len(point)):
    nb=tree.query(point[i,:3],k=10,workers=-1)
    nb_dt = nb[0]
    k_dist[i] = np.sum(nb_dt)
max_distance = np.mean(k_dist) +ratio*np.std(k_dist)
#idx3=np.where(k_dist<max_distance,idx1,-1)
idx3=np.where(k_dist<max_distance)
idx4=np.where(idx3>-1)
idx3=idx3[idx4]
# for i in range(0,len(point)):
#     if k_dist[i]<max_distance:
#         idx3=np.append(idx3,i)
idx3=np.unique(idx3,axis=0)
point3=point[idx3,:]

print(len(point1),len(point3))
ax3.scatter3D(point3[:,0],point3[:,1],point3[:,2],c='b',marker=".")
#
plt.show()

        封装成函数形式的代码: 

def statistical_filter(point,n,std_ratio):
    k_dist = np.zeros(len(point))
    tree = sp.spatial.KDTree(point[:, :3])
    for i in range(0, len(point)):
        nb = tree.query(point[i, :3], k=n, workers=-1)
        nb_dt = nb[0]
        k_dist[i] = np.sum(nb_dt)
    max_distance = np.mean(k_dist) + std_ratio * np.std(k_dist)
    idx=np.where(k_dist<max_distance)
    # idx2=idx[idx1]
    # for i in range(0, len(point)):
    #     if k_dist[i] < max_distance:
    #         idx = np.append(idx,i)
    #numpy的where函数速度远快于遍历
    point = point[idx]
    return point

  • 16
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
激光点云统计滤波是一种常用的点云滤波方法,适用于去除点云中的离群点和噪声。其主要思想是通过统计每个点的邻域内的点的属性,如距离、密度等属性进行滤波。 激光点云统计滤波的源码实现可以从以下几个方面进行描述: 1. 首先,需要定义一个合适的邻域大小,用于确定每个点周围的点的个数。可以选择邻域为固定大小的立方体或球体,也可以根据点云的密度自适应调整邻域大小。 2. 然后,对于每个点,需要计算其邻域内的点的属性,如平均距离、平均法向量等。可以通过计算欧氏距离来确定邻域内每个点与该点的距离,并求得平均距离。法向量的计算可以使用最小二乘法或PCA等方法。 3. 接下来,需要定义一个阈值,用于判断每个点是否为离群点。可以通过设置一个最大距离或最小密度阈值来判断,如果某个点的属性超过了阈值,则认为该点是离群点。 4. 最后,将满足条件的点筛选出来,形成一个新的经过滤波点云。 对于具体的源码实现,可以使用一些点云处理库或软件实现,如PCL (Point Cloud Library)等。在PCL中,可以使用PointCloud类来表示点云数据,通过PointCloud类提供的成员函数和方法实现滤波操作。具体滤波方法可以使用PCL中提供的StatisticalOutlierRemoval类,通过设置需要的参数和阈值实现激光点云统计滤波。 总结起来,激光点云统计滤波源码的实现需要确定邻域大小、计算点的属性、设置阈值以及通过合适的库或软件实现相关操作。具体的实现可以参考相关的点云处理库或算法

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

周_必_成

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值