使用Python的样条线(使用控制结和端点)

sil*_*gon 14 python math numpy spline cubic-spline

我正在尝试执行以下操作(从维基百科中提取的图像)

仿样

#!/usr/bin/env python
from scipy import interpolate
import numpy as np
import matplotlib.pyplot as plt

# sampling
x = np.linspace(0, 10, 10)
y = np.sin(x)

# spline trough all the sampled points
tck = interpolate.splrep(x, y)
x2 = np.linspace(0, 10, 200)
y2 = interpolate.splev(x2, tck)

# spline with all the middle points as knots (not working yet)
# knots = x[1:-1]  # it should be something like this
knots = np.array([x[1]])  # not working with above line and just seeing what this line does
weights = np.concatenate(([1],np.ones(x.shape[0]-2)*.01,[1]))
tck = interpolate.splrep(x, y, t=knots, w=weights)
x3 = np.linspace(0, 10, 200)
y3 = interpolate.splev(x2, tck)

# plot
plt.plot(x, y, 'go', x2, y2, 'b', x3, y3,'r')
plt.show()
Run Code Online (Sandbox Code Playgroud)

代码的第一部分是从主参考中提取的代码,但没有解释如何将这些点用作控制结.

此代码的结果如下图所示.

在此输入图像描述

点是样本,蓝线是考虑所有点的样条.而红线是不适合我的那条线.我试图将所有中间点都考虑为控制结,但我不能.如果我尝试使用knots=x[1:-1]它只是不起作用.我很感激任何帮助.

简而言之:如何在样条函数中使用所有中间点作为控制结?

注意:最后一张图像正是我需要的,它是我所拥有的(样条通过所有点)和我需要的(带有控制结的样条)之间的区别.有任何想法吗? 在此输入图像描述

xec*_*afe 6

在这个IPython Notebook http://nbviewer.ipython.org/github/empet/geom_modeling/blob/master/FP-Bezier-Bspline.ipynb中,您可以找到生成B样条曲线所涉及的数据的详细描述.作为de Boor算法的Python实现.


Fno*_*ord 6

如果要评估bspline,则需要找出适合样条的结矢量,然后手动重建tck以适合您的需求。

tck代表节t+系数c+曲线度ksplrep计算tck通过给定控制点的三次曲线。因此,您无法将其用于所需的内容。

下面的功能将向您展示我针对一段时间前提出的类似问题的解决方案,适合您的需求。

有趣的事实:该代码适用于任何尺寸的曲线(1D,2D,3D,...,nD)

import numpy as np
import scipy.interpolate as si


def bspline(cv, n=100, degree=3):
    """ Calculate n samples on a bspline

        cv :      Array ov control vertices
        n  :      Number of samples to return
        degree:   Curve degree
    """
    cv = np.asarray(cv)
    count = cv.shape[0]

    # Prevent degree from exceeding count-1, otherwise splev will crash
    degree = np.clip(degree,1,count-1)

    # Calculate knot vector
    kv = np.array([0]*degree + range(count-degree+1) + [count-degree]*degree,dtype='int')

    # Calculate query range
    u = np.linspace(0,(count-degree),n)

    # Calculate result
    return np.array(si.splev(u, (kv,cv.T,degree))).T
Run Code Online (Sandbox Code Playgroud)

测试一下:

import matplotlib.pyplot as plt
colors = ('b', 'g', 'r', 'c', 'm', 'y', 'k')

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

plt.plot(cv[:,0],cv[:,1], 'o-', label='Control Points')

for d in range(1,5):
    p = bspline(cv,n=100,degree=d,periodic=True)
    x,y = p.T
    plt.plot(x,y,'k-',label='Degree %s'%d,color=colors[d%len(colors)])

plt.minorticks_on()
plt.legend()
plt.xlabel('x')
plt.ylabel('y')
plt.xlim(35, 70)
plt.ylim(0, 30)
plt.gca().set_aspect('equal', adjustable='box')
plt.show()
Run Code Online (Sandbox Code Playgroud)

结果:

不同程度的开放样条


sil*_*gon 3

我刚刚在这个链接中找到了一些非常有趣的答案,我需要 ab\xc3\xa9zier 。然后我就用代码自己尝试了一下。显然它运行良好。这是我的实现:

\n
#! /usr/bin/python\n# -*- coding: utf-8 -*-\nimport numpy as np\nimport matplotlib.pyplot as plt\nfrom scipy.special import binom\n\ndef Bernstein(n, k):\n    """Bernstein polynomial.\n\n    """\n    coeff = binom(n, k)\n\n    def _bpoly(x):\n        return coeff * x ** k * (1 - x) ** (n - k)\n\n    return _bpoly\n\n\ndef Bezier(points, num=200):\n    """Build B\xc3\xa9zier curve from points.\n\n    """\n    N = len(points)\n    t = np.linspace(0, 1, num=num)\n    curve = np.zeros((num, 2))\n    for ii in range(N):\n        curve += np.outer(Bernstein(N - 1, ii)(t), points[ii])\n    return curve\nxp = np.array([2,3,4,5])\nyp = np.array([2,1,4,0])\nx, y = Bezier(list(zip(xp, yp))).T\n\nplt.plot(x,y)\nplt.plot(xp,yp,"ro")\nplt.plot(xp,yp,"b--")\n\nplt.show()\n
Run Code Online (Sandbox Code Playgroud)\n

以及示例的图像。\nb\xc3\xa9zier 实现

\n

红点代表控制点。\n就是这样 =)

\n