作为工作项目的一部分,我必须计算 3D 空间中一组点的质心。现在我正在以一种看似简单但幼稚的方式来做这件事——通过取每组点的平均值,如下所示:
centroid = average(x), average(y), average(z)
其中x
,y
和z
是浮点数数组。我似乎记得有一种方法可以获得更准确的质心,但我还没有找到一个简单的算法来做到这一点。有人有什么想法或建议吗?我为此使用 Python,但我可以改编其他语言的示例。
与这里的常见说法相反,有不同的方法来定义(和计算)点云的中心。您已经提出了第一个也是最常见的解决方案,我不会争辩这有什么问题:
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
or median
。如您所见,您可以用不同的方式定义中心点。下面我将向您展示 2 个 2D 点云的示例,并考虑到这些建议。
深蓝点是平均(平均)质心。中位数显示为绿色。中间显示为红色。在第二张图片中,您将看到我之前所说的:绿点“更接近”点云最密集的部分,而红点离它更远,考虑到最极端的边界。点云。
不,这是点集合质心的唯一公式。参见维基百科:http ://en.wikipedia.org/wiki/Centroid
您含糊地提到“一种获得更准确质心的方法”。也许您正在谈论不受异常值影响的质心。例如,美国的平均家庭收入可能非常高,因为少数非常富有的人扭曲了平均水平;他们是“异常值”。出于这个原因,统计学家改用中位数。获得中位数的一种方法是对值进行排序,然后在列表的中间选择值。
也许您正在寻找类似的东西,但对于 2D 或 3D 点。问题是,在 2D 及更高版本中,您无法排序。没有自然规律。然而,有一些方法可以消除异常值。
一种方法是找到点的凸包。凸包的所有点都在点集的“外部”。如果你这样做,并扔掉船体上的点,你将扔掉异常值,剩下的点将给出一个更具“代表性”的质心。你甚至可以多次重复这个过程,结果就像剥洋葱一样。实际上,它被称为“凸壳剥落”。
您可以使用提高准确度求和 - Kahan 求和 - 这就是您的想法吗?
可能更有效:如果您要多次计算,则可以通过保留两个常设变量来加快速度
N # number of points
sums = dict(x=0,y=0,z=0) # sums of the locations for each point
然后在创建或销毁点时更改 N 和总和。这会将计算的时间从 O(N) 更改为 O(1),但每次创建、移动或销毁一个点时都会花费更多的工作。
“更准确的质心”我相信质心是按照您计算它的方式定义的,因此不可能有“更准确的质心”。
是的,这是正确的公式。
如果您有大量点,您可以利用问题的对称性(无论是圆柱、球面还是镜面)。否则,您可以从统计数据中借用并平均随机数的点,而只会出现一些错误。
如果您的n 维向量在列表[[a0, a1, ..., an],[b0, b1, ..., bn],[c0, c1, ..., cn]]中,只需转换要数组的列表,然后像这样计算质心:
import numpy as np
vectors = np.array(Listv)
centroid = np.mean(vectors, axis=0)
你说对了。您正在计算的是质心或平均向量。