この記事は現在、プロジェクトメンバーによる査読中のものです。草稿段階ですので、内容・表現の正確さについて責任を負いかねます。 リンクを正しく張れていないところが存在しますのでご注意ください。 正式公開まで、いましばらくお待ちください。
JavaScriptのsetTransformについて

仕事で,JavaScriptで画像処理を行う機会があったのですが, その中で,setTransform関数で画像の回転を扱いました. それに関してなかなか明快な説明をしているサイトが探せなかったので, この関数について,説明してみようと思います. 取りあえずは,こちらの 画像回転のデモ をご覧ください.

HTMLの残念な座標系

chromel-setTransform-01.png

HTMLにおいては,座標は左から右にx軸があり,上から下にy軸があります. つまり,左手系なのです.(図1参照)

setTransformの引数

さて,setTransform関数は次のような引数を取ります.

setTransform(a,b,c,d,e,f);

このa〜fは行列の成分を意味します. 以下の様な行列です.

A = \begin{pmatrix}a & c & e \\b & d & f \\0 & 0 & 1\end{pmatrix} \tag{1}

つまり,アフィン変換です. ここで,canvas上の座標 (x,y)A で変換した後の座標を (x^\prime,y^\prime) とすると,

\begin{pmatrix}x^\prime \\y^\prime \\1\end{pmatrix} = \begin{pmatrix}a & c & e \\b & d & f \\0 & 0 & 1\end{pmatrix}\begin{pmatrix}x \\y \\1\end{pmatrix}\tag{2}

となります.

画像の回転

ここで,能動的回転を考えましょう. \alpha だけ反時計回りに回転するとき,

\begin{pmatrix}x^\prime \\y^\prime \\1\end{pmatrix} = \begin{pmatrix}\cos \alpha & -\sin \alpha & 0 \\\sin \alpha & \cos \alpha & 0 \\0 & 0 & 1\end{pmatrix}\begin{pmatrix}x \\y \\1\end{pmatrix}\tag{3}

となります. この際,左手系であることが混乱を招きます.

chromel-setTransform-02.png

しかし,高校数学の複素数平面をご存知の方は,こう考えるといいでしょう. 計算の世界では普通の複素数平面で, \alpha(>0) の回転は反時計回りの回転を考えます. 回転後に,canvasの世界に合わせる為,x軸で折り返して,左手系にするのです.(図2参照)

だから,式 (3) は複素数平面の世界では反時計回りで, canvasの世界になった時,時計回りの回転を表します.

画像の並進

なお, e,f に関しては,canvasの原点 O を中心に a,b,c,d で回転した後, 原点自体が (x,y)=(e,f) へ並進すると考えればよいでしょう.

若しくは, (x,y)=(e,f) を中心に \alpha の回転を行ったのだ. と考えても良いです.

canvasの書き方に関して

さて,以上を踏まえて,最初のデモファイルでは画像クラスの中で,

ctx.setTransform(Math.cos(rad),Math.sin(rad),-Math.sin(rad),Math.cos(rad),e,f);

ctx.drawImage(img, -img.width/2, -img.height/2);

という順番でコマンドを書いています. これはつまり,setTransformで画像を書き込む前に座標系を (e,f) を原点にし, その原点中心として時計回りに \alpha 回転させた座標系に取り直します.

次のdrawImage(img,width,height)ですが,これは本来,座標点 (width,height) を左上の隅として,そこから右下領域に画像を書き込むコマンドです.setTransformで原点は (e,f) になって,x,y基底ベクトルも \alpha 回転していますから, 長方形の画像の横幅 img.width ,縦幅 img.height として,drawImage(img, -img.width/2, -img.height/2) とすることで, (e,f) に画像の中心をおき, \alpha の回転を行った画像が張られます.つまり,これを一定時間間隔でangleを変えながら表示することで,画像を中心を原点として時計回りに回転し続けるプログラムになっています.

今日はここまで,お疲れさまでした!