多項式による曲線の表現: ベジェ曲線

CADなどの分野では、滑らかな曲線または曲面を表現するために、多項式が多く使用される。

コンピュータで使用される文字のフォントも多項式で現れている。

今回の授業では、バーンスタイン多項式(Bernstein polynomial)を紹介して、ベジェ曲線(Bezier curve)の作成方法を学ぶ。

1. バーンスタイン多項式の定義

$n$ 次バーンスタイン基底関数は次のように定義される。

$$ B_{i,n}(x) = {n \choose i} x^{i} (1-x)^{n-i}, \qquad i=0,\ldots,n. $$

ここで ${n \choose i}$ は二項係数として与えられる。

$\{1,x,x^2,\cdots, x^n \}$は$n$次多項式空間(ベクトル空間)の基底となることはよく知られている。 $n$次バーンスタイン基底関数も$n$次の多項式空間の基底となっている。 即ち、任意の$n$次多項式$y(x)$は基底関数$B_{i,n}(x)$の線形結合によって与えられる。

$$ y(x) = \sum_{i=0}^{n} C_{i} B_{i,n}(x) $$

上記の式で書かれている多項式は$n$ 次のバーンスタイン多項式と呼ばれる。 係数 $C_i$ はバーンスタイン係数、またはベジェ係数と呼ばれる。

例1:バーンスタイン多項式の例

  • 3次バーンスタイン多項式の基底関数のグラフを描画しなさい。

$$ B_{0,3} = (1-x)^3 , \quad B_{1,3} = 3x(1-x)^2, \quad B_{2,3} = 3x^2(1-x) , \quad B_{3,3} = x^3 $$

  • $1^3=(x+(1-x))^3$を展開して、各項と上記の3次バーンスタイン多項式と比較してください。
In [32]:
import matplotlib.pyplot as plt
import numpy as np

#[0,1]の分割点を作成します。
x=np.linspace(0,1,101)

color_list = ["r","g","b","k"]

B = []

B.append( (1-x)**3 )
B.append( 3*x*(1-x)**2 )
B.append( 3*x**2*(1-x) )
B.append( x**3 )

for k in range(0,4): 
    plt.plot(x,B[k], color_list[k] )
    
plt.grid()

バーンスタイン多項式による曲線の表示

バーンスタイン多項式を基底として、基底の線型結合で得られる曲線を描いてみます。

多項式の例:

$$ y(x)= 1\cdot B_{0,3}(x) + 2\cdot B_{1,3}(x) + 3\cdot B_{2,3}(x)+ 1\cdot B_{3,3}(x) $$

特殊な多項式:

$$ f(x)=B_{0,3}(x) + B_{1,3}(x) + B_{2,3}(x)+ B_{3,3}(x) = \sum_{i=0}^{3} B_{i,3}(x) $$

$$ g(x)=0\cdot B_{0,3}(x) + \frac{1}{3}B_{1,3}(x) + \frac{2}{3}B_{2,3}(x) + \frac{3}{3} B_{3,3}(x) = \sum_{i=0}^{3}\frac{i}{3} B_{i,3}(x) $$

補足

plot関数を使って、多数のグラフを一括で描画することができる。

plot( x1_list, y1_list, option_1,  x2_list, y2_list, option_2, ... )
In [25]:
import matplotlib.pyplot as plt
import numpy as np

#------------------ 曲線1 ------------------
c = [1,2,3,1]

y = 0
for k in range(0,4): 
    y += c[k]*B[k]

#------------------ 曲線2 ------------------
c = [1,1,1,1]

f = 0
for k in range(0,4): 
    f += c[k]*B[k]

#------------------ 曲線2 ------------------
c = [0,1/3,2/3,3/3]

g = 0
for k in range(0,4): 
    g += c[k]*B[k]

plt.plot(x,y,'-k', x,f,'-r',x,g,'-b')


plt.grid()

一般的な $n$ 次バーンスタイン多項式

以下の式の展開式を確認してください。

$$ 1^n=(x+(1-x))^n = \sum_{i=0}^n \frac{n!}{i!(n-i)!} x^i(1-x)^{n-i} = \sum_{i=0}^n B_{i,N}(x)\:. $$

$n$ 次バーンスタイン多項式の微分は以下の性質を持ってます。

$x=0$のとき、

$$ B'_{0,n}(0)=-n, \quad B'_{1,n}(0)=n, \quad B'_{2,n}(0)=\cdots = B'_{n,n}(0)=0 $$

$x=1$のとき、

$$ B'_{0,n}(1)=\cdots = B'_{n-2,n}(1)=0 , \quad B'_{n-1,n}(1)=-n, \quad B'_{n,n}(1)=n $$

以下の関数Bernstein(i,n,x)は一般的な$n$次バーンスタイン多項式の各関数を定義しています。特に、階乗の関数はfactorial()である。即ち、

$$ \mbox{factorial}(n) = 1\cdot 2 \cdot 3 \cdots (n-1) \cdot n $$

In [19]:
import math
def Bernstein(i,n,x):
    value = math.factorial(n) / ( math.factorial(i) * math.factorial(n-i) )* x**(i) * (1-x)**(n-i)
    return value

バーンスタイン多項式の性質

演習1

  • すべての$5$次バーンスタイン多項式のグラフを描いてください。
  • 各多項式の$x=0$, $x=1$における微分を確認してください。
In [33]:
#演習1
#すべての多項式のグラフを描いてください。

import matplotlib.pyplot as plt
import numpy as np

#[0,1]の分割点を作成します。
x=np.linspace(0,1,101)

B_list = []
B_list.append(Bernstein(0,5,x))
plt.plot(x,B_list[0])
plt.grid()

2. ベジェ曲線

ベジェ曲線(Bézier Curve)とは、、バーンスタイン多項式の線型結合で現れる曲線である。

$$ f(x) = \sum_{i=0}^{N} C_{i} B_{i,N}(x) $$

係数$c_i$に対して、点$P_i( {i}/{N}, C_{i})$が制御点または「コントロール点」と呼ばれる。

$$ P_0(0, C_0) ,~~ P_1(\frac{1}{N}, ~~ C_1) , ~~ \cdots, ~~ P_i(\frac{i}{N}, C_i) , ~~ \cdots, ~~ P_N(1, C_N) , $$

3次ベジェ曲線の例

3次ベジェ曲線$B(x)$

$$ B(x) = C_0 B_{0,3}(x) + C_1 B_{1,3}(x) + C_2 B_{2,3}(x) + C_3 B_{3,3}(x) $$

の関数値と微分を計算してみます。

$$ B(0) = C_0, \quad B'(0) = 3 (C_1 - C_0), \quad B(1) = C_3, \quad B'(1) = 3(C_3- C_2) $$

演習2

  • 以下のC_iに対する制御点$P_i(i=0,1,2,3)$の折れ線を描きなさい。
  • 制御点によって決められる3次ベジェ曲線を描きなさい。

$$ C_0 = 0, C_1 = 2, C_2 = -1, C_3 = 0 $$

考察

  • 制御点の折れ線の両端の座標とベジェ曲線$B(x)$の両端の値と比較してください。
  • 制御点の折れ線の勾配を求めて、ベジェ曲線$B(x)$の両端の微分と比較してください。
In [35]:
C=[0,2,-1,0];

#曲線の描画
f=0;
x=np.linspace(0,1,101)
for k in range(0,4):
    f = f+C[k]*Bernstein(k,3,x) 

plt.plot(x,f,'b-')

#制御点の描画
plt.plot(np.linspace(0,1,4), C, 'r-o')

plt.grid()

レポート課題

ベジェ曲線の制御点を選んで、関数$y=\sin(2\pi x)$ ($0\le x \le 1$)の良い近似ベジェ曲線を作成しなさい。

  • ベジェ曲線の次数を自由に選んでください。(最大6次まで)
  • ベジェ曲線の近似が良いがとうかについて、判断の基準を自由に考えてください。
  • 区分的なベジェ曲線を使っても良い。例えば、[0,0.5]と[0.5,1]の区間で二つのベジェ曲線を作ること。
In [31]:
#レポート課題 (ベジェ曲線の次数と制御点を調整して、Sin曲線のよい近似を作成してください。)
import matplotlib.pyplot as plt
import numpy as np

x=np.linspace(0,1,101)
y=np.sin(2*math.pi*x)
plt.plot(x,y,'b-')

C=[0,4.,-4.,0]; 
f= 0;
for k in range(0,4):
    f = f+C[k]*Bernstein(k,3,x)

plt.plot(x,f,'r-')
plt.grid()