这可能很明显,但是如果您能够猜出每个数据点对应的 uv 坐标(最简单的情况u=x
,v=y
如果表面是图形),参数插值(u,v) -> (x,y,z)
本质上是 3 个独立数据集(x、y、和 z 坐标),因此您可以使用任何常用的二维插值方法。
splprep
实际上是这样工作的,假设点是有序的,并u
根据u[i] = u[i-1] + dist(p[i], p[j])
使用欧几里得距离分配坐标。如果您知道哪些点“彼此相邻”,这可以推广到二维。例如,如果x,y,z
数据以二维数组的形式出现,您可以这样做
from scipy import interpolate
import numpy as np
# example dataset (wavy cylinder)
def surf(u, v):
x = np.cos(v*np.pi*2) * (1 + 0.3*np.cos(30*u))
y = np.sin(v*np.pi*2) * (1 + 0.3*np.cos(30*u))
z = 2*u
return x, y, z
ux, vx = np.meshgrid(np.linspace(0, 1, 20),
np.linspace(0, 1, 20))
x, y, z = surf(ux, vx)
# reconstruct (u, v) using the existing (!) neighbourhood information
du = np.sqrt(np.diff(x, axis=0)**2 + np.diff(y, axis=0)**2 + np.diff(z, axis=0)**2)
dv = np.sqrt(np.diff(x, axis=1)**2 + np.diff(y, axis=1)**2 + np.diff(z, axis=1)**2)
u = np.zeros_like(x)
v = np.zeros_like(x)
u[1:,:] = np.cumsum(du, axis=0)
v[:,1:] = np.cumsum(dv, axis=1)
u /= u.max(axis=0)[None,:] # hmm..., or maybe skip this scaling step -- may distort the result
v /= v.max(axis=1)[:,None]
# construct interpolant (unstructured grid)
ip_surf = interpolate.CloughTocher2DInterpolator(
(u.ravel(), v.ravel()),
np.c_[x.ravel(), y.ravel(), z.ravel()])
# the BivariateSpline classes might also work here, but the above is more robust
# plot projections
import matplotlib.pyplot as plt
u = np.random.rand(2000)
v = np.random.rand(2000)
plt.subplot(131)
plt.plot(ip_surf(u, v)[:,0], ip_surf(u, v)[:,1], '.')
plt.title('xy')
plt.subplot(132)
plt.plot(ip_surf(u, v)[:,1], ip_surf(u, v)[:,2], '.')
plt.title('yz')
plt.subplot(133)
plt.plot(ip_surf(u, v)[:,2], ip_surf(u, v)[:,0], '.')
plt.title('zx')
plt.show()
编辑:好的,我不完全确定上述计算u,v
在实践中有多稳健,因为它似乎有失真的空间。但是,下面的 LocallyLinearEmbedding 在这方面可能会更好。
如果您无法猜测这些u,v
值,例如您只有一堆点而没有邻域信息,那么问题就会变得更加困难。这里合适的关键词似乎是“表面重建”和“流形学习”。
我没有尝试,但在我看来,您可以使用scikits-learn轻松获得合适的u,v
坐标,请参阅此示例。他们有一堆不同的算法,这似乎足够可靠。然后,您可以将结果用于非结构化二维插值方法,如上所示。LocallyLinearEmbedding
u = Y[:,0]; v = Y[:,1]
也许谷歌搜索更多会发现更多的包裹。