B-spline就是Basis Spline的简称:
术语B-spline一词,是由Isaac Jacob Schoenberg创造的。一个n阶的B-spline函数,是一个变量为x的n-1次分段多项式函数f(x)。分段函数之间,段与段之间的断点被称为knots。
B-spline的定义:

B-spline,可以看成是一系列控制点(Control points)和权重函数(Weight function)的线性组合,简而言之,就是每个控制点乘以自己对应的权重系数然后再求和,就能得到B-spline曲线在对应位置的值。控制点是我们后期指定的,而权重函数是我们预先定义好的,不会因为q的改变而改变。
权重函数(注意:以下只讨论权重函数N,不涉及控制点CP)
权重函数的定义:
函数的定义,可以参考Cox–de Boor的递归公式。对于给定的knots,当D=1时,一阶权重函数N可以定义为:

一阶权重函数的图像:

有了一阶B函数以后,其他所有D>1的高阶权重函数都是基于这一函数生成的递归表达式:

其中权重函数有如下特征:
1,是一个分段函数,其中,i表示第几段函数,D表示阶数。
2,如果函数的阶数为D,则每段函数都是一个D-1次多项式。
3,每段函数之间的断点,被称为knots,用非递减序列t0,t1,...tn表示,被称为knot vector。
4,一但knots确定了以后,那么每段函数之间的连续性等于D-2。
5,对每一段权重函数而言,他只在固定的一个区间内有值,其他地方都为0。这个区间就是u的定义域,他等于[~
),有些地方叫knot span,是一个半开半闭区间。(此处,对knot span的定义不一定严谨)
比如说,对于上述的一阶权重函数而言,阶数D=1,每段函数都是一个D-1=0阶多项式。对于第i段函数而言,u的定义区间为[
~
)。对于第0段函数
而言,他的knot span为[0,1),在[0,1)之间的函数值等于1,在这之外函数值都等于0。

为了简化上面所提到的这个高阶权重函数的定义,也为了简化计算,一般情况下,会把knot vector也就是函数之间的断点t0,t1,...tn,简化成一组非常递减的正整数。简而言之,就是把原来的t0,t1,...tn换成了0,1,...n。

为了更好的理解当D>1时的递归公式,我这里借用了一组别人的插图(见参考文献1)。
首先,让我们把目光放在图中三角形的最左上角的一个小三角形,,
和
,其中还有两条红线把
与
和
与
分别连接了起来。他所要表达的是,要想求出二阶函数
,我们需要先知道一阶函数
和
。也就是说,要想知道上图大三角形中左起第二列的所有二阶函数
,
,。。。
,必须先知道左起第一列的一阶函数
,
。。。
。依此类推,当我们要计算六阶函数
时,首先需要先知道五阶函数
和
,其次我们需要相应的所有四阶函数,三阶函数。。。直到一阶函数。
从公式的角度看也一样,根据简化后的公式,我们发现要想得到阶数为D的第i条曲线,比如说,需要先知道阶数为D-1的第i条曲线
和阶数为D-1的第i+1条曲线
。比D低一阶的两条基础曲线前面大括号内的值,实际上就是这两条曲线的权重。

下面我们逐一探讨一下,几个不同阶数的权重函数。我这里再次强调,我们到目前为止都没有讨论过控制点CP,而只讨论权重函数,目的是为了避免让大家混淆权重函数和控制点,这两个B-spline中最重要的概念。因为,B-spline可以说就是这两个概念的线性组合,因为,只有分别理解他们的各自的作用,才能更好的理解B-spline。
一阶权重函数:
首先,我们知道权重函数都有一个有效区间,也就是u的定义域,函数在定义域之外的值都是0。一阶函数,D=1,u=[i,i+1),有效区间为i+1。

这里我们统一以7个knots为例,knot vector list ={0,1,2,3,4,5,6},每段函数的knot span为1。对于第0段函数,也就是当i=0时,u的定义域为[0,1),函数
的断点knot为0,1。对于最后一段函数,也就是第5段函数,此时,i=5,u=[5,6),函数两端的端点knot为,5,6。注意,此时还没有用到递归函数。

一阶权重函数的图像:

Matlab code:

二阶权重函数:
二阶函数,D=2,u=[i,i+2),第i段函数的有效区间为i+2。 同样是7个knots,knot vector list
={0,1,2,3,4,5,6},每段函数的knot span=D=2。
对于二阶权重函数的计算,此时我们需要用到递归函数(下图中的公式2)。

首先,我们把重点放在公式中的阶数D,当我们要计算,我们预先要知道
和
。用文字来描述就是, 要想得到阶数为D的第i条曲线,需要预先知道阶数为D-1的第i条曲线和阶数同为为D-1的第i+1条曲线 。
同样,现在我们分别把i=0,1,5和D=2代入简化后的公式2,看一下二阶权重函数。

当i=0时,对于第0段函数而言,定义域u=[0,2)。但是,用于合成他的两个(2-1)一阶函数
和
的定义域分别是[0,1)和[1,2)。这一点可以借助之前的递归图更好的看明白:

因此,当u=[0,1)时,仅仅只有函数对函数
起作用,也就是上式中的前半部分
。此时,
等于0,
等于1,
=u。同理, 当u=[1,2)时,仅仅只有函数
对函数
起作用,也就是上式中的后半部分
。 此时,
等于0,
等于1,
=2-u。如下图所示:

当i=1时,u=[1,3):


当i=4时,u=[4,6):

二阶权重函数的图像:

这里我对上图进行一个简单的说明,我们看上图中的第一幅图,也就是的函数图像,他的第一段函数在0~1之间,此时y(u)=u,这是一个标准的y=x的函数图像,此时斜率为45°。现在我们把目光移到他的右半边,也就是第一段函数在1~2之间的图像,此时y(u)=2-u。熟悉函数图像的同学马上就会发现,他其实就是把y=-x的图像向上移动了2位得到的。
Matlab code:

三阶权重函数:
三阶函数,D=3,u=[i,i+3),第i段函数的有效区间为i+3。 总共7个knots,knot vector list
={0,1,2,3,4,5,6},每段函数的knot span=D=3。
按照Cox–de Boor递归公式,要求三阶的权重函数,首先我们要先知道二阶的权重函数,而这些函数都已经在前面求出来了。
和前面一样,我们把i=0,1,4和D=3逐一代入简化后的公式2,逐一看一下三阶权重函数。首先我们来看一下三阶权重函数的第0段函数,也就是当i=0时,u=[0,3)时的函数:

化简后得:

我们可以看到,和前面一样,为了求出,我们需要先知道
和
(前面已经算好了)。此时,我们要特别注意函数
的定义域u=[0,3),用于合成他的子函数之一
的定义域是[0,2),继而我们还会发现,对于
而言,用于合成他的子函数之一
的定义域是[0,1),在这以外都是0。也就是说,对于这个递归分段函数,我们要特别注意他的有效区间,或者说是每一小段子函数的有效定义域。(这在递归图中会更加直观)
1,当u=[0,1)时:

此时,只有在此处有定义,其他都为0。因此,这时只有
对函数
起作用, 此时,
等于u,
等于0,
=u^2/2。

2, 当u=[1,2)时:

此时,和
都有定义,他们同时对函数
起作用, 此时,
在[1,2)上等于2-u,
在[1,2)上等于u-1,
=(-2u^2+6u-3)/2。

3, 当u=[2,3)时:

此时,只有在此处有定义,其他都为0。因此,这时只有
对函数
起作用。此时,
等于3-u,
等于0,
=(3-u)^2/2。

当i=1时,u=[1,4):

当i=3时,u=[3,6):

三阶B-spline的函数图像:

Matlab code:

补充:





(全文完)
作者 --- 松下J27
谢谢收看!
参考文献:
1,B-spline Basis Functions: Definition
2,
诗词赏析:
《遣悲怀三首·其二》--- 元稹
昔日戏言身后意,今朝都到眼前来。(身后意 一作:身后事)
衣裳已施行看尽,针线犹存未忍开。
尚想旧情怜婢仆,也曾因梦送钱财。
诚知此恨人人有,贫贱夫妻百事哀。

(配图与本文无关)
版权声明:所有的笔记,可能来自很多不同的网站和说明,在此没法一一列出,如有侵权,请告知,立即删除。欢迎大家转载,但是,如果有人引用或者COPY我的文章,必须在你的文章中注明你所使用的图片或者文字来自于我的文章,否则,侵权必究。 ----松下J27