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)


3267

被折叠的 条评论
为什么被折叠?



