快速找到点云的 3D 边界

Quickly finding 3D bounds of point cloud

我有一个名为 Point 的 class,它保存每个点的 x、y 和 z 值。它还具有其他属性,例如“类别”字符串。

另一个名为 Map 的 class 在列表中保留对所有 Point 对象的引用。我目前有大约 150 个这样的 Point 对象。

地图 class 通过使用简单的范围数据class:

跟踪其所有点对象的 3D 范围
@dataclass
class Extents:
    min_x: int
    max_x: int
    min_y: int
    max_y: int
    min_z: int
    max_z: int

在我的 GUI 中(我通过 PySide6 使用 Qt),一个控件在按类别为所有点着色之间切换,这是非常快的(0.002 秒)和按 z 值着色,这足够慢单击控件时会很明显(0.2 秒)。

速度很慢,因为对于绘制的每个点对象,代码都会检查地图的最小和最大范围,以便将颜色输出缩放到所有点的当前 z 范围。

@property
def extents(self) -> Extents:
    if self.size == 0:
        return Extents(0, 0, 0, 0, 0, 0)
    else:
        return Extents(
            min(point.x for point in self.points),
            max(point.x for point in self.points),
            min(point.y for point in self.points),
            max(point.y for point in self.points),
            min(point.z for point in self.points),
            max(point.z for point in self.points)
        )

我考虑过将 Extents 缓存在一个实例变量中(在 Map 中)并仅在场景发生变化时修改它,但情况更糟,因为每当 GUI 中发生修改时,应用程序计算最小值和最大值。

我可以添加一个只检查 z 值的 属性。这应该会减少 60% 的时间,但我想知道是否有更好的方法。看起来这么简单的问题肯定已经处理过上千次了。

编辑:

不过,我仍然想知道最有效的方法是什么。有时我可能需要 150 多个对象。

第一个问题是,在上面的代码中,您实际上是在重新创建和遍历列表 6 次,而不是像这样一次性完成:

min_x,min_y,min_z,max_x,max_y,max_z=0,0,0,points[0].x, points[0].y,points[0].z
for point in points:
    max_x = point.x if point.x > max_x else max_x
    max_y = point.y if point.y > max_y else max_y
    max_z = point.z if point.z > max_z else max_z
    min_x = point.x if point.x < min_x else min_x
    min_y = point.y if point.y < min_y else min_y
    min_z = point.z if point.z < min_z else min_z

还有一些其他更好的方法可以解决这个问题。例如,如果你只想知道每个轴的 min/max 你可以只保留一个排序列表;或为 3 个轴中的每一个构建一维 KD 树。

综上所述,对一组 3d 点进行 min/max 搜索绝不会 运行 超过线性时间。