我有 4 个点,它们非常接近一个平面 - 这是 1,4-二氢吡啶循环。
我需要计算 C3 和 N1 到由 C1-C2-C4-C5 构成的平面的距离。 计算距离还可以,但拟合平面对我来说很难。
1,4-DHP 循环:
1,4-DHP循环,另一种观点:
from array import *
from numpy import *
from scipy import *
# coordinates (XYZ) of C1, C2, C4 and C5
x = [0.274791784, -1.001679346, -1.851320839, 0.365840754]
y = [-1.155674199, -1.215133985, 0.053119249, 1.162878076]
z = [1.216239624, 0.764265677, 0.956099579, 1.198231236]
# plane equation Ax + By + Cz = D
# non-fitted plane
abcd = [0.506645455682, -0.185724560275, -1.43998120646, 1.37626378129]
# creating distance variable
distance = zeros(4, float)
# calculating distance from point to plane
for i in range(4):
distance[i] = (x[i]*abcd[0]+y[i]*abcd[1]+z[i]*abcd[2]+abcd[3])/sqrt(abcd[0]**2 + abcd[1]**2 + abcd[2]**2)
print distance
# calculating squares
squares = distance**2
print squares
如何使 sum(squares) 最小化?我尝试过最小二乘法,但这对我来说太难了。
最佳答案
这听起来不错,但您应该用 SVD 代替非线性优化。下面创建惯性张量 M,然后使用 SVD 得到平面的法线。这应该是最小二乘拟合的近似值,并且速度更快,更可预测。它返回点云中心和法线。
def planeFit(points):
"""
p, n = planeFit(points)
Given an array, points, of shape (d,...)
representing points in d-dimensional space,
fit an d-dimensional plane to the points.
Return a point, p, on the plane (the point-cloud centroid),
and the normal, n.
"""
import numpy as np
from numpy.linalg import svd
points = np.reshape(points, (np.shape(points)[0], -1)) # Collapse trialing dimensions
assert points.shape[0] <= points.shape[1], "There are only {} points in {} dimensions.".format(points.shape[1], points.shape[0])
ctr = points.mean(axis=1)
x = points - ctr[:,np.newaxis]
M = np.dot(x, x.T) # Could also use np.cov(x) here.
return ctr, svd(M)[0][:,-1]
例如:在 (10, 100) 处构造一个二维云,它在 x 方向上很薄,在 y 方向上大 100 倍:
>>> pts = np.diag((.1, 10)).dot(randn(2,1000)) + np.reshape((10, 100),(2,-1))
拟合平面非常接近 (10, 100),法线非常接近 x 轴。
>>> planeFit(pts)
(array([ 10.00382471, 99.48404676]),
array([ 9.99999881e-01, 4.88824145e-04]))
关于python - 平面拟合到 4 个(或更多)XYZ 点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/12299540/