【发布时间】:2017-10-27 21:11:40
【问题描述】:
我需要构建一个 3D B-spline 表面并在各种参数坐标下对其进行多次采样。我找到的最接近的解决方案是使用bisplev,它期望tck 输入由bsplprep 计算。不幸的是,我不能使用 tck 组件,因为它会产生一个通过控制点的表面,而我想要的是在 B-spline basis 中计算的表面。所以我手动构造了tck 输入bsplev 可以用来产生所需的表面。
不幸的是,如果不使用 2 个嵌套循环,我无法弄清楚如何做到这一点:每个 uv 查询一个,每个空间组件一个。后者是可以接受的,但前者在处理非常大的查询数组时非常慢。
代码如下:
import numpy as np
import scipy.interpolate as si
def bivariate_bspline(cv,u,v,uCount,vCount,uDegree,vDegree):
# cv = grid of control vertices
# u,v = list of u,v component queries
# uCount, vCount = number of control points along the u and v directions
# uDegree, vDegree = curve degree along the u and v directions
uMax = uCount-uDegree # Max u parameter
vMax = vCount-vDegree # Max v parameter
# Calculate knot vectors for both u and v
u_kv = np.clip(np.arange(uCount+uDegree+1)-uDegree,0,uCount-uDegree) # knot vector in the u direction
v_kv = np.clip(np.arange(vCount+vDegree+1)-vDegree,0,vCount-vDegree) # knot vector in the v direction
# Compute queries
position = np.empty((u.shape[0], cv.shape[1]))
for i in xrange(cv.shape[1]):
tck = (u_kv, v_kv, cv[:,i], uDegree,vDegree)
for j in xrange(u.shape[0]):
position[j,i] = si.bisplev(u[j],v[j], tck)
return position
测试:
# A test grid of control vertices
cv = np.array([[-0.5 , -0. , 0.5 ],
[-0.5 , -0. , 0.33333333],
[-0.5 , -0. , 0. ],
[-0.5 , 0. , -0.33333333],
[-0.5 , 0. , -0.5 ],
[-0.16666667, 1. , 0.5 ],
[-0.16666667, -0. , 0.33333333],
[-0.16666667, 0.5 , 0. ],
[-0.16666667, 0.5 , -0.33333333],
[-0.16666667, 0. , -0.5 ],
[ 0.16666667, -0. , 0.5 ],
[ 0.16666667, -0. , 0.33333333],
[ 0.16666667, -0. , 0. ],
[ 0.16666667, 0. , -0.33333333],
[ 0.16666667, 0. , -0.5 ],
[ 0.5 , -0. , 0.5 ],
[ 0.5 , -0. , 0.33333333],
[ 0.5 , -0.5 , 0. ],
[ 0.5 , 0. , -0.33333333],
[ 0.5 , 0. , -0.5 ]])
uCount = 4
vCount = 5
uDegree = 3
vDegree = 3
n = 10**4 # make 10k random queries
u = np.random.random(n) * (uCount-uDegree)
v = np.random.random(n) * (vCount-vDegree)
bivariate_bspline(cv,u,v,uCount,vCount,uDegree,vDegree) # will return n correct samples on a b-spline basis surface
速度测试:
import cProfile
cProfile.run('bivariate_bspline(cv,u,v,uCount,vCount,uDegree,vDegree)') # 0.929 seconds
因此,对于 10k 个样本,将近 1 秒,其中 bisplev 调用占用了大部分计算时间,因为每个空间组件都调用了 10k 次。
我确实尝试用一个 bisplev 调用替换 for j in xrange(u.shape[0]): 循环,一次性给它 u 和 v 数组,但这会在 scipy\interpolate\_fitpack_impl.py", line 1048, in bisplev 引发 ValueError: Invalid input data。
问题
有没有办法摆脱这两者,或者至少摆脱 uv 查询循环并在单个矢量化操作中执行所有 uv 查询?
【问题讨论】:
-
如果您尝试
si.bisplev(u, v, tck),会出现什么问题?bisplev方法应该接受数组。 -
@Desire 它在
scipy\interpolate\_fitpack_impl.py", line 1048, in bisplev raise ValueError("Invalid input data")引发ValueError("Invalid input data")