Python 在B样条基上查询二元样条上的多个点

Python 在B样条基上查询二元样条上的多个点,python,numpy,scipy,Python,Numpy,Scipy,我需要构造一个3DB样条曲面,并在不同的参数坐标下多次采样。我找到的最接近的解决方案是使用,它需要一个由计算得出的tck输入。不幸的是,我不能使用tck组件,因为它生成了一个通过控制点的曲面,而我想要的是在B样条曲线基础上计算的曲面。因此,我手动构建tck输入bsplev可以用来生成所需曲面 不幸的是,如果不使用两个嵌套循环,我就无法理解如何做到这一点:每个uv查询一个,每个空间组件一个。后者是可以接受的,但前者在处理非常大的查询数组时速度非常慢 代码如下: import numpy as np

我需要构造一个3D
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]