Flash CS3 - 背景差分法

昨日Flash CS3を買ったので、さっそくAS3でやってみた。

自分で1からBitmapDataクラスを使うのは初めてだったけどprocessingやってたお陰ですぐわかった。

一旦カメラの前からどいて、Save Backgroundボタンを押してみてください

うまくいくとこうなってるはず

BackgroundSubtraction

SourceCode (Flash CS3 / AS3)



1フレーム目。左の大きなビデオ(camDebug)とは別に、画面に表示していない200×150の小さなVideoオブジェクト(camVideo)がある。そこからBitmapDataを作って、背景差分法で処理する。処理した結果を画面右のBitmapオブジェクトに表示して、ついでにぼかしフィルタ(blur)をかけた。

背景差分法は、単純に1度保存しておいたBitmapData(bgBmd)と現在の表示(nowBmd)を1ピクセルずつ比較して、差がある所だけ黒くしている。大体Processingの時と同じ。

var threshold:int = 30; // 影化のしきい値

labelThreshold.text = ”threshold: ” + threshold.toString();

var cam:Camera = Camera.getCamera();

cam.setMode(640, 480, 24, true); // 24fps

cam.setQuality(0, 100);

var camVideo:Video = new Video(200, 150); // bitmap計算用

camVideo.attachCamera(cam);

camDebug.attachCamera(cam); // デバッグ用の表示

var bgBmd:BitmapData = new BitmapData(camVideo.width, camVideo.height);

var nowBmd:BitmapData = new BitmapData(camVideo.width, camVideo.height);

var shadowBmd:BitmapData = new BitmapData(camVideo.width, camVideo.height);

// 結果表示用

var shadowBmp:Bitmap = new Bitmap(shadowBmd); // bmdを操作すると逐次bmpに反映される

shadowBmp.x = 400;

shadowBmp.width = 400;

shadowBmp.height = 300;

this.addChild(shadowBmp);

var blur:BlurFilter = new BlurFilter(); // ぼかしフィルタ

blur.blurX = 5;

blur.blurY = 5;

blur.quality = BitmapFilterQuality.MEDIUM;

shadowBmp.filters = [blur];

buttonSaveBg.addEventListener(MouseEvent.CLICK, saveBg);

function saveBg(e:Event){

    trace(”saveBg()”);

    bgBmd.draw(camVideo); // 背景再取得

}

function comparePixels(a:int, b:int, threshold:int):Boolean{

    var a_red:int = a>>16&0xFF;

    var b_red:int = b>>16&0xFF;

    var a_green:int = a>>8&0xFF;

    var b_green:int = b>>8&0xFF;

    var a_blue:int = a&0xFF;

    var b_blue:int = b&0xFF;

    if((a_red > b_red && a_red-b_red > threshold) || (a_red < b_red && b_red-a_red > threshold) ||

       (a_green > b_green && a_green-b_green > threshold) || (a_green < b_green && b_green-a_green > threshold) ||

       (a_blue > b_blue && a_blue-b_blue > threshold) || (a_blue < b_blue && b_blue-a_blue > threshold)

       ) return true; // 色に差がある時

    else return false; // 色に差が無い時

}

this.addEventListener(Event.ENTER_FRAME, reload); // 毎フレーム実行イベント

function reload(e:Event){

    // 背景差分法で変化のあったピクセルを検出、黒く塗りつぶす

    nowBmd.draw(camVideo);

    shadowBmd.lock(); // bitmap操作中は表示に反映させない

    for(var y:int = 0; y < bgBmd.height; y++){

        for(var x:int = 0; x < bgBmd.width; x++){

            if( comparePixels( bgBmd.getPixel(x, y), nowBmd.getPixel(x, y), threshold ) ){

                shadowBmd.setPixel(x, y, 0xFF000000);

            }

            else{

                shadowBmd.setPixel(x, y, 0xFFFFFF90);

            }

        }

    }

    shadowBmd.unlock();

}

buttonInc.addEventListener(MouseEvent.CLICK, 

                           function(){

                               if(threshold < 128) labelThreshold.text = "threshold: " + (++threshold).toString();

                           } );

buttonDec.addEventListener(MouseEvent.CLICK,

                           function(){

                               if(threshold > 0) labelThreshold.text = ”threshold: ” + (–threshold).toString();

                           } );

あとMath.abs()の動作がおかしくて、comparePixels()の所で使えなかったので長いif文になってしまった。

■参考

ActionScript3.0で動体検知 01 (Unknown Quality)

flashrod - AS3で画像処理入門(1)

flashrod - 2006-11-17

s.h.log: Proce55ingで背景差分法

タグ: , , , , ,

コメントをどうぞ