こんにちは。エンジニアをしています、鷲見と申します。
今回はアフィン変換についてです。
あらまし
Objective-Cにはアフィン変換を行う機能があり、簡単にUIViewの幾何学的変換を行うことができます。
例えばUIViewを回転したい場合は、以下のように書くことができます。
// ビューを30度回転 CGFloat angle = 30.0 * M_PI / 180.0; view.transform = CGAffineTransformMakeRotation(angle);
この他にもいろいろな機能があるのですが、その中にCGAffineTransformMakeという
アフィン行列を指定してアフィン変換を行う機能があります。
さて、このアフィン行列とは何なのでしょうか?そもそもアフィン変換とは一体何者なのでしょうか?
というわけで本ブログではアフィン変換の理屈について解説してみようと思います。
幾何学的変換
まずは、アフィン変換のことは置いておいて、
単純にオブジェクトを平行移動、拡大・縮小、回転させることを考えます。
デジタルオブジェクトは画素の集合ですから、画素1つ1つに対して、
何らかの処理をかけてやれば、これらのことを実現することができそうです。
ここでは画素の位置を(x, y)で表します。
ここでtxはx方向への移動量、tyはy方向への移動量です。
全画素分上記の計算を繰り返せばオブジェクトの平行移動が可能です。
上記の計算式は行列を用いることで1つにまとめることができます。
ここでsxはx方向の拡大率、syはy方向の拡大率です。
上記の計算式を行列を用いて1つにすると以下になります(拡大縮小行列)。
回転
回転は少し厄介です。
回転と相性のいい極座標で考えると、以下の計算式で行うことができます。
ここで、rは動径、φは偏角、θはφからの回転角度です。
xとyを使った計算式の方が扱いやすいので、直交座標に変形します。
上記の計算式を行列を用いて1つにすると以下になります(回転行列)。
アフィン変換
上記で表した計算式を使用すれば、オブジェクトを変換することができますが、
これらの計算式をひとつにして汎用的に使用できるようにすると便利です。
さらに以下のように、3次元の座標を導入すると上記を1つの行列の乗算にまとめることができます(アフィン行列)。
この行列を用いることで、任意の線形変換(拡大・縮小・回転など)と平行移動を組み合わせた変換ができるようになります。これがアフィン変換です。
CGAffineTransformMakeを使ってみる
上記を踏まえた上でCGAffineTransformMakeを使ってみます。
CGAffineTransformMakeのシンタックス
CGAffineTransform CGAffineTransformMake ( CGFloat a, CGFloat b, CGFloat c, CGFloat d, CGFloat tx, CGFloat ty );
平行移動
CGFloat tx = 50; // x軸方向に50px移動 CGFloat ty = 100; // y軸方向に100px移動 myView.transform = CGAffineTransformMake(1, 0, 0, 1, tx, ty);
拡大・縮小
CGFloat sx = 2.0f; // x軸方向に2倍 CGFloat sy = 0.5f; // y軸方向に0.5倍 myView.transform = CGAffineTransformMake(sx, 0, 0, sy, 0, 0);
回転
CGFloat angle = 45.0 * M_PI / 180; // 45度回転(ラジアンに変換) myView.transform = CGAffineTransformMake(cos(angle), -sin(angle), sin(angle), cos(angle), 0, 0);
以上今回はアフィン変換について解説してみました。
OpenCVやvImageなど、面倒くさいことをしなくても、
この手の変換をしてくれるライブラリが充実してきたのは大変うれしいですね。
※ 座標を等倍しているだけなので、実際には再配列や内挿などの処理が必要です。