Swift Playgroundsで学ぶiOSプログラミング

6つのパラメーターを使って画像を変形させてみる

文●柴田文彦 編集●吉田ヒロ

2017年07月10日 17時00分

既定のアフィン変換とスケーリングを利用

 アフィン変換について、ここで詳しく解説するゆとりはありませんが、有名な手法なのでネット上にいくらでも情報はあるはずです。簡単に言えば、元のX,Y座標に対して3×3(実質的には、そのうちに2×3)のマトリクス(行列)を掛け合わせて変換後の座標を得る、というものです。

 iOSでは、CGAffineTransformというデータ構造として定義されています。原理的には、その行列の要素を任意に設定して目的の変換を得ることができるのですが、よく使われる定型的変換については、簡単に変換行列を設定する方法があらかじめいくつか用意されています。そのうちの1つが拡大/縮小実現するもので、X軸方向とY軸方向の拡縮率を別々に指定できるようになっています。

 その部分の実際のコードは少しあとで見ることにして、その前に、前回とは違ったアニメーションの起動方法について確認しておきましょう。前回は、まずUIViewPropertyAnimatorクラスのオブジェクトを初期化することでアニメーションオブジェクトを作成し、そのオブジェクトのstartAnimationメソッドによってアニメーションを起動していました。今回は、そのクラスに用意されたrunningPropertyAnimatorというメソッドを使って、アニメーションを作成すると同時に起動します。

 なぜそうするかと言うと、このメソッドを使うとアニメーションを作成してから起動するまでの待ち時間を指定することができるからです。それによって、viewDidLoadメソッドの中でアニメーションを作成し、一定時間が経過したところで自動的に起動させています。今回は、ボタンではなく、画像(UIImageView)をアニメートしたかったので、これが最もシンプルな方法と判断しました。

 それでは、このrunningPropertyAnimatorメソッドを使い、CGAffineTransformによるスケーリングとアルファ値の変更、中心点の移動を組み合わせたアニメーションを実行するプログラムを画面で確認しましょう。

CGAffineTransformの既定の変換の1つ、スケーリングと、前回も利用したアルファ値の変化、中心点の移動を組み合わせて、ASCII倶楽部ロゴが拡大されながら消えていくアニメーションを構成しました

 高度な処理のわりにはプログラムはシンプルで、1画面にすべて収まっています。この例では、ASCII倶楽部のロゴ画像をサイトからコピーして「clubName.png」という名前で保存し、iCloud経由でプレイグラウンドにコピーしてあります。

 このプログラムを動かすと、まずASCII倶楽部のロゴが画面の左上に表示されます。

アニメーションは、プログラムの起動と同時にスタートしますが、実際には2秒の遅延を設定してあるので、最初の2秒間は止まっています

 それから約2秒後にアニメーションが起動し、ロゴは拡大されると同時に薄くなり、画面の右下に向かって移動し、最後には見えなくなります。

プログラムの起動2秒後に動き出したアニメーションは、ロゴ画像を移動しながら拡大し、さらにアルファ値を0に向かって変化させることで、消えていくような効果を生み出します

スケーリングに代えて別の既定のアフィン変換と回転を指定

 CGAffineTransformの別の既定の変換には、変換対象を回転させるものも用意されています。rotationAngleのパラメータに回転角度をラジアン(πが180度)で指定するものです。上の例のスケーリングの部分を、回転に置き換えて試してみましょう。回転角度はちょうど180度となるように、πを表すCGFloat.piで指定しています。最初に左上にASCII倶楽部のロゴが表示されるところは同じですが、アニメーションが始まるとロゴは回転しながら、同時に色が薄くなりながら、右下方向に移動して消えていきます。

CGAffineTransformの既定の変換には、回転を実現するものもあります。回転角度をラジアンで指定するだけで設定できます。上の例の拡大の効果を回転に置き換えて、動かしてみました

 CGAffineTransformの既定の変換には、もう1つ平行移動を実現するトランスレーションというものもあります。これはスケーリングの場合のscaleXをtranslationXに代えて、x軸、y軸方向の移動量を指定するだけでいいのです。これはビューの中心座標を移動するのと基本的には同じ結果になるので実例は省略します。気になる人は実際に試してみてください。

フルカスタム仕様のアフィン変換で画像を変形

 CGAffineTransformには、変換行列内の個々の要素を指定できる、フルカスタマイズ可能な使い方も用意されています。この場合、3×3の座標変換のマトリクスの中で、アフィン変換として有効な2×3の6つのパラメータを指定することになります。その6つのパラメータは、一般的にa、b、c、d、tx、tyと呼ばれていますが、CGAffineTransformでもそれらの名前をそのまま採用しています。

座標変換行列の9つのパラメータのうち、アフィン変換として設定可能なのは、a、b、c、d、tx、tyの6つです。右端の列の0、0、1は、アフィン変換では固定です

 ちなみに、元のX、Y座標に、このマトリクスを掛け合わせる行列式は下図のようになります。変換の結果、新たな座標X'、y'が得られるというわけです。

平面上の座標値X、Yにアフィン変換のマトリクスを掛け合わせる行列式は、このようなかたちになります。座標は3×1のマトリクスで表していますが、実質は2次元なので、3番目は常に1としています

 この式を展開すると下図のようになります。これから、パラメータaとdは、それぞれX軸方向とY軸方向の拡大、縮小に関わるものだとわかるでしょう。またtxとtyは、それぞれX軸方向とY軸方向の移動量を表していることも明白です。

変換前の座標値X、Yに対して、変換後の座標値X'、Y'は、前の図の行列式を展開して、このような式で表すことができます。ちなみに何も変換しない場合は、aとdに1、そのほかのパラメータはすべて0にすればいいのです

 それでは、bとcはなんでしょうか。これらのパラメータは、それぞれX座標の要素をY座標に、Y座標の要素をX座標に持ち込んでいます。これらをうまく指定すると、回転や、アフィン変換に特徴的な変形を実現できます。その中には、いわゆる「剪断変形」も含まれています。これは図形の底辺と上辺に、それぞれ左右方向に逆の力が働いて横滑りしたような変形です。文字なら斜体(イタリック)になります。

 言葉で説明してもよくわからないので、実例を見てみましょう。剪断変形を実現するには、bは0のまま、cに適当な値を設定します。ここでは、-0.6に設定しています。また、拡大/縮小の必要はないので、aとdは1に設定し、ついでに少し位置をずらすために、txとtyにも適当な値を設定しています。

剪断変形を実現するために、aとdには1.0を、bには0.0、cには-0.6を指定しています。txとtyは、いずれも0でいいのですが、変形のついでに少しだけ右下に移動するように比較的小さな値を設定してみました

 この結果は、画像が少しだけ右下に移動しながら、右方向に傾く剪断変形が加わったものとなります。

 これを上の式で考えると、bが0なので、y座標に対するx座標の影響はありませんが、cの値が0ではないので、x座標にy座標の影響が現れます。それによって、図形の高さが高くなるほど横滑りが大きくなるような効果、つまり剪断変形が実現できるのです。

複数のアフィン変換をつなげて、1つにまとめてから適用

 CGAffineTransformには、別々に定義した2つのアフィン変換オブジェクトをつなげて1つにまとめる、concatenatingというメソッドが用意されています。結果は、2つの変換の効果が合成されたものとなります。このメソッドを続けて使えば、3つあるいはそれ以上の数のアフィン変換も1つにまとめることが可能です。

 このメソッドを使って、カスタムなパラメータ設定で実現した剪断変形、既定の回転、既定の平行移動を1つのアフィン変換に合成し、ASCII倶楽部のロゴ画像に適用する様子をアニメーションで表示してみましょう。

2つのアフィン変換を合成するconcatenatingメソッドを使って、2つ以上の変換をくっつけて1つにまとめることができます。この例では、合成後アフィン変換のパラメータをSwift Playgroundsのオブジェクトプレビュー機能によって確認しています

 なお、Swift Playgroundsのデバッグ機能では、実行中のソースコードの右側に表示されるアイコンをタップすることで、該当するオブジェクトの値、内容をプレビューすることができます。CGAffineTransformのオブジェクトの場合には、なんとアフィン変換マトリクスの6つのパラメータの値を確認可能です。これで合成前や合成後のマトリクスの内容把握できるので、アフィン変換の学習にも大いに役立つでしょう。

次回の予定

 前回と今回で取り上げたUIViewPropertyAnimatorは、ビューのプロパティを変化させるという、アニメーションとしては比較的地味な効果を実現するものでした。前にも書きましたが、iOSには他にも色々なタイプのアニメーション機能が用意されています。次回からは、もう少し見栄えのするアニメーション機能を少しずつ探求していく予定です。

mobileASCII.jp TOPページへ

mobile ASCII

Access Rankingアクセスランキング