简体   繁体   English

测试共面点,并比较多组点的最佳平面拟合?

[英]Test for coplanar points, and comparing best planar fit of many sets of points?

Perhaps best asked in three parts:也许最好分三个部分问:

  1. Given five not necessarily coplanar points (in 3 dimensions), what is a good measure of how close to coplanar they are?给定五个不一定共面的点(在 3 维中),什么是衡量它们接近共面程度的好方法?

  2. Given another set of five not necessarily coplanar points, how can we assess which of these two sets of five points is “more coplanar”?给定另一组五个不一定共面的点,我们如何评估这两组五个点中的哪一个“更共面”?

  3. Given n sets of five not necessarily coplanar points, how can we order these sets of points from “most coplanar” to “least coplanar”?给定n组五个不一定共面的点,我们如何将这些点从“最共面”排序到“最不共面”?

Suggestions?建议?

I'm working with sets of five points at a time, but will eventually need to consider more points in these sets.我一次处理五个点,但最终需要在这些集合中考虑更多点。

Is this a well-formulated question?这是一个精心设计的问题吗? An algorithm would be helpful, especially if coded in Python.算法会很有帮助,特别是如果用 Python 编码。

I would start with 3D OBB and try to use its dimensions as metrics m .我将从3D OBB开始,并尝试将其尺寸用作指标m Let a,b,c be the sides of the OBB then for example I would try this:a,b,c成为OBB的两侧,然后例如我会试试这个:

V = a*b*c             // volume
d = min(a,b,c)        // thickness
S = a*b*c/min(a,b,c)  // area
  = V/d
m = d/S               // cop-lanarity metrics
  = d/(V/d)
  = d^2/V

this will lead to m in range <0 , +inf> where 0 means co-planar however the result will be non linear and maybe you should normalize the result by dividing it with V so you can compare between different PCL s这将导致m<0 , +inf>范围内,其中0表示共面,但是结果将是非线性的,也许您应该通过将结果除以V来标准化结果,以便您可以在不同的PCL之间进行比较

If you want something linear you can try angle of side and diagonal chose the side with smallest and not biggest side lengths:如果你想要线性的东西,你可以尝试边角和对角线选择边长最小而不是最大的边:

对角线

m = atan( min(a,b,c) / ( a*b*c / (min(a,b,c)*max(a,b,c)) ) )
    atan( min(a,b,c)^2 * max(a,b,c) / (a*b*c) )

this will lead to angle in range <0deg , 45deg> where 0deg means co-planar.这将导致<0deg , 45deg>范围内的角度,其中0deg表示共面。 If you want to have something more precise I would add also the other side angle and combine them somehow for example like this:如果您想要更精确的东西,我还会添加另一个侧角并以某种方式将它们组合起来,例如:

对角线

m0 = atan( min(a,b,c)^2 * max(a,b,c) / (a*b*c) ) 
m1 = atan( min(a,b,c) / max(a,b,c) )  
m =  0.5*(m0+m1)

If you sort the sides so a<=b<=c then you can rewrite to:如果你对边进行排序a<=b<=c那么你可以重写为:

m0 = atan(a/b) 
m1 = atan(a/c)  
m =  0.5*(m0+m1)

I would use a simpler approach:我会使用更简单的方法:

  1. Given your points, compute the best-fit plane.给定你的观点,计算最适合的平面。
  2. Compute the point-plane distances.计算点平面距离。
  3. Compute a metric based on the distances above to measure the quality of the fitting.根据上述距离计算一个度量来衡量拟合的质量。

So, here is the code in Python (for the best-fit plane computation I use the scikit-spatial library):所以,这里是 Python 中的代码(为了最适合的平面计算,我使用scikit-spatial库):

Import libraries:导入库:

import numpy as np
import matplotlib.pyplot as plt

from skspatial.objects import Plane, Points

Load the points (for the sake of simplicity I have just hardcoded them here, but you will get them from an external source):加载这些点(为了简单起见,我只是在这里对它们进行了硬编码,但您将从外部来源获取它们):

points = Points([[2, 0, -1], [1, 0, 0], [0, 4, -2], [6, -2, 5], [-2, -7, 5]])

Compute the best-fit plane:计算最佳拟合平面:

best_fit_plane = Plane.best_fit(points)

Compute the point-plane distances:计算点平面距离:

distances = [best_fit_plane.distance_point(point) for point in points]

Compute a metric to measure the quality of the fitting (eg, a RMSE):计算一个度量来衡量拟合的质量(例如,RMSE):

error = np.sqrt(np.dot(distances, distances) / len(distances))

Now, going back to three questions:现在,回到三个问题:

  1. Use the error metric.使用error度量。
  2. Use the error as a comparison metric.使用error作为比较指标。
  3. Use the distances.使用距离。

The Points class has an are_coplanar method. Points类有一个are_coplanar方法。 So, before doing the computation above, check if the points are coplanar in the first place:因此,在进行上述计算之前,首先检查点是否共面:

points.are_coplanar()

If you calculate the singular value decomposition (SVD) of the point matrix, you get the semi-axes of an ellipsoid that approximates the shape of the point distribution.如果您计算点矩阵的奇异值分解 (SVD),您会得到近似点分布形状的椭圆体的半轴。

If the point array has a point per row:如果点数组每行有一个点:

points = np.array([(0,0,0), (1,0,1), (0,1,0), (2,0,2), (1,1,1)])

centroid = np.mean(points, axis=0)
_, magnitudes, axes = np.linalg.svd(points - centroid, full_matrices=False)

axes is an array containing the three unitary axes of the ellipsoid, normal to each other. axes是一个数组,包含椭圆体的三个单一轴,彼此垂直。 And magnitudes is a vector of non-negative numbers that represent the magninude of each axis. magnitudes是代表每个轴的幅度的非负数向量。 Both are conveniently sorted from high to low magnitude.两者都方便地从高到低排序。

The axis of minimum magnitude is normal to the best fitting plane.最小幅度的轴垂直于最佳拟合平面。 Along with the centroid you get the plane equation:除了centroid ,您还可以得到平面方程:

>>> normal = axes[2]
>>> normal
array([-7.07106781e-01,  1.11022302e-16,  7.07106781e-01])
>>> centroid
array([0.8, 0.4, 0.8])

The magnitude of the last axis is a measure of coplanarity, where zero represents a perfect plane fit.最后一个轴的大小是共面性的度量,其中零表示完美的平面拟合。 In this example, the fit is perfect:在这个例子中,拟合是完美的:

>>> dispersion = magnitudes[2]
>>> dispersion
1.5265928729081877e-16

You can use the dispersion value to rank point sets by coplanarity.您可以使用dispersion值按共面性对点集进行排序。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM