三维点云学习(1)下-点云体素降采样

三维点云学习(1)下

点云体素降采样(Voxel Filter Downsampling)

代码参考网址秦乐乐CSDN博客
理论参考知乎博主:WALL-E

1.方法

Centroid 均值采样
Random select 随机采样
三维点云学习(1)下-点云体素降采样_第1张图片

2.伪代码流程

三维点云学习(1)下-点云体素降采样_第2张图片

3.代码编写

step1 计算边界值

    #step1 计算边界点
    xmax, ymax, zmax = np.amax(pointcloud,axis=0)      #计算 x,y,z三个维度的最值
    x_min, y_min, z_min = np.amin(point_cloud, axis=0)

step2 确定体素的尺寸

    #step2 确定体素的尺寸
    size_r = leaf_size

step3 计算每个 volex的维度

    #step3 计算每个 volex的维度
    Dx = (x_max - x_min)/size_r +1
    Dy = (y_max - y_min)/size_r +1
    Dz = (z_max - z_min)/size_r +1

step4 计算每个点在volex grid内每一个维度的值

    #step4 计算每个点在volex grid内每一个维度的值
    h = list()
    for i in range(len(point_cloud)):
        Dx = (x_max - x_min)/size_r
        Dy = (y_max - y_min)/size_r
        Dz = (z_max - z_min)/size_r
        h.append(hx + hyDx + hzDxDy)

step5 对h值进行排序

    h = np.array(h)
    h_indice  = np.argsort(h)   #提取索引
    h_sorted = h[h_indice]      #升序

将h值相同的点放入到同一个grid中,并进行筛选,并区分random和centroid两种滤波方式

    count = 0 #用于维度的累计
    #将h值相同的点放入到同一个grid中,并进行筛选
    for i  in range(len(h_sorted)-1):      #0-19999个数据点
        if h_sorted[i] == h_sorted[i+1]:   #当前的点与后面的相同,放在同一个volex grid中
            continue
        else:
            if(filter_mode == "centroid"):    #均值滤波
                point_idx = h_indice[count: i+1]
                filtered_points.append(np.mean(point_cloud[point_idx],axis=0))   #取同一个grid的均值
                count = i
            elif(filter_mode == "random"):  #随机滤波
                point_idx = h_indice[count: i+1]
                random_points =  random.choice(point_cloud[point_idx])
                filtered_points.append(random_points)
                count = i

调用

    # 调用voxel滤波函数,实现滤波
    filtered_cloud = voxel_filter(points, 0.05, "random")   #centroid or random
    point_cloud_o3d_filter.points = o3d.utility.Vector3dVector(filtered_cloud)

效果图

原点云图在open3d中展示如下
三维点云学习(1)下-点云体素降采样_第3张图片
random随机降采样效果如下
三维点云学习(1)下-点云体素降采样_第4张图片
centroid随机降采样效果如下
三维点云学习(1)下-点云体素降采样_第5张图片
整体对比
三维点云学习(1)下-点云体素降采样_第6张图片

完整代码

注意:数据集放在相应运行的目录下

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
"""
Created on Sat Feb 20 08:47:58 2021

@author: renzhanqi
"""

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

import open3d as o3d 
import os
import numpy as np
from pyntcloud import PyntCloud
import matplotlib.pyplot as plt
import random
from pandas import DataFrame

# matplotlib显示点云函数
def Point_Cloud_Show(points):
    fig = plt.figure(dpi=150)
    ax = fig.add_subplot(111, projection='3d')
    ax.scatter(points[:, 0], points[:, 1], points[:, 2], cmap='spectral', s=2, linewidths=0, alpha=1, marker=".")
    plt.title('Point Cloud')
    ax.set_xlabel('x')
    ax.set_ylabel('y')
    ax.set_zlabel('z')
    plt.show()

# 二维点云显示函数
def Point_Show(pca_point_cloud):
    x = []
    y = []
    pca_point_cloud = np.asarray(pca_point_cloud)
    for i in range(10000):
        x.append(pca_point_cloud[i][0])
        y.append(pca_point_cloud[i][1])
    plt.scatter(x, y)
    plt.show()



# 功能:对点云进行voxel滤波
# 输入:
#     point_cloud:输入点云
#     leaf_size: voxel尺寸
def voxel_filter(point_cloud, leaf_size,filter_mode):
    filtered_points = []
    # 作业3
    # 屏蔽开始
    #step1 计算边界点
    x_max, y_max, z_max = np.amax(point_cloud,axis=0)      #计算 x,y,z三个维度的最值
    x_min, y_min, z_min = np.amin(point_cloud, axis=0)
    #step2 确定体素的尺寸
    size_r = leaf_size
    #step3 计算每个 volex的维度
    Dx = (x_max - x_min)/size_r
    Dy = (y_max - y_min)/size_r
    Dz = (z_max - z_min)/size_r
    #step4 计算每个点在volex grid内每一个维度的值
    h = list()
    for i in range(len(point_cloud)):
        hx = np.floor((point_cloud[i][0] - x_min)/size_r)
        hy = np.floor((point_cloud[i][1] - y_min)/size_r)
        hz = np.floor((point_cloud[i][2] - z_min)/size_r)
        h.append(hx + hy*Dx + hz*Dx*Dy)
    #step5 对h值进行排序
    h = np.array(h)
    h_indice  = np.argsort(h)   #提取索引
    h_sorted = h[h_indice]      #升序
    count = 0 #用于维度的累计
    #将h值相同的点放入到同一个grid中,并进行筛选
    for i  in range(len(h_sorted)-1):      #0-19999个数据点
        if h_sorted[i] == h_sorted[i+1]:   #当前的点与后面的相同,放在同一个volex grid中
            continue
        else:
            if(filter_mode == "centroid"):    #均值滤波
                point_idx = h_indice[count: i+1]
                filtered_points.append(np.mean(point_cloud[point_idx],axis=0))   #取同一个grid的均值
                count = i
            elif(filter_mode == "random"):  #随机滤波
                point_idx = h_indice[count: i+1]
                random_points =  random.choice(point_cloud[point_idx])
                filtered_points.append(random_points)
                count = i

    # 屏蔽结束

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

def main():
    # # 从ModelNet数据集文件夹中自动索引路径,加载点云
    # cat_index = 10 # 物体编号,范围是0-39,即对应数据集中40个物体
    # root_dir = '/Users/renqian/cloud_lesson/ModelNet40/ply_data_points' # 数据集路径
    # cat = os.listdir(root_dir)
    # filename = os.path.join(root_dir, cat[cat_index],'train', cat[cat_index]+'_0001.ply') # 默认使用第一个点云
    # point_cloud_pynt = PyntCloud.from_file(file_name)

    # 加载自己的点云文件
    point_cloud_raw = np.genfromtxt(r"/home/renzhanqi/code/pythonCode/shenLanLidarPrcess/data/modelnet40_normal_resampled/person/person_0001.txt", delimiter=",")
    point_cloud_raw = DataFrame(point_cloud_raw[:,0:3])   # 为 xyz的 N*3矩阵
    point_cloud_raw.columns = ['x', 'y', 'z']  # 给选取到的数据 附上标题
    point_cloud_pynt = PyntCloud(point_cloud_raw)  # 将points的数据 存到结构体中

    point_cloud_o3d_orign = point_cloud_pynt.to_instance("open3d", mesh=False)  # to_instance实例化
    point_cloud_o3d_filter = o3d.geometry.PointCloud()     #实例化

    # o3d.visualization.draw_geometries([point_cloud_o3d]) # 显示原始点云

    points = np.array(point_cloud_o3d_orign.points)

    # 调用voxel滤波函数,实现滤波
    filtered_cloud = voxel_filter(points, 0.05, "centroid")   #centroid or random
    point_cloud_o3d_filter.points = o3d.utility.Vector3dVector(filtered_cloud)
    # 显示滤波前后的点云
    o3d.visualization.draw_geometries([point_cloud_o3d_orign])
    o3d.visualization.draw_geometries([point_cloud_o3d_filter])
if __name__ == '__main__':
    main()

 

你可能感兴趣的:(点云处理,深蓝点云处理课程笔记,python)