14

Python で bspline 曲線を計算する必要があります。scipy.interpolate.splprep と他のいくつかの scipy モジュールを調べましたが、必要なものをすぐに提供してくれるものは見つかりませんでした。そこで、以下に独自のモジュールを作成しました。コードは正常に動作しますが、遅いです (テスト関数は 0.03 秒で実行されます。これは、6 つのコントロール頂点で 100 サンプルしか要求していないことを考えると、かなりの時間のように思えます)。

いくつかの scipy モジュール呼び出しを使用して以下のコードを単純化する方法はありますか? そうでない場合、パフォーマンスを向上させるためにコードに何ができるでしょうか?

import numpy as np

# cv = np.array of 3d control vertices
# n = number of samples (default: 100)
# d = curve degree (default: cubic)
# closed = is the curve closed (periodic) or open? (default: open)
def bspline(cv, n=100, d=3, closed=False):

    # Create a range of u values
    count = len(cv)
    knots = None
    u = None
    if not closed:
        u = np.arange(0,n,dtype='float')/(n-1) * (count-d)
        knots = np.array([0]*d + range(count-d+1) + [count-d]*d,dtype='int')
    else:
        u = ((np.arange(0,n,dtype='float')/(n-1) * count) - (0.5 * (d-1))) % count # keep u=0 relative to 1st cv
        knots = np.arange(0-d,count+d+d-1,dtype='int')


    # Simple Cox - DeBoor recursion
    def coxDeBoor(u, k, d):

        # Test for end conditions
        if (d == 0):
            if (knots[k] <= u and u < knots[k+1]):
                return 1
            return 0

        Den1 = knots[k+d] - knots[k]
        Den2 = knots[k+d+1] - knots[k+1]
        Eq1  = 0;
        Eq2  = 0;

        if Den1 > 0:
            Eq1 = ((u-knots[k]) / Den1) * coxDeBoor(u,k,(d-1))
        if Den2 > 0:
            Eq2 = ((knots[k+d+1]-u) / Den2) * coxDeBoor(u,(k+1),(d-1))

        return Eq1 + Eq2


    # Sample the curve at each u value
    samples = np.zeros((n,3))
    for i in xrange(n):
        if not closed:
            if u[i] == count-d:
                samples[i] = np.array(cv[-1])
            else:
                for k in xrange(count):
                    samples[i] += coxDeBoor(u[i],k,d) * cv[k]

        else:
            for k in xrange(count+d):
                samples[i] += coxDeBoor(u[i],k,d) * cv[k%count]


    return samples




if __name__ == "__main__":
    import matplotlib.pyplot as plt
    def test(closed):
        cv = np.array([[ 50.,  25.,  -0.],
               [ 59.,  12.,  -0.],
               [ 50.,  10.,   0.],
               [ 57.,   2.,   0.],
               [ 40.,   4.,   0.],
               [ 40.,   14.,  -0.]])

        p = bspline(cv,closed=closed)
        x,y,z = p.T
        cv = cv.T
        plt.plot(cv[0],cv[1], 'o-', label='Control Points')
        plt.plot(x,y,'k-',label='Curve')
        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()

    test(False)

以下の 2 つの画像は、私のコードが両方の閉じた条件で返すものを示しています。 開いた曲線 閉曲線

4

2 に答える 2

1

データをプロファイリングせずに最適化のヒントを提供することは、暗闇での撮影に少し似ています。ただし、関数coxDeBoorは非常に頻繁に呼び出されるようです。ここから最適化を開始します。

Python での関数呼び出しは高価です。coxDeBoor過度の関数呼び出しを避けるために、再帰を反復に置き換えるようにしてください。これを行う方法に関する一般的な情報は、この質問への回答に記載されています。スタック/キューとして使用できますcollections.deque

于 2016-01-15T10:13:01.930 に答える