// refer to http://opencv.jp/sample/accumulation_of_background.html package { import flash.display.*; import flash.events.*; import flash.filters.*; import flash.geom.*; import flash.media.*; import flash.net.*; import flash.text.*; //import com.flashdynamix.utils.SWFProfiler; [SWF(width="320", height="240", backgroundColor="#ffffff", frameRate="30")] public class Test extends Sprite { private const WIDTH:uint = 320; private const HEIGHT:uint = 240; private const PIXELS:uint = WIDTH * HEIGHT; private var camera:Camera; private var video:Video; private var bitmap:BitmapData = new BitmapData(WIDTH, HEIGHT, false, 0); private var object:BitmapData = new BitmapData(WIDTH, HEIGHT, true , 0); private var statistics1:Vector.<Number> = new Vector.<Number>(PIXELS, true); private var statistics2:Vector.<Number> = new Vector.<Number>(PIXELS, true); private var r1:Number = 0.02; private var r2:Number = 0.005; private var count:int = 0; private var shader:Sprite = new Sprite(); private var luminance:ColorMatrixFilter; private var erode:ConvolutionFilter; private var dilate:ConvolutionFilter; private var blur:BlurFilter; public function Test() { stage.scaleMode = "noScale"; stage.align = "TL"; //SWFProfiler.init(stage, this); camera = Camera.getCamera(); if (camera == null) return; camera.setMode(WIDTH, HEIGHT, 30); video = new Video(WIDTH, HEIGHT); video.attachCamera(camera); addChild(video); addChild(new Bitmap(object)); luminance = new ColorMatrixFilter([ 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0.3, 0.59, 0.11, 0, 0, 0, 0, 0, 0, 0 ]); erode = new ConvolutionFilter(3, 3); erode.bias = -(0xff0 + 0xff * 7); erode.matrix = [ 1, 1, 1, 1, 16, 1, 1, 1, 1 ]; dilate = new ConvolutionFilter(3, 3); dilate.matrix = [ 1, 1, 1, 1, 1, 1, 1, 1, 1 ]; blur = new BlurFilter(2, 2); if (camera.muted) { camera.addEventListener(StatusEvent.STATUS, function(e:StatusEvent):void { if (!camera.muted) start(); }); } else { start(); } } public function start():void { shader.graphics.beginFill(0x000000, 0.5); shader.graphics.drawRect(0, 0, WIDTH, HEIGHT); addChild(shader); var tf:TextField = new TextField(); tf.defaultTextFormat = new TextFormat("_sans", 18); tf.autoSize = "left"; tf.textColor = 0xffffff; tf.text = "initializing..."; tf.x = (WIDTH - tf.width) / 2; tf.y = (HEIGHT - tf.height) / 2; shader.addChild(tf); addChild(shader); addEventListener(Event.ENTER_FRAME, initialize); } public function initialize(e:Event):void { var frame:Vector.<uint> = getFrame(); var i:int = PIXELS; var x:Number, amplitude:Number; if (count < 50) { while (i--) statistics1[i] += frame[i] & 0xff; } else if (count == 50) { while (i--) statistics1[i] /= 50; } else if (count < 100) { while (i--) statistics2[i] += (x = (frame[i] & 0xff) - statistics1[i]) > 0 ? x : -x; } else { while (i--) statistics2[i] /= 50; removeChild(shader); removeEventListener(Event.ENTER_FRAME, initialize); addEventListener(Event.ENTER_FRAME, loop); } count++; } public function loop(e:Event):void { var frame:Vector.<uint> = getFrame(); var amplitude:Number; object.lock(); for (var i:int = 0; i < PIXELS; i++) { amplitude = (frame[i] & 0xff) - statistics1[i]; amplitude = amplitude > 0 ? amplitude : -amplitude; if (amplitude > 1.414 * statistics2[i] + 10) { statistics2[i] = (1 - r1) * statistics2[i] + r1 * amplitude; object.setPixel32(i % WIDTH, int(i / WIDTH), 0xff00ffff); } else { statistics1[i] = (1 - r2) * statistics1[i] + r2 * (frame[i] & 0xff); statistics2[i] = (1 - r2) * statistics2[i] + r2 * amplitude; object.setPixel32(i % WIDTH, int(i / WIDTH), 0x00000000); } } object.applyFilter(object, object.rect, new Point(), erode); object.applyFilter(object, object.rect, new Point(), dilate); object.applyFilter(object, object.rect, new Point(), blur); object.unlock(); } public function getFrame():Vector.<uint> { bitmap.draw(video); bitmap.applyFilter(bitmap, bitmap.rect, new Point(), luminance); return bitmap.getVector(bitmap.rect); } } } Accumulation of Background Statistics