Python 在B样条基上查询二元样条上的多个点
我需要构造一个3DPython 在B样条基上查询二元样条上的多个点,python,numpy,scipy,Python,Numpy,Scipy,我需要构造一个3DB样条曲面,并在不同的参数坐标下多次采样。我找到的最接近的解决方案是使用,它需要一个由计算得出的tck输入。不幸的是,我不能使用tck组件,因为它生成了一个通过控制点的曲面,而我想要的是在B样条曲线基础上计算的曲面。因此,我手动构建tck输入bsplev可以用来生成所需曲面 不幸的是,如果不使用两个嵌套循环,我就无法理解如何做到这一点:每个uv查询一个,每个空间组件一个。后者是可以接受的,但前者在处理非常大的查询数组时速度非常慢 代码如下: import numpy as np
B样条曲面,并在不同的参数坐标下多次采样。我找到的最接近的解决方案是使用,它需要一个由计算得出的tck
输入。不幸的是,我不能使用tck
组件,因为它生成了一个通过控制点的曲面,而我想要的是在B样条曲线基础上计算的曲面。因此,我手动构建tck
输入bsplev
可以用来生成所需曲面
不幸的是,如果不使用两个嵌套循环,我就无法理解如何做到这一点:每个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
测试:
速度测试:
import cProfile
cProfile.run('bivariate_bspline(cv,u,v,uCount,vCount,uDegree,vDegree)') # 0.929 seconds
因此,对于10k个样本,调用bisplev几乎需要1秒的时间,bisplev
调用占用了大部分的计算时间,因为每个空间分量调用了10k次
我确实尝试用一个bisplev
调用替换xrange(u.shape[0])中j的:
循环,一次性给它u和v数组,但这会引起ValueError:在bisplev
中的scipy\interpolate\\u fitpack\u impl.py“,第1048行,输入数据无效
问题:
有没有办法摆脱这两种情况,或者至少取消uv
查询循环,在一个向量化操作中执行所有uv
查询?简短回答:替换
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)
与
解释
bisplev
确实接受数组为si.bisplev(u,v,tck)
,但它将它们解释为定义xy网格。因此,u
和v
必须按升序排序,并对所有对执行求值(u[j],v[k])
,输出是一个2D值数组。这不是您想要的;平方求值的数量可能不好,而且从返回的2D数组中提取您真正想要的值并不容易(它们不一定在对角线上,因为您的u,v不是从开始排序的)
但是包含一个布尔参数网格
,设置为False使其仅计算(u[j],v[j])
对处的样条曲线。向量u,v不再需要排序,但现在它们必须具有相同的大小
但是您正在准备自己的tck
。这提供了两种方法:用手工制作的tck实例化SmoothBivariateSpline
;或者读取源代码,并在参数grid
设置为False时执行它所做的操作。我使用了后一种方法。如果尝试si.bisplev(u,v,tck),会出现什么问题
?方法bisplev
应该接受数组。@希望它在bisplev raise ValueError(“无效输入数据”)中的scipy\interpolate\\u fitpack\u impl.py”第1048行引发ValueError(“无效输入数据”)
谢谢!!!巨大的性能改进!除非有办法消除每个空间维度的循环,否则这就是胜利!
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)
for i in xrange(cv.shape[1]):
position[:, i] = si.dfitpack.bispeu(u_kv, v_kv, cv[:,i], uDegree, vDegree, u, v)[0]