Flashの最近のブログ記事
「画像処理プログラミング」のAS実装第3回目。
今回はズームブラーと回転ブラーに挑戦してみました。ズームブラーは前回のマスクパターンを利用したエフェクトの応用で、サンプルとする画素を画像の中心から放射状に並ぶ形で取得し、加重平均平滑化を行っています。
回転ブラーは上記のように取得したサンプルの画素に、更に90度加算してやるだけで実現できます。
んー、前回に比べると、実行速度がとても遅い感じ。どこか処理を間違っているのかなぁ?
こういうエフェクトを実用したい方は、popforgeにImageprocessing Libraryというのがあって、その中にZoomBlurとRadialBlurというクラスが用意されているようなので、試してみるといいかもしれませんねー。(このライブラリはswcファイルによる提供で、多分Flex用。詳しいことは分かりませぬ。)
余談ですが、ZoomBlurクラスは書籍掲載のサンプルコードに倣って、for文内で使うローカル変数をそのブロックの外でごっそりと定義したのですが、大量のデータを走査する場合は、こういうスタイルがプログラムの実行速度に影響を及ぼすのでしょうか?
僕は大抵for文内で変数定義をしているのですが。
via Using TextMate for ActionScript 3 Development (The Flash Blog)
TextMateがASエディタとしてとても優秀ということなので、とりあえずインストールしてみました。ちょっと試してみたところ、パッケージのimportを自動的に追加/削除してくれないのと、そして何よりもコードヒントが出ないのが非常に残念なところです。ただ、メニューを眺めた感じだと、その他の機能はかなり充実してそうですね。
価格はシングルライセンスだと$62。Flex Builderに比べればかなり安価。でもコードヒントの表示機能がないのはかなり痛いから、結局今のところはFlex BuilderがMacの最強ASエディタかなー。
前回に続き、画像処理の練習です。
今回は「マスクパターン」と呼ばれるものを用い、各々の画素にエフェクトを適用する際に、そのピクセルだけではなく、周辺の画素の値も考慮して計算を行っています。
「加重平均平滑化」は、少々効果が分かりづらいかもしれませんが、元の色をできるだけ保持しつつ、色の変化を緩やかにしてくれるという、要するにブラーみたいな効果ですね。
getPixel()、setPixel()を多用しているので、色々と高速化の余地はあるのでしょうが、まぁとりあえず基本っていうことでご容赦ください。
それと今回用いたマスクパターンは基本的な一例です。詳しく知りたい方は、「ラプラシンフィルタ」とかで検索してみると、色々と勉強になることが分かるのではないかと思います。
最後に、まったくの余談ですが、サンプルで使っているなんだかエッチい感じの女の人は、レナという名前だそうで、こういう理由から画像処理をするときのサンプルの定番らしいです。
ホントにエロイ人(18禁)だったんですねー。
なんか最近はJavaScriptの本を読んでみたり、Processingを触ってみたりと、まったくもって節操のない感じですが、懲りずに「詳解 画像処理プログラミング C言語で実装する画像処理アルゴリズムのすべて」という本を購入してみました。
ジュンク堂で平積みにされているのを目にし、ほとんど衝動買いに近い状態で購入しましたが、こういう無理めな本を買うにはイキオイも必要かと思うのですよ。
サンプルがC言語で書かれていることもあり、やはりそれなりに難しいのですが、Photoshop等の画像処理専用のアプリによってブラックボックス化されている一連の処理も、当然プログラムで実行されているわけで、そういうアルゴリズムをFlashでも実現できたらかなり役に立つのではないかと思います。
そんなわけで初歩の初歩ですが、線形関数を用いた色調変換に挑戦してみました。
右下がりのラインにすると、ネガ化処理とかできますね。
色調変換の部分はこんな感じです。
/*
pixelsにはgetPixel()で取得した24ビットカラーの値を、
r, g, bの各々のプロパティとして保持したオブジェクト
を格納してあります。
*/
var len:uint = pixels.length;
for (var i:uint = 0; i < len; i++) {
var rgb:Object = pixels[i];
var x:uint = i % bmd.width;
var y:uint = Math.floor(i / bmd.width);
// rgbの全てに対し、線形処理を行い、24ビット16進数の形に戻す
var calibratedColor:uint = ColorConversion.rgbToHex24(calibrateColor(rgb.r), calibrateColor(rgb.g), calibrateColor(rgb.b));
// レンダリング
bmd.setPixel(x, y, calibratedColor);
}
// 色調変換用の関数
function calibrateColor(color:uint):uint {
// y1はトーンカーブの始点のyの値
// y2はトーンカーブの終点のyの値
// それぞれ0〜255の範囲でマッピングしてあります
return ((y2 - y1) * color) / 255 + y1;
}
一端のFLASHerとして、「メモリーリークが発生しないように、使ったオモチャの後片付けは忘れずにしましょうね」ということでIDisposableというインターフェースを用意し、そこで定義されたdisposeと名付けたメソッドに、イベントリスナーの登録解除等を実装するようにしたりしてました。
今までこのメソッドは親のディスプレイオブジェクトから、このオブジェクトをremoveChildするタイミングでコールすることが多かったのだけれど、そうではなく自分自身のremovedFromStageイベントにリスナーとしてdisposeを登録しておけば、せっかく実装したメソッドを呼び忘れることが少なくなるのではないかと思うのだけれど、どうだろう?
public class DragTest extends Sprite implements IDisposable {
// コンストラクタ
public function DragTest() {
stage.addEventListener(MouseEvent.MOUSE_MOVE, mouseMoveListener);
// removedFromStageイベントにdisposeをリスナーとして登録しておく
addEventListener(Event.REMOVED_FROM_STAGE, dispose);
}
// IDisposableで定義したメソッドを実装
public function dispose(event:Event = null):void {
stage.removeEventListener(MouseEvent.MOUSE_MOVE, mouseMoveListener);
}
/*
このリスナーの登録を解除し忘れると、
イベントターゲット(この場合stage)はsomeObjectへの参照を保持し、
メモリーリークの原因となる(はず)
*/
private function mouseMoveListener(event:MouseEvent):void {
someObject.someMethod();
}
// 以下略
}
IDisposable.as
package {
import flash.events.Event;
public interface IDisposable {
function dispose(event:Event = null):void
}
}





