昨日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の時と同じ。

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

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

varcam:Camera=Camera.getCamera();

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

cam.setQuality(0,100);

varcamVideo:Video=newVideo(200,150);//bitmap計算用

camVideo.attachCamera(cam);

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

varbgBmd:BitmapData=newBitmapData(camVideo.width,camVideo.height);

varnowBmd:BitmapData=newBitmapData(camVideo.width,camVideo.height);

varshadowBmd:BitmapData=newBitmapData(camVideo.width,camVideo.height);

//結果表示用

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

shadowBmp.x=400;

shadowBmp.width=400;

shadowBmp.height=300;

this.addChild(shadowBmp);

varblur:BlurFilter=newBlurFilter();//ぼかしフィルタ

blur.blurX=5;

blur.blurY=5;

blur.quality=BitmapFilterQuality.MEDIUM;

shadowBmp.filters=[blur];

buttonSaveBg.addEventListener(MouseEvent.CLICK,saveBg);

functionsaveBg(e:Event){

trace(“saveBg()”);

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

}

functioncomparePixels(a:int,b:int,threshold:int):Boolean{

vara_red:int=a>>16&0xFF;

varb_red:int=b>>16&0xFF;

vara_green:int=a>>8&0xFF;

varb_green:int=b>>8&0xFF;

vara_blue:int=a&0xFF;

varb_blue:int=b&0xFF;

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

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

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

)returntrue;//色に差がある時

elsereturnfalse;//色に差が無い時

}

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

functionreload(e:Event){

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

nowBmd.draw(camVideo);

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

for(vary:int=0;y
for(varx:int=0;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で背景差分法