Ich muss 3D Bspline-Kurven in Python berechnen. Ich schaute in scipy.interpolate.splprep und einige andere scipy Module, aber konnte nichts finden, das bereitwillig mir gab, was ich brauchte. Also habe ich mein eigenes Modul geschrieben. Der Code funktioniert gut, aber er ist langsam (die Testfunktion läuft in 0.03s, was sehr viel ist, wenn man bedenkt, dass ich nur 100 Samples mit 6 Kontrollknoten benötige).Schneller B-Spline-Algorithmus mit numpy/scipy
Gibt es eine Möglichkeit, den unten stehenden Code mit ein paar Scipy-Modulaufrufen zu vereinfachen, was vermutlich die Geschwindigkeit erhöhen würde? Und wenn nicht, was könnte ich mit meinem Code tun, um seine Leistung zu verbessern?
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)
Die beiden Bilder unten zeigt, was mit meinem Code gibt sowohl geschlossenen Bedingungen:
Awesome, vielen Dank! Funktioniert einwandfrei in meiner Anwendung, wo ich zwei Ende 3D-Koordinaten und eine Reihe von bekannten 3D-Kontrollpunkten habe. Es zeichnet den Spline außerordentlich gut! BRAVO!!! Ich arbeite mit NDarrays von 3D-Bilddaten. – kabammi
Großartig!Sie haben mich aufgefordert, meine Antwort zu bearbeiten und die for-Schleife am nicht benötigten Ende zu entfernen. Ich habe auch am Ende ein Addendum gemacht, um die offizielle BSpline-Funktion zu erwähnen, die in scipy 0.19.0 – Fnord
hinzugefügt wurde. Hmmm ... Ich habe Fehler mit Ihrer scipy_bspline-Funktion. Ich gebe eine Liste als Lebenslauf, also war cv = np.asarray (cv) in Ihrer ursprünglichen Funktion hilfreich. Dann benutze ich degree = 5 und die neue Funktion wirft einen Fehler und sagt mir, dass ich mindestens 12 Knoten brauche ... der alte Code war mir egal und funktionierte einfach. So gewinnt der alte Code für mich. :) – kabammi