代码之家  ›  专栏  ›  技术社区  ›  insin

计算3D(或n-D)质心的最佳方法是什么?

  •  29
  • insin  · 技术社区  · 17 年前

    作为工作项目的一部分,我必须计算3D空间中一组点的质心。现在,我以一种看似简单但幼稚的方式做这件事——取每组点的平均值,如:

    centroid = average(x), average(y), average(z)
    

    哪里 x , y z 是浮点数数组。我似乎记得有一种方法可以获得更准确的质心,但我还没有找到一个简单的算法。有人有什么想法或建议吗?我使用Python来实现这一点,但我可以改编其他语言的示例。

    9 回复  |  直到 17 年前
        1
  •  6
  •   Chris    10 年前

    与这里常见的说法相反,有不同的方法来定义(和计算)点云的中心。你已经提出了第一个也是最常见的解决方案,我会的 认为这有什么不对:

    centroid = average(x), average(y), average(z)

    这里的“问题”是,它会根据你的点的分布“扭曲”你的中心点。例如,如果你假设你的所有点都在一个立方体或其他几何形状内,但它们中的大多数恰好位于上半部分,你的中心点也会朝那个方向移动。

    作为替代方案,您可以在每个维度中使用数学中间值(极值的平均值)来避免这种情况:

    middle = middle(x), middle(y), middle(z)

    当你不太关心点的数量,而是更关心全局边界框时,你可以使用它,因为这就是全部——围绕你的点的边界框的中心。

    最后,您还可以使用 median (中间的元素)在每个维度中:

    median = median(x), median(y), median(z)

    现在,这将与 middle 实际上,它可以帮助你忽略点云中的异常值,并找到一个中心点 基于 你的分数分布。

    找到“好”中心点的一种更稳健的方法可能是忽略每个维度的顶部和底部10%,然后计算 average 中值的 如您所见,您可以用不同的方式定义中心点。下面,我将向您展示2个二维点云的示例,并牢记这些建议。

    深蓝色点是平均(均值)质心。 中位数显示为绿色。 中间显示为红色。 在第二张图片中,您将看到我之前所说的内容:考虑到点云最极端的边界,绿点“更接近”点云最密集的部分,而红点离点云更远。

    enter image description here enter image description here

        2
  •  13
  •   deemer    17 年前

    不,这是点集合质心的唯一公式。请参阅维基百科: http://en.wikipedia.org/wiki/Centroid

        3
  •  11
  •   AlejoHausner    17 年前

    你含糊地提到“一种获得更精确质心的方法”。也许你在谈论一个不受异常值影响的质心。例如 平均的 美国的家庭收入可能很高,因为少数 非常 富人扭曲了平均水平;他们是“异类”。因此,统计学家使用 中值的 相反。获得中值的一种方法是对值进行排序,然后从列表的中间位置选择值。

    也许你正在寻找这样的东西,但对于2D或3D点。问题是,在2D和更高版本中,你无法排序。没有自然顺序。然而,有一些方法可以消除异常值。

    一种方法是找到 convex hull 的点。凸包的所有点都在点集的“外侧”。如果你这样做,并抛出船体上的点,你将抛出异常值,剩下的点将给出一个更具“代表性”的质心。你甚至可以重复这个过程几次,结果就像剥洋葱一样。事实上,这被称为“凸包剥离”。

        4
  •  3
  •   petr kodl    17 年前

    你可以使用增加精度求和——Kahan求和——这是你想要的吗?

        5
  •  2
  •   Gregg Lind    17 年前

    可能更有效:如果你要多次计算,你可以通过保持两个不变的变量来大大加快计算速度

    N  # number of points
    sums = dict(x=0,y=0,z=0)  # sums of the locations for each point
    

    然后每当创建或销毁点时,改变N并求和。这将计算从O(N)更改为O(1),但每次创建、移动或销毁一个点时都需要付出更多的工作。

        6
  •  0
  •   Sarien    17 年前

    一个“更精确的质心”我相信质心是按照你的计算方式定义的,因此不可能有“更准确的质心”。

        7
  •  0
  •   Jamie-Ryan    17 年前

    是的,这是正确的公式。

    如果你有很多点,你可以利用问题的对称性(无论是圆柱形、球形还是镜像)。否则,您可以借用统计数据并对随机数的点进行平均,只会有一点误差。

        8
  •  -1
  •   Dima    17 年前

    如果你 n维的 向量在列表中 [[a0,a1,…,an],[b0,b1,…,bn],[c0,c1,…,cn]] ,只需将列表转换为数组,然后按如下方式计算质心:

    import numpy as np
    
    vectors = np.array(Listv)
    centroid = np.mean(vectors, axis=0)