機械学習基礎理論独習

誤りがあればご指摘いただけると幸いです。数式が整うまで少し時間かかります。リンクフリーです。

勉強ログです。リンクフリーです
目次へ戻る

幅のある3次ベジェ曲線を定義してみる

はじめに

左右の異なる幅を3次ベジェ曲線を定義できれば、面白いものが作れるんじゃないかと思ったので、考えてみました。
非常に単純なアルゴリズムです。

幅をどうやって定義するか


左の幅、右の幅とは3次ベジェ曲線の接線ベクトルの方法に対しての左右です。
左と右を3次ベジェ曲線のパラメータを用いて定義します。
左の幅を{\rm w}_l(t)、右の幅を {\rm w}_r(t) とします。

\begin{eqnarray}
&&{\rm w}_l(t)=a_lt^3+b_lt^2+c_lt+d_l\tag{1}\\
&&{\rm w}_r(t)=a_rt^3+b_rt^2+c_rt+d_r\tag{2}
\end{eqnarray}
単なる3次式です。
左右別々に求めていきます。

幅関数のパラメータの求め方

左右どちらでもよいので、どちらかの関数を {\rm w}(t) とします。

\begin{eqnarray}
{\rm w}(t)=at^3+bt^2+ct+d\tag{3}
\end{eqnarray}
4点 \{(t_0,w_0),(t_1,w_1),(t_2,w_2),(t_3,w_3)\} より、パラメータ a,b,c,d を求めます。
3次ベジェ曲線の太さを決めるものなので、t_0=0,t_3=1 とします。
すると以下が成り立ちます。
\begin{eqnarray}
&&{\rm w}(0)=d=w_0\tag{4}\\
&&{\rm w}(t_1)=at_1^3+bt_1^2+ct_1+d=w_1\tag{5}\\
&&{\rm w}(t_2)=at_2^3+bt_2^2+ct_2+d=w_2\tag{6}\\
&&{\rm w}(1)=a+b+c+d=w_3\tag{7}
\end{eqnarray}
(4) を式 (5),(6),(7) に代入します。
\begin{eqnarray}
&&\left\{
\begin{array}{l}
at_1^3+bt_1^2+ct_1+w_0=w_1\\
at_2^3+bt_2^2+ct_2+w_0=w_2\\
a+b+c+w_0=w_3
\end{array}
\right.\\
\Rightarrow&&\begin{pmatrix}
t_1^3 & t_1^2 & t_1\\
t_2^3 & t_2^2 & t_2\\
1 & 1 & 1
\end{pmatrix}
\begin{pmatrix}a \\ b \\ c\end{pmatrix}
=\begin{pmatrix}w_1-w_0 \\ w_2-w_0 \\ w_3-w_0\end{pmatrix}\tag{8}
\end{eqnarray}
{\bf T}=\begin{pmatrix}
t_1^3 & t_1^2 & t_1\\
t_2^3 & t_2^2 & t_2\\
1 & 1 & 1
\end{pmatrix}とおきます。
この \bf T が正則であれば、a,b,c,d は求まるので、行列式を計算してみます。
\begin{eqnarray}
\det{\bf T}&=&t_1^3t_2^3+t_1^2t_2+t_1t_2^3-t_1t_2^3-t_1^2t_2^3-t_1^3t_2\\
&=&t_1t_2(t_1^2t_2+t_1+t_2^2-t_2-t_1t_2^2-t_1^2)\\
&=&t_1t_2(t_1-1)(t_2-1)(t_1-t_2)\tag{9}
\end{eqnarray}
おっと、びっくりするぐらい式がキレイになりました。
(9)=0 となるのは、t_1=0 または t_2=0 または t_1=1 または t_2=1 または t_1=t_2 のときです。
t_1,t_2 が共に 0 または 1 のときは、t_0,t_3 の2点からなる線分を求めればよいです。
t_1,t_2 のどちらかが 0 または 1 のときは、t_i\not=0,1t_0,t_3 の3点からなる2次曲線を求めればよいです。
t_1=t_2 のときは t_0,t_1, t_3 の3点からなる2次曲線を求めればよいです。
では、3点の場合の2次曲線も求めておきましょう。
\begin{eqnarray}
{\rm w}(t)=at^2+bt+c\tag{10}
\end{eqnarray}
3点 \{(t_0,w_0),(t_1,w_1),(t_2,w_2)\} より、パラメータ a,b,c を求めます。
t_0=0,t_1\in(0,1),t_2=1 とします。
すると以下が成り立ちます。
\begin{eqnarray}
&&{\rm w}(0)=c=w_0\tag{11}\\
&&{\rm w}(t_1)=at_1^2+bt_1+c=w_1\tag{12}\\
&&{\rm w}(1)=a+b+c=w_2\tag{13}
\end{eqnarray}
(11) を式 (12),(13) に代入します。
\begin{eqnarray}
&&\left\{
\begin{array}{l}
at_1^2+bt_1+ct_1+w_0=w_1\\
a+b+w_0=w_3
\end{array}
\right.\\
\Rightarrow&&\begin{pmatrix}
t_1^2 & t_1\\
1 & 1
\end{pmatrix}
\begin{pmatrix}a \\ b\end{pmatrix}
=\begin{pmatrix}w_1-w_0 \\ w_2-w_0\end{pmatrix}\tag{14}\\
\Rightarrow&&
\begin{pmatrix}a \\ b\end{pmatrix}
=\begin{pmatrix}
t_1^2 & t_1\\
1 & 1
\end{pmatrix}^{-1}\begin{pmatrix}w_1-w_0 \\ w_2-w_0\end{pmatrix}\tag{15}
\end{eqnarray}
(15)\begin{pmatrix}t_1^2 & t_1\\1 & 1\end{pmatrix}^{-1} は存在します。
なぜなら以下のように、いかなる時も行列式 0 にならないためです。
\begin{eqnarray}
\det \begin{pmatrix}
t_1^2 & t_1\\
1 & 1
\end{pmatrix}=t_1^2-t_1< 0
\end{eqnarray}

まとめ

4点 \{(t_0=0,w_0),(t_1,w_1),(t_2,w_2),(t_3=1,w_3)\} からなる幅関数 {\rm w}(t) は以下のようになります。
以下で使用する{\rm Same} 関数は次の通りです。

\begin{eqnarray}
{\rm Same}(a, b)\left\{
\begin{array}{l}
1\ (a=b)\\
0\ (a\not=b)
\end{array}
\right.
\end{eqnarray}
また、w_i の更新ですが t の値が等しいものの平均を取ります。
\begin{eqnarray}
&&w_i\leftarrow\frac{\sum_{j = 0}^3{\rm Same}(t_i, t_j)w_j}{\sum_{j = 0}^3{\rm Same}(t_i, t_j)}\tag{16}\\
\end{eqnarray}

(1) t_1,t_2 が共に 0 または 1 のときは、
w_0,w_3 を更新し、2点 \{(t_0,w_0),(t_3,w_3)\} から直線を求めそれを {\rm w}(t) とします。

\begin{eqnarray}
{\rm w}(t)=(w_3-w_0)t+w_0\tag{17}
\end{eqnarray}

(2) t_1,t_2 のどちらか一方のみが 0 または 1 のときは、
w_0,w_i,w_3 を更新し、3点 \{(t_0,w_0),(t_i,w_i),(t_3,w_3)\} から2次曲線を求めそれを {\rm w}(t) とします。(t_i\not=0,1)

\begin{eqnarray}
{\rm w}(t)=at^2+bt+c\tag{18}
\end{eqnarray}
\begin{eqnarray}
\begin{pmatrix}a \\ b\end{pmatrix}
=\begin{pmatrix}
t_i^2 & t_i\\
1 & 1
\end{pmatrix}^{-1}\begin{pmatrix}w_i-w_0 \\ w_3-w_0\end{pmatrix}
\end{eqnarray}
\begin{eqnarray}
c=w_0
\end{eqnarray}

(3) t_1=t_2 であり、t_1,t_2\not=0,1 のときは、
w_0,w_1,w_3 を更新し、3点 \{(t_0,w_0),(t_1,w_1),(t_3,w_3)\} から2次曲線を求めそれを {\rm w}(t) とします。

\begin{eqnarray}
{\rm w}(t)=at^2+bt+c\tag{19}
\end{eqnarray}
\begin{eqnarray}
\begin{pmatrix}a \\ b\end{pmatrix}
=\begin{pmatrix}
t_1^2 & t_1\\
1 & 1
\end{pmatrix}^{-1}\begin{pmatrix}w_1-w_0 \\ w_3-w_0\end{pmatrix}
\end{eqnarray}
\begin{eqnarray}
c=w_0
\end{eqnarray}

(3) t_1\not=t_2 であり、t_1,t_2\not=0,1 のときは、
4点 \{(t_0=0,w_0),(t_1,w_1),(t_2,w_2),(t_3=1,w_3)\} から3次曲線を求めそれを {\rm w}(t) とします。

\begin{eqnarray}
{\rm w}(t)=at^3+bt^2+ct+d\tag{20}
\end{eqnarray}
\begin{eqnarray}
\begin{pmatrix}a \\ b\\ c\end{pmatrix}
=\begin{pmatrix}
t_1^3 & t_1^2 & t_1\\
t_2^3 & t_2^2 & t_2\\
1 & 1 & 1
\end{pmatrix}^{-1}\begin{pmatrix}w_1-w_0 \\ w_2-w_0\\ w_3-w_0\end{pmatrix}
\end{eqnarray}
\begin{eqnarray}
d=w_0
\end{eqnarray}
結局、4点を通る3次関数の問題になりました。
大事なのは、その4点をどのように入力させるかですね、それにより使いやすさが決まると思います。

最後に

行列式の値が0に近くなると、計算が不安定なるので、例えばアプリケーションで t_1,t_2\in[0.01,0.99] とするなど、工夫するのもありだと思います。
また、今回は検討していませんが、一般逆行列を求めればこんな場合分け不要になるかと思います。(本件に一般逆行列をを適用した場合の記事は別途書く予定)
{\rm w}(t) は幅を返す関数なので正の値を返す必要があります。本記事ではそれについて考慮していませんので、アプリに組み込む際、4点が決まったときに{\rm w}(t) が0以下の値を取るときは警告でも出せば良いんじゃないでしょうか?

追記

中心となる曲線はCatmullスプラインで左右の幅は区分ごとに直線でよいと思う
(ex. 0-0.5: x=0.5t + 0.8, 0.5-0.8: x=-0.2t + 2.3, 0.8-1: 0.9)

目次へ戻る