算法介绍
基于哈希表的采样在计算机图形学和计算机视觉领域中有一些应用,尤其是在点云处理和采样中。下面是基于哈希表的采样的一些作用:
去重: 哈希表可以用于快速检查点云中是否存在重复的点。通过将点的坐标映射到哈希表中,可以在常数时间内检查点是否已经存在。这在点云处理中是一个常见的步骤,以确保采样后的点集中不包含重复的点。
快速查找: 使用哈希表可以实现对点云的快速查找。通过将点的坐标映射到哈希表的索引,可以在常数时间内找到对应的点。这对于点云的快速查询和检索是很有用的。
降采样: 哈希表可以用于点云的降采样,即从原始点云中提取一部分代表性的点,以减少点的数量。通过在哈希表中记录每个栅格(或者哈希桶)中的一个点,可以有效地降低点云的密度,而仍然保留重要的形状信息。
加速算法: 在一些图形学和计算机视觉算法中,哈希表也被用于加速搜索和匹配过程。例如,基于哈希表的加速结构可以在点云中进行最近邻搜索,用于查找每个点的邻域。
实现原理
确定哈希函数:
选择或设计一个哈希函数,将点的坐标映射到一个唯一的整数值(哈希码)。这个哈希函数应该使得相邻的点在哈希表中有较大可能性映射到不同的位置,以减少冲突。
创建哈希表:
通过哈希函数的映射,创建一个哈希表,表的每个槽存储一个链表或数组,用于存储哈希到同一个位置的所有点。哈希表的大小通常根据点云的特性和数据分布进行调整。
遍历点云并插入:
遍历点云中的每个点,计算其哈希值,然后将点插入到相应的哈希表槽中。如果两个点具有相同的哈希值(哈希冲突),它们将存储在同一个槽中的链表或数组中。
查询和处理:
当需要查询或处理点云中的点时,可以使用哈希函数计算点的哈希值,然后在哈希表中查找对应的槽,以获取哈希到同一位置的所有点。这样可以提高点云数据的检索效率。
实现结果
原始点云数据
均匀降采样数据
随机降采样数据
实现代码
import random
import open3d as o3d
import os
import numpy as np
from pyntcloud import PyntCloud
# 功能:对点云进行基于hash表的voxel滤波
# 输入:
# point_cloud:输入点云
# leaf_size: voxel尺寸
def voxel_filter(point_cloud, leaf_size: float,function: str):
filtered_points = []
data = point_cloud.values
# 求出x,y,z三轴各自的最小值、最大值
min_d = data.min(axis=0)
max_d = data.max(axis=0)
# 求出x,y,z三轴各自的维度
D = (max_d - min_d)/leaf_size
# 基于hash表的采样算法
voxel = [[] for _ in range(int(D[0]*D[1]*D[2]))]
for i,point in enumerate(data):
h_xyz = (point - min_d) // leaf_size # 求第i点的hx,hy,hz
h =round(h_xyz[0] + h_xyz[1] * D[0] + h_xyz[2] *D[0] * D[1])
if 0 <= h < len(voxel):
voxel[int(h)].append(i) #在序号为point_h的栅格中存储当前点云
# 均值采样
if function == "centriod":
for v in voxel:
if len(v) == 0:
continue
filtered_points.append(np.sum(data[v],axis=0)/len(v))
# 随机采样
if function == "random":
for v in voxel:
if len(v) == 0:
continue
filtered_points.append(data[random.choice(v)])
# 把点云格式改成array,并对外返回
filtered_points = np.array(filtered_points, dtype=np.float64)
return filtered_points[:,:3]
def main():
# 加载自己的点云文件
file_name = "bed_0003.txt"
point_cloud_pynt = PyntCloud.from_file(file_name, header=None, names=["x", "y", "z", "nx", "ny", "nz"])
# 转成open3d能识别的格式
point_cloud_o3d = point_cloud_pynt.to_instance("open3d", mesh=False)
o3d.visualization.draw_geometries([point_cloud_o3d]) # 显示原始点云
print("原始点云个数是:",len(point_cloud_o3d.points))
# 调用voxel滤波函数,实现滤波
filtered_cloud = voxel_filter(point_cloud_pynt.points, 0.05,function = "random") # 0.01是要划分栅格的大小,要根据实际点云坐标和大小设置
point_cloud_o3d.points = o3d.utility.Vector3dVector(filtered_cloud)
# 显示滤波后的点云
o3d.visualization.draw_geometries([point_cloud_o3d])
print("滤波后点云个数是:", len(point_cloud_o3d.points))
if __name__ == '__main__':
main()