如何在Python中按距离阈值分组距离较近的3D点?
3D点按距离阈值分组的实现方案
算法简易指引
- 初始化剩余点集为原始点的副本,避免修改原数据
- 初始化分组列表,用于存储最终的点组
- 循环处理剩余点集,直到为空:
- 取出剩余点集中的第一个点作为当前组的核心点
- 遍历剩余点,筛选出所有与核心点的欧氏距离≤设定阈值的点,组成当前分组
- 从剩余点集中移除这些已分组的点
- 将当前分组加入分组列表
- 若需要将单个点归为未分组,可在最后对分组列表做筛选:保留点数≥2的组,将单点点组的点归入未分组列表
示例代码
纯Python实现(无需额外库)
import math def group_3d_points(points, distance_threshold, single_point_as_ungrouped=True): # 复制原始点集,避免修改输入数据 remaining_points = points.copy() groups = [] while remaining_points: # 取第一个点作为当前组的核心点 core_point = remaining_points[0] current_group = [] to_remove = [] # 遍历剩余点,计算欧氏距离并筛选符合条件的点 for idx, point in enumerate(remaining_points): distance = math.sqrt( (point[0] - core_point[0])**2 + (point[1] - core_point[1])**2 + (point[2] - core_point[2])**2 ) if distance <= distance_threshold: current_group.append(point) to_remove.append(idx) # 倒序删除已分组的点,避免索引错乱 for idx in reversed(to_remove): del remaining_points[idx] groups.append(current_group) # 区分单点点组和有效分组 if single_point_as_ungrouped: valid_groups = [] ungrouped = [] for group in groups: if len(group) > 1: valid_groups.append(group) else: ungrouped.extend(group) return valid_groups, ungrouped else: return groups, remaining_points # 测试示例 if __name__ == "__main__": sample_points = [ (0, 0, 0), (0.1, 0.1, 0.1), (10, 10, 10), (10.2, 10.3, 10.1), (20, 20, 20) ] threshold = 1.0 groups, ungrouped = group_3d_points(sample_points, threshold) print("有效分组:") for i, group in enumerate(groups): print(f"组{i+1}: {group}") print(f"未分组点:{ungrouped}")
用Numpy简化计算(代码更简洁)
如果可以安装Numpy库(执行pip install numpy即可),用向量运算能简化距离计算:
import numpy as np def group_3d_points_np(points, distance_threshold, single_point_as_ungrouped=True): remaining_points = np.array(points) groups = [] while len(remaining_points) > 0: core_point = remaining_points[0] # 批量计算所有点与核心点的欧氏距离 distances = np.linalg.norm(remaining_points - core_point, axis=1) # 筛选符合距离阈值的点 mask = distances <= distance_threshold current_group = remaining_points[mask].tolist() # 更新剩余点集 remaining_points = remaining_points[~mask] groups.append(current_group) # 区分单点点组和有效分组 if single_point_as_ungrouped: valid_groups = [] ungrouped = [] for group in groups: if len(group) > 1: valid_groups.append(group) else: ungrouped.extend(group) return valid_groups, ungrouped else: return groups, remaining_points.tolist() # 测试示例 if __name__ == "__main__": sample_points = [ (0, 0, 0), (0.1, 0.1, 0.1), (10, 10, 10), (10.2, 10.3, 10.1), (20, 20, 20) ] threshold = 1.0 groups, ungrouped = group_3d_points_np(sample_points, threshold) print("有效分组:") for i, group in enumerate(groups): print(f"组{i+1}: {group}") print(f"未分组点:{ungrouped}")
说明
- 纯Python版本无需额外依赖,逻辑直观,适合快速理解
- Numpy版本利用批量运算,处理几千个点的速度完全够用,代码更简洁
- 通过
single_point_as_ungrouped参数可以切换是否将单个点视为未分组
内容的提问来源于stack exchange,提问作者Jules
相关产品推荐
相关产品推荐

