9.6 画像の重ね合わせ(アフィン変換・その3)&画像をぼかす

前回はアフィン変換行列の話が長くなっちゃったから紹介できなかったんだけど…
ん? なに?
アフィン変換にも画像を重ね合わせられるメソッドがあるんだ。
えっと、それって operateRect メソッドとか operateStretch メソッドみたいなのがアフィン変換用にもあるってこと?
operateRect メソッド、 operateStretch メソッドについては §9.3 参照。
そうそう。だから operateAffine メソッドっていうの。
画像を重ね合わせるメソッドには全部“operate”が付くんだね。
そうだね。ちなみに operate が付くメソッドは、 画像をそのまま重ね合わせる operateRect メソッド、 画像を拡大/縮小して重ね合わせる operateStretch メソッド、 あと画像をアフィン変換して重ね合わせる operateAffine メソッドの3つだよ。
じゃあ今回の operateAffine メソッドが最後の operate が付くメソッドなんだね。
そういうことになるね。
それじゃ、operateAffine メソッドを使って実際に画像をアフィン変換して重ね合わせてみるね。
は〜い。
それじゃこのスクリプトを first.ks に書き込んで実行してみて。

operateAffine メソッドの使用例(first.ksの中身)>

; メッセージレイヤを非表示にします
[position page=fore layer=message0 visible=false]
; 表画面の 0 番の前景レイヤに画像を読み込みます
[image page=fore layer=0 storage="krkr" visible=true]

[iscript]
// 画像を見やすくするため背景レイヤを白色で塗りつぶします
kag.fore.base.fillRect(0, 0, kag.fore.base.width, kag.fore.base.height, 0xFFFFFF);

// 0 番の前景レイヤへの参照を変数 layer0 に代入します
var layer0 = kag.fore.layers[0];

// 親レイヤを 0 番の前景レイヤとして一時レイヤを作ります
var tempLayer = new Layer(kag, layer0);
// 一時レイヤに 0 番の前景レイヤの画像をコピーします
tempLayer.assignImages(layer0);

// 0 番の前景レイヤの幅と高さを調整します
layer0.setImageSize(135, 90);
layer0.setSizeToImageSize();

// 0 番の前景レイヤを透明色で塗りつぶします
layer0.fillRect(0, 0, layer0.imageWidth, layer0.imageHeight, 0x00000000);

// operateAffine メソッドで画像をアフィン変換(回転)して重ね合わせます
layer0.operateAffine(tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, false, 0, 45, 45, 0, 45, 90, omAuto, 255, stNearest);
layer0.operateAffine(tempLayer, 0, 0, tempLayer.imageWidth, tempLayer.imageHeight, false, 90, 0, 135, 45, 45, 45, omAuto, 255, stNearest);

// 一時レイヤは必要なくなったので無効化します
invalidate tempLayer;
[endscript]

実行するね〜。
ん。ちなみにこのスクリプトは 吉里吉里のアイコン画像 を時計回りに45°回転させた画像と反時計回りに45°回転させた画像を重ね合わせるようにしてるから。

<実行結果(画像の部分だけ示しています)>

ちゃんと重ね合わせられてるね〜。
右のが時計回りに回転してて、左のが反時計回りに回転してるんだね。
そうそう。
じゃ次は operateAffine メソッドの引数を見てくね。
はーい。

operateAffine メソッドの引数>
引数名引数の意味デフォルト値
第1引数srcコピー元のレイヤ
第2引数sleftコピー元の四角形の左端の位置
第3引数stopコピー元の四角形の上端の位置
第4引数swidthコピー元の四角形の幅
第5引数sheightコピー元の四角形の高さ
第6引数affineアフィン変換行列を指定する場合は true/変換後の座標を指定する場合は false
第7引数Aアフィン変換行列の a 要素の値/変換後の左上の点の x 座標
第8引数Bアフィン変換行列の b 要素の値/変換後の左上の点の y 座標
第9引数Cアフィン変換行列の c 要素の値/変換後の右上の点の x 座標
第10引数Dアフィン変換行列の d 要素の値/変換後の右上の点の y 座標
第11引数Eアフィン変換行列の tx 要素の値/変換後の左下の点の x 座標
第12引数Fアフィン変換行列の ty 要素の値/変換後の左下の点の y 座標
第13引数mode演算のモードomAuto(自動決定)
第14引数opa演算の強度(不透明度)255
第15引数type補間のタイプstNearest(最近傍補間)
※アフィン変換行列の要素については §9.5 参照。

まず、第1引数〜第12引数までは affineCopy メソッドと同じだから大丈夫だよね?
affineCopy メソッドの引数については §9.4§9.5 参照。
うん、おっけー。
あと、第13引数〜第15引数は operateStretch メソッドの第10引数〜第12引数と同じなんだ。
ちなみに指定できる値とデフォルト値も operateStretch メソッドの mode, opa, type とおんなじだよ。
operateStretch メソッドの引数については §9.3 参照。
あ、そーなんだ。
じゃあ operateAffine メソッドって operateStretch メソッドのアフィン変換版みたいな感じなんだね。
ん、そんな感じだね。
んじゃスクリプトの方見ていこうと思うんだけど、 operateAffine メソッドを呼び出してるとこ以外は特に新しいことは何もやってないから、 operateAffine メソッドの呼び出しだけチェックすることにするね。
りょ〜かい。
operateAffine メソッドの第1引数〜第12引数までは affineCopy メソッドと同じだから、こうやって画像を変換してるってのはわかるよね?

operateAffine メソッドによる画像の変換>

この辺はおっけーだよ。もう何回もやったもんね。
ん、じゃ次は第13引数の mode だけど、 omAuto はどういう意味だったか覚えてる?
え〜っと…確かどうやって画像を重ね合わせるかを自動的に決めてくれるんじゃなかったっけ?
そ。この場合は元々の画像(吉里吉里のアイコン画像 のことね)がアルファ値の情報を持ってるから、omAlpha を使うのが良さそうって判断されて、結果的には omAlpha を指定して重ね合わせたのとおんなじになるわけね。
mode に指定できる値については §9.3 参照。
なるほどねぇ…
第14引数の opa は覚えてるよね?
opa は画像を重ね合わせる時の不透明度(opacity のことだよね)で、今は 255 になってるから半透明にせずに普通に重ね合わせてるんだよね。
そうそう。
んじゃ最後の type は?
画像を補間する時の方法だね。
stNearest になってるから、一番単純な補間方法を使ってるんだよね。
ん。ちなみに operateAffine メソッドの type に指定できるのは基本的に stNearest(最近傍補間)だけだよ。
※吉里吉里2 version 2.30 Rev.2 現在で stFastLinear は特定の条件を満たした場合のみ使用可能で、stLinear, stCubic は未実装(使用不可能)となっています。 詳細は「吉里吉里2リファレンス」の「Layerクラス−operateAffineメソッド」の項目を参照してください。
確か operateStretch メソッドもそうじゃなかったっけ?
うん、そうだよ。だからアフィン変換を使ってキレイに画像を重ね合わせようと思ったら、 拡大/縮小をやった時と同じように、 一旦 affineCopy メソッドで一時レイヤにアフィン変換した画像をコピーして、 それから operateRect メソッドで重ね合わせるの。
スクリプトにするとこんな感じだね。

<画像を低精度線形補間(stFastLinear)して重ね合わせるスクリプト(first.ksの中身)>

; メッセージレイヤを非表示にします
[position page=fore layer=message0 visible=false]
; 表画面の 0 番の前景レイヤに画像を読み込みます
[image page=fore layer=0 storage="krkr" visible=true]

[iscript]
// 画像を見やすくするため背景レイヤを白色で塗りつぶします
kag.fore.base.fillRect(0, 0, kag.fore.base.width, kag.fore.base.height, 0xFFFFFF);

// 0 番の前景レイヤへの参照を変数 layer0 に代入します
var layer0 = kag.fore.layers[0];

// 親レイヤを 0 番の前景レイヤとして1枚目の一時レイヤを作ります
var tempLayer1 = new Layer(kag, layer0);
// 1枚目の一時レイヤに 0 番の前景レイヤの画像をアフィン変換(回転)してコピーします
tempLayer1.setImageSize(90, 90);
tempLayer1.affineCopy(layer0, 0, 0, layer0.imageWidth, layer0.imageHeight, false, 0, 45, 45, 0, 45, 90, stFastLinear);

// 親レイヤを 0 番の前景レイヤとして2枚目の一時レイヤを作ります
var tempLayer2 = new Layer(kag, layer0);
// 2枚目の一時レイヤに 0 番の前景レイヤの画像をアフィン変換(回転)してコピーします
tempLayer2.setImageSize(90, 90);
tempLayer2.affineCopy(layer0, 0, 0, layer0.imageWidth, layer0.imageHeight, false, 45, 0, 90, 45, 0, 45, stFastLinear);

// 0 番の前景レイヤの幅と高さを調整します
layer0.setImageSize(135, 90);
layer0.setSizeToImageSize();

// 0 番の前景レイヤを透明色で塗りつぶします
layer0.fillRect(0, 0, layer0.imageWidth, layer0.imageHeight, 0x00000000);

// operateRect メソッドで2枚の一時レイヤの画像を重ね合わせます
layer0.operateRect(0, 0, tempLayer1, 0, 0, tempLayer1.imageWidth, tempLayer1.imageHeight);
layer0.operateRect(45, 0, tempLayer2, 0, 0, tempLayer2.imageWidth, tempLayer2.imageHeight);

// 一時レイヤは必要なくなったので無効化します
invalidate tempLayer1;
invalidate tempLayer2;
[endscript]

このスクリプトって first.ks に書き込んで実行できるの?
ん、ちょっと実行してみて。
は〜い。

<実行結果(画像の部分だけ示しています)>

確かにキレイに重ね合わせられてるね。
ちなみに affineCopy メソッドで使える補間法は stNeareststFastLinear の2種類だから、 画像をアフィン変換して重ね合わせる時に使える補間法もこの2種類だけってことに注意してね。
それじゃあこれって stFastLinear を使って重ね合わせてるってこと?
そうだよ。
このスクリプトの中には特に新しいことは出てこないから、説明は省略させてもらうね。
う〜ん…一時レイヤが2つ使われてるみたいだけど…
確かにメソッドとかは今まで使ったことあるのだけみたいだね。
じゃ次行っていいかな?
うん、おっけー。
とりあえずアフィン変換の話はここまでにしといて、 次は画像をぼかす doBoxBlur メソッドを見ていくことにするね。
画像をぼかすって、なんか前にやったことあるような気がするんだけど?
ん、画像をぼかす機能は eximage マクロに入れてるからね。
§9.1 の最後の方で実際にやってみたよね。
あ〜、そーいえば…
で、画像をぼかす doBoxBlur メソッドなんだけど、 これはアフィン変換のメソッドと比べるとずっとカンタンに使えるメソッドなんだ。
そーなの?
じゃ実際に doBoxBlur メソッドを使って画像をぼかしてみるね。
まずこのスクリプトを実行してみて。

<画像をぼかすスクリプト(first.ks の中身)>

; メッセージレイヤを非表示にします
[position page=fore layer=message0 visible=false]
; 表画面の 0 番の前景レイヤに画像を読み込みます
[image page=fore layer=0 storage="krkr" left=100 top=100 visible=true]

[iscript]
// 画像を見やすくするため背景レイヤを白色で塗りつぶします
kag.fore.base.fillRect(0, 0, kag.fore.base.width, kag.fore.base.height, 0xFFFFFF);
// 画像をぼかします
kag.fore.layers[0].doBoxBlur(2, 2);
[endscript]

確かにスクリプトはだいぶ短いみたいだね…
えっと、じゃあとりあえず実行してみるね。
うん。

<実行結果(画像の部分だけ示しています)>

§9.1 でやった時とおんなじように画像がぼやけてるね。
あの時と同じ設定で画像をぼかしてるからね。
それじゃスクリプトの方を見てこっか。
はーい。
って言ってもここdoBoxBlur メソッドを呼び出すだけでいいんだけどね。
えっと、kag.fore.layers[0].doBoxBlur(2, 2); ってことは、 0 番の前景レイヤに対して doBoxBlur メソッドを呼び出してるってコトだよね?
そうだね。
じゃあ画像をぼかすのって一時レイヤが無くてもできるってコト?
ん、doBoxBlur メソッドはそのレイヤの画像を直接ぼかすことができるから、 一時レイヤは必要ないよ。
そーなんだ。だからスクリプトがシンプルなんだね。
そういうことだね。
ちなみに引数はこの2つね。

doBoxBlur メソッドの引数>
引数名引数の意味デフォルト値
第1引数xblur横方向のブラーの範囲(ピクセル単位)1
第2引数yblur縦方向のブラーの範囲(ピクセル単位)1

ブラーの範囲…ってなんなの?
んー、ブラーの範囲によって画像のぼやけ方が変わってくるんだけど、 細かいことを説明するとややこしくなっちゃいそうだから、 とりあえずブラーの範囲が広ければ広いほど画像がぼやけるって思っといて。
えっと、それじゃあ xbluryblur の値が大きければ大きいほど画像がぼやけるってことなんだね?
そういうこと。
ちなみに、(xblur, yblur)(1, 1)(2, 2)(3, 3)(4, 4) にして doBoxBlur メソッドを呼び出すとこんな感じになるよ。

<各 xblur, yblur の値に対する doBoxBlur メソッドの実行結果>

ホントだ。
xbluryblur の値が大きくなると画像がどんどんぼやけていってるね。
あと、xbluryblur を別々の値にすると、 こんなふうに横方向や縦方向に画像をぼかすこともできるよ。

<縦方向・横方向に画像をぼかした結果>

いろんなぼかし方ができるんだね。
だね。
それじゃ今回はこれくらいにして、次回は image タグで使われてる他の画像処理系のメソッドを一通り見ていくことにするね。
image タグで使われてる他の画像処理系のメソッドって?
image タグには画像処理ができる色んな属性があるでしょ?
例えば grayscale 属性とか rgamma 属性とか mcolor 属性とか flipud 属性とか。
う〜ん…あんまり使ったことないけど、確かにそーゆー属性はいっぱいあるよね。
そういう属性は大抵 Layer クラスのメソッドが関係してるから、 どの属性を指定するとどのメソッドが呼び出されるのかってのを簡単に紹介しとこうと思うんだ。
なるほどね。りょーかい。
ん、それじゃまた次回ね!


前へ | TOP | 次へ