昨日Flash CS3を買ったので、さっそくAS3でやってみた。
自分で1からBitmapDataクラスを使うのは初めてだったけどprocessingやってたお陰ですぐわかった。
一旦カメラの前からどいて、Save Backgroundボタンを押してみてください
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で背景差分法
