On this post,we will enumerate and compare drawing vs interpolating a B-spline curves
Requirements
Things you'll need:
- Python 2.7.x or 3.x.x,
- Numpy
- Scipy
- Matplotlib
Getting hands dirty
Assuming you already know a little about B-spline curves, if not just google about it or go here ^^.
Let consider a 9 points list named plist :
plist = [(3 , 1), (2.5, 4), (0, 1), (-2.5, 4),(-3, 0), (-2.5, -4), (0, -1), (2.5, -4), (3, -1),]
We will do two things :
A. Drawing a cubic B-Spline curve where plist is the control polygon. B. Find(interpolate) and draw the B-spline curve that go trough plist points and or in other words a curve fitting using a cubic B-spline curve.
As we will work with Numpy , let's create a numpy array named ctr form plist a split it to x and y arrays.
ctr =np.array(plist)
x=ctr[:,0]
y=ctr[:,1]
A. Drawing the B-spline Curve
We will draw a cubic B-spline which degree k=3 as it's the most used one. We need now to define the knots vector, with k ending equal knots:
l=len(x)
t=np.linspace(0,1,l-2,endpoint=True)
t=np.append([0,0,0],t)
t=np.append(t,[1,1,1])
Now we have defined all requirement to draw it. we can construct a sequence of length 3 containing the knots, coefficients, and degree of the spline to pass it as the tck argument to scipy.interpolate.splev , the function that will evaluate our curve:
tck=[t,[x,y],3]
And as we will evaluate the B-spline curve, we need a second parameter__u__ , an array of points :
u3=np.linspace(0,1,(max(l*2,70)),endpoint=True)
And we evaluate it :
out = interpolate.splev(u3,tck)
Drawing it using matplotlib :
With this code :
plt.plot(x,y,'k--',label='Control polygon',marker='o',markerfacecolor='red')
plt.plot(out[0],out[1],'b',linewidth=2.0,label='B-spline curve')
plt.legend(loc='best')
plt.axis([min(x)-1, max(x)+1, min(y)-1, max(y)+1])
plt.title('Cubic B-spline curve evaluation')
plt.show()
B. interpolate the B-spline Curve
We will interpolate now the B-spline cruve that should go through n points. As we done before, a numpy array must be created using plist and split into x and y arrays :
plist = [(3 , 1), (2.5, 4), (0, 1), (-2.5, 4),(-3, 0), (-2.5, -4), (0, -1), (2.5, -4), (3, -1),]
ctr =np.array(plist)
x=ctr[:,0]
y=ctr[:,1]
To interpolate the B-spline that go through this points. To do so, we will be using scipy.interpolate.splprep, to get the interpolated S-pline parameters :
u,tck=interpolate.splprep([x,y],k=3,s=0)
And we use them to evaluate it using scipy.interpolate.splev, we still have a to redefine u variable to get a clear plot :
u=np.linspace(0,1,num=50,endpoint=True)
out = interpolate.splev(u,tck)
and we finaly draw it :
With this code :
plt.figure()
plt.plot(x, y, 'ro', out[0], out[1], 'b')
plt.legend(['Points', 'Interpolated B-spline', 'True'],loc='best')
plt.axis([min(x)-1, max(x)+1, min(y)-1, max(y)+1])
plt.title('B-Spline interpolation')
plt.show()
Full code :
B-Spline evalutation
import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
ctr =np.array( [(3 , 1), (2.5, 4), (0, 1), (-2.5, 4),
(-3, 0), (-2.5, -4), (0, -1), (2.5, -4), (3, -1),])
x=ctr[:,0]
y=ctr[:,1]
# uncomment both lines for a closed curve
#x=np.append(x,[x[0]])
#y=np.append(y,[y[0]])
l=len(x)
t=np.linspace(0,1,l-2,endpoint=True)
t=np.append([0,0,0],t)
t=np.append(t,[1,1,1])
tck=[t,[x,y],3]
u3=np.linspace(0,1,(max(l*2,70)),endpoint=True)
out = interpolate.splev(u3,tck)
plt.plot(x,y,'k--',label='Control polygon',marker='o',markerfacecolor='red')
#plt.plot(x,y,'ro',label='Control points only')
plt.plot(out[0],out[1],'b',linewidth=2.0,label='B-spline curve')
plt.legend(loc='best')
plt.axis([min(x)-1, max(x)+1, min(y)-1, max(y)+1])
plt.title('Cubic B-spline curve evaluation')
plt.show()
B-Spline interpolation
import numpy as np
from scipy import interpolate
import matplotlib.pyplot as plt
#x = np.arange(0, 2*np.pi+np.pi/4, 2*np.pi/8)
#y = np.sin(x)
ctr =np.array( [(3 , 1), (2.5, 4), (0, 1), (-2.5, 4),
(-3, 0), (-2.5, -4), (0, -1), (2.5, -4), (3, -1)])
x=ctr[:,0]
y=ctr[:,1]
#x=np.append(x,x[0])
#y=np.append(y,y[0])
tck,u = interpolate.splprep([x,y],k=3,s=0)
u=np.linspace(0,1,num=50,endpoint=True)
out = interpolate.splev(u,tck)
plt.figure()
plt.plot(x, y, 'ro', out[0], out[1], 'b')
plt.legend(['Points', 'Interpolated B-spline', 'True'],loc='best')
plt.axis([min(x)-1, max(x)+1, min(y)-1, max(y)+1])
plt.title('B-Spline interpolation')
plt.show()
Thanks to give your feedback in a comment and help me improve this article.
Comments
comments powered by Disqus