19

次のようなことをしようとしています(wikipediaから抽出した画像)

スプライン

#!/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()

コードの最初の部分は、メイン リファレンスから抽出されたコードですが、ポイントをコントロール ノットとして使用する方法については説明されていません。

このコードの結果は次の画像です。

ここに画像の説明を入力

ポイントはサンプルで、青い線はすべてのポイントを考慮したスプラインです。そして、赤い線は私にとってはうまくいかないものです. すべての中間点を制御ノットとして考慮しようとしていますが、できません。使おうとしてもknots=x[1:-1]、うまくいかない。助けていただければ幸いです。

要するに質問:スプライン関数ですべての中間点を制御ノットとして使用するにはどうすればよいですか?

注: この最後の画像はまさに私が必要としているものであり、私が持っているもの (すべてのポイントを渡すスプライン) と必要なもの (コントロール ノットを持つスプライン) の違いです。何か案は? ここに画像の説明を入力

4

5 に答える 5

16

bsplineを評価したい場合は、スプラインに適したノット ベクトルを見つけてから、必要に応じて手動で再構築tckする必要があります。

tckは、ノットt+ 係数c+ 曲線度 を表しkます。指定された制御点を通過する 3 次曲線をsplrep計算します。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

試して:

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()

結果:

さまざまな角度の開いたスプライン

于 2016-09-01T04:48:36.227 に答える
7

この IPython Notebook http://nbviewer.ipython.org/github/empet/geom_modeling/blob/master/FP-Bezier-Bspline.ipynbでは、B スプライン曲線の生成に関連するデータの詳細な説明も見つけることができます。 de Boor アルゴリズムの Python 実装として。

于 2015-02-17T18:03:13.870 に答える
2

このリンクのベジエで必要な答えで、本当に興味深いものを見つけました。次に、コードを使用して自分で試しました。どうやら正常に動作しています。これは私の実装です:

#! /usr/bin/python
# -*- coding: utf-8 -*-
import numpy as np
import matplotlib.pyplot as plt
from scipy.special import binom

def Bernstein(n, k):
    """Bernstein polynomial.

    """
    coeff = binom(n, k)

    def _bpoly(x):
        return coeff * x ** k * (1 - x) ** (n - k)

    return _bpoly


def Bezier(points, num=200):
    """Build Bézier curve from points.

    """
    N = len(points)
    t = np.linspace(0, 1, num=num)
    curve = np.zeros((num, 2))
    for ii in range(N):
        curve += np.outer(Bernstein(N - 1, ii)(t), points[ii])
    return curve
xp = np.array([2,3,4,5])
yp = np.array([2,1,4,0])
x, y = Bezier(list(zip(xp, yp))).T

plt.plot(x,y)
plt.plot(xp,yp,"ro")
plt.plot(xp,yp,"b--")

plt.show()

そして例の画像。 ベジエの実装

赤い点はコントロール ポイントを表します。それだけです=)

于 2015-02-15T21:18:27.657 に答える
1

問題はノットベクトルに関係していると思います。選択したノットが多すぎると問題が発生するようです。ノット間にデータ ポイントが必要です。この質問は、scipy.insterpolate の splrep 関数でノットを選択する際の問題のバグ (?) を解決します

#!/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)
print tck
x2 = np.linspace(0, 10, 200)
y2 = interpolate.splev(x2, tck)

# spline with all the middle points as knots (not working yet)
knots = np.asarray(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
nknots = 5
idx_knots = (np.arange(1,len(x)-1,(len(x)-2)/np.double(nknots))).astype('int')
knots = x[idx_knots]
print knots

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()

5 ノットを選択するとうまくいくようです。

于 2015-02-14T19:10:41.580 に答える