アフィン変換基本のキ
https://gyazo.com/e99be02ba27aa6ba8b4511438fa13790
アフィン変換というものがありますkeroxp.icon2019/4/13
というかあることは知っているけどよくわからない人のためにこの記事を書いています
ソフトウェア開発、特にUIやゲームの開発においてはアフィン変換はある座標値 $ (x,y) を別の座標値$ (x',y') に一意に変換する操作を指します
ソフトウェア開発において座標を変換する操作は一般的に変形(transform)と呼ばれます
大抵の場合点群(points)が形(form)をなしていて、それをまとめて変換する作業が変形といえるからじゃないでしょうか
点群はパス(path)や矩形(rect)、円弧(arc)などが一般的です
線分や円弧は数学的には方程式で表された連続な点群ですが、ソフトウェアにおいてはこれら有限に分割された点群として計算されています
点群を変形したいと思うことはユーザの操作を受け付けるUIやゲームを開発している場合によくあります
とくにPhotoshopやAffinityDesignerなどの画像編集アプリは顕著で
回転
移動
拡大
などをする場面がとても多いです
アフィン変換はこういった変形操作を一発で適用するために便利な方法として有名です
前提として、アフィン変換は行列の掛け算として表現されます
行列がなにかわからないという人は別途調べてください
ある座標値 $ (x,y) を別の座標値$ (x',y') に変換するアフィン変換は次のように定義されます
$ \begin{pmatrix} x' \\ y' \end{pmatrix} = M \times \begin{pmatrix} x \\ y \end{pmatrix}
※Mは2x2のアフィン行列
アフィン行列Mを座標値(x,y)に掛けることで、変換後の座標値を計算します
この順番がとても重要で、アフィン変換は適用する変形から先にかけなくてはいけません
なぜかというと、Mは2x2の行列なので、2x1の行列である(x,y)の後にかけることができないからです
※行列の積は左の行列の列数(幅)と右側の行列の行数(高さ)が等しくないと定義できない
2x2のアフィン行列の定義は次のようになります
$ M = \begin{bmatrix} scaleX & skewY \\ skewX & scaleY \end{bmatrix}
Mが2行2列の正方行列である理由は、適用させるx, yの座標を2行1列の行列として表現するためです
※知っているアフィン行列と違う?もう少し読みすすめてくださいね
scaleX, scaleYは、それぞれx, y方向の拡大値を表します
skewX, skewYは、それぞれx, y方向のせん断値を表します
せん断がどんな変形になるかというのは以下を参照してください
正直せん断単体で変形させたいことはあまりないです
skewはsearとも呼ばれます
アフィン行列の単位行列(identity)は以下のように定義されます
$ \begin{bmatrix} 1 & 0 \\ 0 & 1 \end{bmatrix}
(0,0)を原点とした座標(100, 200)をx, yともに2倍に拡大するアフィン変換は以下のようになります
$ \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{bmatrix} 2 & 0 \\ 0 & 2 \end{bmatrix} \times \begin{pmatrix} 100 \\ 200 \end{pmatrix} = \begin{bmatrix} 2 \times 100 + 0 \times 200 \\ 0 \times 100 + 2 \times 200 \end{bmatrix} = \begin{pmatrix} 200 \\ 400 \end{pmatrix}
次は回転です。回転は、スケールとせん断を組み合わせたアフィン行列によって表現されます
(0,0)を原点とした座標(x,y)をθ(radian)だけ回転させる変換は以下のようになります
$ \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{bmatrix} cos\theta & -sin\theta \\ sin\theta & cos\theta \end{bmatrix} \times \begin{pmatrix} x \\ y \end{pmatrix} = \begin{bmatrix} cos\theta \times x -sin\theta \times y \\ sin\theta \times x + cos\theta \times y \end{bmatrix}
しかしなぜ回転がこの行列で表せるのでしょうか?
というのは長くなりそうなので別記事で解説します
2x2のアフィン行列はスケールとせん断を同時に適用することができる変換です
しかし(x,y)の純粋な平行移動は適用できません
座標の平行移動は一般的に行列の加法で表現されます
$ \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{pmatrix} x \\ y \end{pmatrix} + \begin{pmatrix} tx \\ ty \end{pmatrix} = \begin{pmatrix} x + tx \\ y + ty \end{pmatrix}
※tx, tyはxとyの移動量(tlansrate)
プログラムで書くとこんな感じで、よく書きますね
code:js
let x = 100;
let y = 200;
let tx = 50;
let ty = 100
let x_ = x + tx; // 100 + 50 = 150
let y_ = y + ty; // 200 + 100= 300
スケール・せん断と平行移動を合わせた変形は、次のような式で表されます
$ \begin{pmatrix} x' \\ y' \end{pmatrix} = M \times \begin{pmatrix} x \\ y \end{pmatrix} + \begin{pmatrix} tx \\ ty \end{pmatrix}
では、この平行移動もスケール・せん断と同時に掛け算として一発で行えないでしょうか?
しかしここで問題があります
先ほども言いましたが行列同士の掛け算は、掛け合わされる同士で、左側の列数(幅)と右側の行数(高さ)が同じでないと定義できません
2x2のアフィン行列は二次元座標(x,y)適用するために2x2として定義されています
平行移動の要素をアフィン行列に追加すると、次元数が3に上がって3x3行列になってしまい、(x,y)に適用できません
さてどうしたものか…というときにちょっとした工夫でそれが可能になります
それが、二次元座標にダミーの要素(component)を一つ追加するという工夫です
すると二次元の座標はこう表現します
$ \begin{pmatrix} x \\ y \\ 1 \end{pmatrix}
3行目の1は、計算上使われないダミーの要素で、値が1なのは何が掛け合わされてもその値を変更させないためです
平行移動が追加されたアフィン行列は、3x3の正方行列になり、アフィン変換の定義はこうなります
$ \begin{pmatrix} x' \\ y' \\ 1 \end{pmatrix} = M \times \begin{pmatrix} x \\ y \\ 1 \end{pmatrix}
先程平行移動は行列同士の加算で表現されると書きました
平行移動が追加されたアフィン変換では、x'とy'の値はこうなっていてほしいはずです
$ \begin{pmatrix} x' \\ y' \end{pmatrix} = \begin{bmatrix} scaleX & skewY \\ skewX & scaleY \end{bmatrix} \times \begin{pmatrix} x \\ y \end{pmatrix} + \begin{pmatrix} tx \\ ty \end{pmatrix} \\ = \begin{pmatrix} scaleX \times x + skewY \times y + tx \\ skewX \times x + scaleY \times y + ty \end{pmatrix}
これを満たすための3x3のアフィン行列Mは、次のように定義できます
$ M = \begin{bmatrix} scaleX & skewY & tx \\ skewX & scaleY & ty \\ 0 & 0 & 1 \end{bmatrix}
実際に計算してみます
簡単のため、
scaleX = a
skewX = b
skew Y = c
scaleY = d
として計算します。すると、
$ \begin{pmatrix} x' \\ y' \\ 1 \end{pmatrix} = \begin{bmatrix} a & c & tx \\ b & d & ty \\ 0 & 0 & 1 \end{bmatrix} \times \begin{pmatrix} x \\ y \\ 1 \end{pmatrix} = \begin{pmatrix} a \times x + c \times y + tx \times 1 \\ b \times x + d \times y + ty \times 1 \\ 0 \times x + 0 \times y + 1 \times 1 \end{pmatrix} = \begin{pmatrix} ax + cy + tx \\ bx + dy + ty \\ 1 \end{pmatrix}
と、見事に欲しかったx', y'の値が手に入ったのがわかるでしょうか
これがアフィン変換だ!!