(一) 三维点云课程---Voxel Grid Downsamping

三维点云课程—Voxel Grid Downsamping

1.选取点的方案

1.质心法:计算所有满足条件点的平均值,速度慢,但相对准确
2.随机法:从满足条件的点中随机选择一个点,速度块,但误差大

2.步骤

1.计算三维点集 p 1 , p 2 , . . . , p N {p_1,p_2,...,p_N} p1,p2,...,pN的最小和最大值
x max ⁡ = max ⁡ ( x 1 , x 2 , ⋯   , x N ) , x min ⁡ = min ⁡ ( x 1 , x 2 , ⋯   , x N ) , y max ⁡ = ⋯ ⋯ x_{\max }=\max \left(x_{1}, x_{2}, \cdots, x_{N}\right), x_{\min }=\min \left(x_{1}, x_{2}, \cdots, x_{N}\right), y_{\max }=\cdots \cdots xmax=max(x1,x2,,xN),xmin=min(x1,x2,,xN),ymax=
2.设置一个voxel grid的大小r

3.计算x,y,z关于voxel grid的维数
D x = ( x max ⁡ − x min ⁡ ) / r D y = ( y max ⁡ − y min ⁡ ) / r D z = ( z max ⁡ − z min ⁡ ) / r \begin{aligned} D_{x} &=\left(x_{\max }-x_{\min }\right) / r \\ D_{y} &=\left(y_{\max }-y_{\min }\right) / r \\ D_{z} &=\left(z_{\max }-z_{\min }\right) / r \end{aligned} DxDyDz=(xmaxxmin)/r=(ymaxymin)/r=(zmaxzmin)/r
4.计算每个点关于voxel的索引
h x = ⌊ ( x − x min ⁡ ) / r ⌋ h y = ⌊ ( y − y min ⁡ ) / r ⌋ h z = ⌊ ( z − z min ⁡ ) / r ⌋ h = h x + h y ∗ D x + h z ∗ D x ∗ D y \begin{aligned} h_{x} &=\left\lfloor\left(x-x_{\min }\right) / r\right\rfloor \\ h_{y} &=\left\lfloor\left(y-y_{\min }\right) / r\right\rfloor \\ h_{z} &=\left\lfloor\left(z-z_{\min }\right) / r\right\rfloor \\ h &=h_{x}+h_{y} * D_{x}+h_{z} * D_{x} * D_{y} \end{aligned} hxhyhzh=(xxmin)/r=(yymin)/r=(zzmin)/r=hx+hyDx+hzDxDy
其中 ⌊ ⌋ \left\lfloor\right\rfloor 符号表示取整的意思

5.对第四步得到的h的索引进行排序,编程中注意:原始三维坐标点也要跟着一起变化

6.选择一种选取点的方案(质心法还是随机法),进行筛选。

例如排序后h的索引为
0 , 0 , 0 , 0 , 3 , 3 , 3 , 8 , 8 , 8 , 8 , 8 , 8 , . . . . 0,0,0,0,3,3,3,8,8,8,8,8,8,.... 0000333888888....
那么质心法就是在所有0的索引所对应的原始点云中进行求均值,随机法就是在所有0的索引中随机选择一个索引,再通过这个索引得到原始点云的数据。对于3或者8也是这样。可能表述的并不是很清楚,具体参见代码,代码中有详细的解释

3.Voxel Grid Downsamping 代码

# 实现voxel滤波,并加载数据集中的文件进行验证

import open3d as o3d 
import os
import numpy as np
from pyntcloud import PyntCloud

# 采用均值法获取所有相关的索引
def get_all_index(lst,item):
    return [i for i in range(len(lst)) if lst[i]==item]

## 采用随机法获取其中的一个索引
def get_one_index(lst,item):
    for i in range(len(lst)):
        if lst[i]==item:
            return i

# 功能:对点云进行voxel滤波
# 输入:point_cloud:输入点云
#       leaf_size: voxel尺寸
# 输出:filtered_points:滤波后的点云
def voxel_filter(point_cloud, leaf_size,method="centroid"):
    filtered_points = []
    filtered_idx=[]

    minPC=np.min(point_cloud)
    maxPC=np.max(point_cloud)
    Dx=(maxPC[0]-minPC[0])/leaf_size
    Dy=(maxPC[1]-minPC[1])/leaf_size
    #Dz=(maxPC[2]-minPC(2))/leaf_size

    N=point_cloud.shape[0]
    for i in range(N):
        hx=(np.asarray(point_cloud)[i][0] -  minPC[0] )//leaf_size
        hy=(np.asarray(point_cloud)[i][1] -  minPC[1] ) //leaf_size
        hz=(np.asarray(point_cloud)[i][2] -  minPC[2] )//leaf_size
        idx=hx+hy*Dx+hz*Dx*Dy
        filtered_idx.append(idx)

    #argsort函数返回的是数组值从小到大的索引值,加上[::-1]表示从大到小
    sort_idx=np.array(filtered_idx).argsort()[::-1]

    #filtered_idx_ok里面由相等的数,且按照从大到小的顺序进行
    filtered_idx_ok=np.array(filtered_idx)[sort_idx]

    #point_cloud_ok是将原始点云数据point_cloud按照sort_idx进行排列
    point_cloud_ok=np.asarray(point_cloud)[sort_idx]

    #set()函数产生一个无序不重复元素集,给下面的for循环使用
    idx_set=set(filtered_idx_ok)

    if method=="centroid":
        print("method is centroid")
        for i in idx_set:
            all_idx=get_all_index(filtered_idx_ok,i)
            #axis = 0:压缩行,对各列求均值,返回 1* n 矩阵
            xm=np.mean(np.asarray(point_cloud_ok)[all_idx],axis=0)
            filtered_points.append(xm)
    elif method=="random":
        print("method is random")
        for i in idx_set:
            one_idx=get_one_index(filtered_idx_ok,i)
            xm=np.asarray(point_cloud_ok)[one_idx]
            filtered_points.append(xm)

    # 把点云格式改成array,并对外返回
    filtered_points = np.array(filtered_points, dtype=np.float64)
    return filtered_points

def main():
    # 加载自己的点云文件
    file_name = r"D:\ply_data\airplane\train\airplane_0001.ply"
    point_cloud_pynt = PyntCloud.from_file(file_name)

    #显示原图
    point_cloud_o3d = point_cloud_pynt.to_instance("open3d", mesh=False)
    o3d.visualization.draw_geometries([point_cloud_o3d]) # 显示原始点云

    # 调用voxel滤波函数,实现滤波
    filtered_cloud = voxel_filter(point_cloud_pynt.points, 10,method="random")
    point_cloud_o3d.points = o3d.utility.Vector3dVector(filtered_cloud)
    # 显示滤波后的点云
    o3d.visualization.draw_geometries([point_cloud_o3d])

if __name__ == '__main__':
    main()

由于数据集比较大,需要的话请加我QQ:2822902808,备注:点云数据集

4.仿真结果

原图:
滤波前
滤波后
滤波

  • 2
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值