如何从 scipy.interpolate.BSpline 中提取 BSpline 基础

Fno*_*ord 7 python numpy scipy

这个问题中,我向社区询问如何计算样条线基础。我的目标是通过预先计算 ascipy.interpolate.splev来更快地计算样条线,并通过点积生成曲线。splevbspline basisbasiscontrol point

从那时起,一个新的scipy.interpolate.BSpline插值器被添加到scipy. 它带有一个basis_elementfunction,我认为该函数可用于返回用于计算样条线的基础。

例如,使用此处的代码和以下输入:

import numpy as np

# Control points
cv = np.array([[ 50.,  25., 0.],
       [ 59.,  12., 0.],
       [ 50.,  10., 0.],
       [ 57.,   2., 0.],
       [ 40.,   4., 0.],
       [ 40.,   14., 0.]])

kv = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3] # knot vector
n = 10  # 10 samples (keeping it simple)
degree = 3 # Curve degree
Run Code Online (Sandbox Code Playgroud)

我可以计算以下 bspline 基础:

[[ 1.          0.          0.          0.          0.          0.        ]
 [ 0.2962963   0.56481481  0.13271605  0.00617284  0.          0.        ]
 [ 0.03703704  0.51851852  0.39506173  0.04938272  0.          0.        ]
 [ 0.          0.25        0.58333333  0.16666667  0.          0.        ]
 [ 0.          0.07407407  0.54938272  0.36728395  0.00925926  0.        ]
 [ 0.          0.00925926  0.36728395  0.54938272  0.07407407  0.        ]
 [ 0.          0.          0.16666667  0.58333333  0.25        0.        ]
 [ 0.          0.          0.04938272  0.39506173  0.51851852  0.03703704]
 [ 0.          0.          0.00617284  0.13271605  0.56481481  0.2962963 ]
 [ 0.          0.          0.          0.          0.          1.        ]]
Run Code Online (Sandbox Code Playgroud)

使用np.dotbasis返回control points曲线上的 10 个样本:

[[ 50.          25.           0.        ]
 [ 55.12654321  15.52469136   0.        ]
 [ 55.01234568  11.19753086   0.        ]
 [ 53.41666667   9.16666667   0.        ]
 [ 53.14506173   7.15432099   0.        ]
 [ 53.1882716    5.17901235   0.        ]
 [ 51.58333333   3.83333333   0.        ]
 [ 47.20987654   3.87654321   0.        ]
 [ 42.31790123   6.7345679    0.        ]
 [ 40.          14.           0.        ]]
Run Code Online (Sandbox Code Playgroud)

问题:是否可以将上述基础提取出来scipy.interpolate.BSpline

显然我一定用错了,因为当我尝试时我得到这样的东西:

from scipy.interpolate import BSpline
b = BSpline.basis_element(kv)
print b(np.linspace(kv[0],kv[-1],n)) # i'm not sure what these values represent
[ 0.          0.00256299  0.04495618  0.16555213  0.28691315  0.28691315
  0.16555213  0.04495618  0.00256299  0.        ]
Run Code Online (Sandbox Code Playgroud)

ev-*_*-br 4

BSpline.basis_element内部结作为其论据。

在您的示例中,您填充了结,但这并没有达到您的预期:

In [3]: t = [0, 0, 0, 0, 1, 2, 3, 3, 3, 3]

In [4]: b = BSpline.basis_element(t)

In [5]: b.k
Out[5]: 8
Run Code Online (Sandbox Code Playgroud)

所以它是一个八阶样条线。

如果你想要二次样条,你会这样做

In [7]: b1 = BSpline.basis_element([0, 1, 2, 3])

In [8]: b1.k
Out[8]: 2

In [9]: b1.t
Out[9]: array([-1., -1.,  0.,  1.,  2.,  3.,  4.,  4.])
Run Code Online (Sandbox Code Playgroud)

使困惑?方法非常简单:https://github.com/scipy/scipy/blob/v0.19.1/scipy/interpolate/_bsplines.py#L243-L302

返回的可调用BSpline.basis_element实际上是一个 b 样条函数。使用数组参数调用它的结果相当于直接BSpline在循环中为数组的每个元素运行文档字符串中的示例代码,https://docs.scipy.org/doc/scipy/reference/ generated/scipy .interpolate.BSpline.html

编辑:如果您正在寻找计算给定点的所有非零样条的 Cox-de Boor 算法的变体,那么您可以查看一个_bspl.evaluate_all_bsplines函数, https: //github.com/scipy/scipy/blob/v0 .19.1/scipy/interpolate/_bspl.pyx#L161 (它本身只是 C 例程的包装,它完成所有繁重的工作;请注意,很难在性能方面击败后一个例程。)

但是,它不是公共函数,因此不保证在未来版本中可用。如果您对它有很好的用途,并且对面向用户的 API 有建议,请将讨论转移到 scipy bug 跟踪器。