第十五课Open3D点云数据处理:体素滤波之近似体素质心、中心下采样

Python3.8

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

体素滤波之近似体素质心下采样

1 体素下采样原理

1.1 体素下采样分类

1.2 下采样结果对比

2 体素中心下采样代码实现

2.1 代码行实现

2.2 函数封装 my_approximate_voxel_down_sample()

体素滤波之体素中心下采样

代码实现

代码封装

参考文献


体素滤波之近似体素质心下采样

1 体素下采样原理

点云体素下采样(Voxel Downsampling)是一种将点云数据进行降采样的方法。点云体素下采样的基本原理是将点云数据分割成小的体素(Voxel,小的正方体单元),并只保留每个体素内部的一个点,而剩余的所有点则被丢弃。这样就可以减小点云数据的大小,从而降低计算量,提高点云数据处理的速度和效率。

1.1 体素下采样分类

根据保留体素内点的形式,可分为体素质心下采样、体素中心下采样、近似体素中心下采样。

体素质心下采样

计算体素内所有点的质心,以质心坐标代替体素内所有点的坐标。
优点:计算速度快
缺点:下采样后的点为体素质心,是新的点,而不是原始点云中的点。

体素中心下采样

以体素中心代替体素内所有点的坐标。
优点:相比计算质心,直接计算体素中心的速度更快,且体素内的点越多,速度差异越明显。
缺点:下采样后的点为体素中心,是新的点,而不是原始点云中的点,且会导致原始点云变形,就如像素点一般整整齐齐排列。

近似体素质心下采样

计算体素内所有点的质心,保留距离体素质心最近的一个点,过滤其他点。
优点:下采样后的点为原始点云中的点
缺点:计算质心后还要计算体素内的点到质心的距离,计算速度较慢。

1.2 下采样结果对比

2 体素中心下采样代码实现

2.1 代码行实现

import numpy as np 
import open3d as o3d

# 读取点云
pcd = o3d.io.read_point_cloud(r"H:\HTempWK\temp\open3d\pointdata\feiji.pcd")

# 体素边长
voxel_size = 0.05

# 计算点云的范围
min_bound = pcd.get_min_bound()
max_bound = pcd.get_max_bound()

# 计算体素数量和体素质心
x_size = int(np.ceil((max_bound[0] - min_bound[0]) / voxel_size))
y_size = int(np.ceil((max_bound[1] - min_bound[1]) / voxel_size))
z_size = int(np.ceil((max_bound[2] - min_bound[2]) / voxel_size))
# 体素质心坐标
voxel_centers = np.zeros((x_size, y_size, z_size, 3))
# 体素个数
voxel_count = np.zeros((x_size, y_size, z_size))

# 遍历每个点,将其放入对应的体素中
points = np.asarray(pcd.points)
for i, point in enumerate(points):
    voxel = ((point - min_bound) // voxel_size).astype(int)
    voxel_count[voxel[0], voxel[1], voxel[2]] += 1
    voxel_centers[voxel[0], voxel[1], voxel[2]] += point

# 遍历每个体素,如果有点则计算质心,否则跳过
down_points = []
for i in range(x_size):
    for j in range(y_size):
        for k in range(z_size):
            if voxel_count[i, j, k] > 0:
                voxel_centers[i, j, k] /= voxel_count[i, j, k]
                # 获取体素内距离体素质心最近的点
                dist = np.sqrt(np.sum(np.square(points - voxel_centers[i, j, k]), axis=1))
                nearest_idx = np.argmin(dist)
                down_points.append(points[nearest_idx])

# 将近似体素质心作为下采样点云的点集
down_pcd = o3d.geometry.PointCloud()
down_pcd.points = o3d.utility.Vector3dVector(down_points)

# 原始点云赋色
pcd.paint_uniform_color([1, 0.5, 0.2])
# 可视化原始点云
o3d.visualization.draw_geometries([pcd], window_name="原始点云", width=800, height=500)

# 下采样点云赋色
down_pcd.paint_uniform_color([0.1, 0.47, 1])
# 可视化下采样点云
o3d.visualization.draw_geometries([down_pcd], window_name="近似体素质心下采样点云", width=800, height=500)

# 保存下采样点云
# o3d.io.write_point_cloud("data/approximate_voxel_down_sample.pcd",down_pcd)

2.2 函数封装 my_approximate_voxel_down_sample()

my_approximate_voxel_down_sample(o3d.geometry.PointCloud()->pointCloud,float->voxel_size)

参数:
pcd:点云
voxel_size:正方体体素边长

import numpy as np
import open3d as o3d

"""
@describe: 近似体素质心下采样
@param[I]: pcd, 原始点云
@param[I]: voxel_size, 体素边长
@return: down_pcd: 近似体素质心下采样点云
"""
def my_approximate_voxel_down_sample(pcd, voxel_size):
    # 计算点云的范围
    min_bound = pcd.get_min_bound()
    max_bound = pcd.get_max_bound()

    # 计算体素数量和体素中心位置
    x_size = int(np.ceil((max_bound[0] - min_bound[0]) / voxel_size))
    y_size = int(np.ceil((max_bound[1] - min_bound[1]) / voxel_size))
    z_size = int(np.ceil((max_bound[2] - min_bound[2]) / voxel_size))

    # 体素质心坐标
    voxel_centers = np.zeros((x_size, y_size, z_size, 3))
    # 体素个数
    voxel_count = np.zeros((x_size, y_size, z_size))

    # 遍历每个点,将其放入对应的体素中
    points = np.asarray(pcd.points)
    for i, point in enumerate(points):
        voxel = ((point - min_bound) // voxel_size).astype(int)
        voxel_count[voxel[0], voxel[1], voxel[2]] += 1
        voxel_centers[voxel[0], voxel[1], voxel[2]] += point

    # 遍历每个体素,如果有点则计算质心,否则跳过
    down_points = []
    for i in range(x_size):
        for j in range(y_size):
            for k in range(z_size):
                if voxel_count[i, j, k] > 0:
                    voxel_centers[i, j, k] /= voxel_count[i, j, k]
                    # 获取体素内距离体素质心最近的点
                    dist = np.sqrt(np.sum(np.square(points - voxel_centers[i, j, k]), axis=1))
                    nearest_idx = np.argmin(dist)
                    down_points.append(points[nearest_idx])

    # 将近似体素质心作为下采样点云的点集
    down_pcd = o3d.geometry.PointCloud()
    down_pcd.points = o3d.utility.Vector3dVector(down_points)

    # 将下采样结果作为返回值返回
    return down_pcd

if __name__ == "__main__":
    # 读取点云文件
    pcd = o3d.io.read_point_cloud("data/desk.pcd")

    # 定义存放下采样点云的容器
    down_pcd = o3d.geometry.PointCloud()

    # 调用my_approximate_voxel_down_sample函数
    down_pcd = my_approximate_voxel_down_sample(pcd,voxel_size=0.05)

    # 下采样点云赋色
    down_pcd.paint_uniform_color([0.1, 0.47, 1])

    # 可视化下采样点云
    o3d.visualization.draw_geometries([down_pcd], window_name="近似体素质心下采样点云", width=800, height=500)

    # 保存下采样点云
    # o3d.io.write_point_cloud("data/approximate_voxel_down_sample.pcd",down_pcd)

体素滤波之体素中心下采样

代码实现

import numpy as np 
import open3d as o3d

# 读取点云
pcd = o3d.io.read_point_cloud("data/desk.pcd")

# 体素边长
voxel_size = 0.05

# 计算点云的范围
min_bound = pcd.get_min_bound()
max_bound = pcd.get_max_bound()

# 计算体素数量和体素中心
x_size = int(np.ceil((max_bound[0] - min_bound[0]) / voxel_size))
y_size = int(np.ceil((max_bound[1] - min_bound[1]) / voxel_size))
z_size = int(np.ceil((max_bound[2] - min_bound[2]) / voxel_size))
# 体素中心坐标
voxel_centers = []
# 遍历每个体素,计算其中心点
for i in range(x_size):
    for j in range(y_size):
        for k in range(z_size):
            voxel_min = np.array([i, j, k]) * voxel_size + min_bound
            voxel_max = voxel_min + voxel_size
            voxel_center = (voxel_min + voxel_max) / 2.0
            voxel_centers.append(voxel_center)

# 遍历每个点,将其划入对应的体素中
points = np.asarray(pcd.points)
down_points = []
for i, point in enumerate(points):
    voxel = ((point - min_bound) // voxel_size).astype(int)
    voxel_idx = voxel[0] * y_size * z_size + voxel[1] * z_size + voxel[2]
    if voxel_idx < len(voxel_centers):
        down_points.append(voxel_centers[voxel_idx])

# 将中心点作为下采样点云的点集
down_pcd = o3d.geometry.PointCloud()
down_pcd.points = o3d.utility.Vector3dVector(down_points)

# 原始点云赋色
pcd.paint_uniform_color([1, 0.5, 0.2])
# 可视化原始点云
o3d.visualization.draw_geometries([pcd], window_name="原始点云", width=800, height=500)

# 下采样点云赋色
down_pcd.paint_uniform_color([0.1, 0.47, 1])
# 可视化下采样点云
o3d.visualization.draw_geometries([down_pcd], window_name="体素中心下采样点云", width=800, height=500)

# 保存下采样点云
# o3d.io.write_point_cloud("data/voxel_center_down_sample.pcd",down_pcd)

代码封装

my_approximate_voxel_down_sample(o3d.geometry.PointCloud()->pointCloud,float->voxel_size)

参数:
pcd:点云
voxel_size:正方体体素边长

import numpy as np
import open3d as o3d

"""
@describe: 体素中心下采样
@param[I]: pcd, 原始点云
@param[I]: voxel_size, 体素边长
@return: down_pcd: 体素中心下采样点云
"""
def my_voxel_center_down_sample(pcd, voxel_size):
    # 计算点云的范围
    min_bound = pcd.get_min_bound()
    max_bound = pcd.get_max_bound()

    # 计算体素数量和体素中心位置
    x_size = int(np.ceil((max_bound[0] - min_bound[0]) / voxel_size))
    y_size = int(np.ceil((max_bound[1] - min_bound[1]) / voxel_size))
    z_size = int(np.ceil((max_bound[2] - min_bound[2]) / voxel_size))

    # 体素中心坐标
    voxel_centers = []
    # 遍历每个体素,计算其中心点
    for i in range(x_size):
        for j in range(y_size):
            for k in range(z_size):
                voxel_min = np.array([i, j, k]) * voxel_size + min_bound
                voxel_max = voxel_min + voxel_size
                voxel_center = (voxel_min + voxel_max) / 2.0
                voxel_centers.append(voxel_center)

    # 遍历每个点,将其划入对应的体素中
    points = np.asarray(pcd.points)
    down_points = []
    for i, point in enumerate(points):
        voxel = ((point - min_bound) // voxel_size).astype(int)
        voxel_idx = voxel[0] * y_size * z_size + voxel[1] * z_size + voxel[2]
        if voxel_idx < len(voxel_centers):
            down_points.append(voxel_centers[voxel_idx])

    # 将中心点作为下采样点云的点集
    down_pcd = o3d.geometry.PointCloud()
    down_pcd.points = o3d.utility.Vector3dVector(down_points)

    # 将下采样结果作为返回值返回
    return down_pcd


if __name__ == "__main__":
    # 读取点云文件
    pcd = o3d.io.read_point_cloud("data/desk.pcd")

    # 定义存放下采样点云的容器
    down_pcd = o3d.geometry.PointCloud()

    # 调用my_voxel_center_down_sample函数
    down_pcd = my_voxel_center_down_sample(pcd,voxel_size=0.05)

    # 下采样点云赋色
    down_pcd.paint_uniform_color([0.1, 0.47, 1])

    # 可视化下采样点云
    o3d.visualization.draw_geometries([down_pcd], window_name="体素中心下采样点云", width=800, height=500)

参考文献

https://sunwukong.blog.csdn.net/article/details/131948187

https://sunwukong.blog.csdn.net/article/details/131948275

您可能感兴趣的与本文相关的镜像

Python3.8

Python3.8

Conda
Python

Python 是一种高级、解释型、通用的编程语言,以其简洁易读的语法而闻名,适用于广泛的应用,包括Web开发、数据分析、人工智能和自动化脚本

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值