Webカメラで光学迷彩

Webカメラを用いてなんちゃって光学迷彩です。
http://moeten.info/flex/20080419_cameraSabunHaikei/bin-release/main.html
動作ムービーはこちら
http://jp.youtube.com/watch?v=q6PThfLabPo

やり方は簡単で、背景をとりあえず作成して、現在のフレーム画像との差分を合成します。
背景の決め方ですが、背景は100フレームをバッファに保存しておいて変化量が少ないフレームを背景とみなしています。当然人物がカメラの前で静止すると背景として認識されちゃいます(汗
ついでにデスクトップの画面を動画としてキャプチャするソフトですが、「劇場版 ディスプレイキャプチャー あれ」ってソフトが便利です。
http://www.vector.co.jp/soft/win95/art/se221399.html?ds
ソースはこちら
合成のモードを用意していますので、それだけでも面白いと思います。

<?xml version="1.0" encoding="utf-8"?>
<mx:Application xmlns:mx="http://www.adobe.com/2006/mxml" layout="vertical" creationComplete="init()" backgroundGradientAlphas="[1.0, 1.0]" backgroundGradientColors="[#FFFFFF, #A0FFB4]" width="601" height="556" viewSourceURL="srcview/index.html">
<mx:Script>
<![CDATA[
import mx.collections.ArrayCollection;
private var camera:Camera;
//画像合成のモード
private var typeArr:Array = [
            {label:"add",data:"add"},
            {label:"alpha" , data:"alpha"},
            {label:"darken" , data:"darken"},
            {label:"difference" , data:"difference"},
            {label:"erase" , data:"erase"},
            {label:"hardlight" , data:"hardlight"},
            {label:"invert" , data:"invert"},
            {label:"layer" , data:"layer"},
            {label:"lighten" , data:"lighten"},
            {label:"multiply" , data:"multiply"},
            {label:"normal" , data:"normal"},
            {label:"overlay" , data:"overlay"},
            {label:"screen" , data:"screen"},
            {label:"subtract" , data:"subtract"}
            ];
//初期化関数
private function init():void{
    //カメラの設定
    camera = Camera.getCamera();
    if (camera != null) {
        camera.setQuality(0, 95);
        camera.setMode(640 , 480 , 15 , true );
        camera.setMotionLevel(0);
        camera.addEventListener(ActivityEvent.ACTIVITY, activityHandler);
        myFlv.attachCamera( camera );
    } else {
        trace("You need a camera.");
    }
}
//カメラアクティブイベント
private function activityHandler(e:ActivityEvent):void{
    setHaikei();
}
//背景を登録
private var bdHaikei:BitmapData;
private function setHaikei():void{
    bdHaikei = new BitmapData( myFlv.width , myFlv.height );
    bdHaikei.draw( myFlv );
    myImage4.source = new Bitmap( bdHaikei );
    this.addEventListener(Event.ENTER_FRAME , sabunStart );
}
//背景と現在のフレームの差分を表示
private var buffArr:Array = new Array();
private var buffArr2:Array = new Array();
private var cnt:int = 0;
private var j:int = 0;
private function sabunStart(e:Event):void{
    var bd:BitmapData = new BitmapData( myFlv.width , myFlv.height );
    bd.draw( myFlv );
    var bd5:BitmapData = new BitmapData( myFlv.width , myFlv.height );
    bd5.draw(myFlv);
    bd5.applyFilter( bd5 , bd5.rect , new Point() , myBlur );
    buffArr2[j] = bd5;
    if( buffArr2.length > 10 ){
        buffArr2[j-10].draw( buffArr2[j] , new Matrix(), new ColorTransform(), "difference" );
        //閾値の数を保存しておく
        buffArr[j] = buffArr2[j-10].threshold( buffArr2[j-10] , bd5.rect , new Point() , ">" , 0xff111111 , 0x33ffffff , 0x33ffffff );
        buffArr.shift();
        myImage7.source = new Bitmap( buffArr2[j-10]);
        if( buffArr.length > 100 ){
            //差分を計算する
            var sum:int = 0;
            cnt = 100;
            while( cnt ){
                sum += buffArr[j-cnt];
                cnt--;
            }
            //差分合計が少なかったら背景として認識させる
            if( sum < 100 ){
                //現在のフレームを背景に認識
                bdHaikei = new BitmapData( myFlv.width , myFlv.height );
                bdHaikei.draw( myFlv );
                myImage4.source = new Bitmap( bdHaikei );
            }
            buffArr.shift();
        }
    }
    j++;
    //画像の差分表示
    bd.draw( bdHaikei , new Matrix(), new ColorTransform(), "difference" );
    bd.applyFilter( bd , bd.rect , new Point() , myBlur );
//    buffArr.push( bd.threshold( bd , bd.rect , new Point() , ">" , 0xff333333 , 0x66ffffff ) );
    myImage5.source = new Bitmap( bd );
    //画像を合成して表示
    var bd2:BitmapData = new BitmapData( myFlv.width , myFlv.height );
    bd2.draw( myFlv );
    bd2.applyFilter( bd , bd.rect , new Point() , myBlur );
    bd2.draw( bdHaikei , new Matrix(), new ColorTransform(), myType.selectedItem.data );
    var bm:Bitmap = new Bitmap( bd2 );
    myImage6.source = bm;
}
]]>
</mx:Script>
<mx:BlurFilter id="myBlur" blurX="5" blurY="5" />
    <mx:Panel width="525" height="480" layout="absolute">
        <mx:Image id="myImage6" x="10" y="10" width="331.75" height="273"/>
        <mx:ComboBox id="myType" x="10" y="10" dataProvider="{typeArr}" rowCount="10" selectedIndex="3" width="124"/>
        <mx:VideoDisplay width="149.46451" height="115" id="myFlv" x="349.75" y="35"/>
        <mx:Label text="カメラ映像" x="349.75" y="10"/>
        <mx:Image id="myImage4" width="149.4" height="113" visible="true" x="349.75" y="170"/>
        <mx:Label text="背景認識" x="348.55" y="151"/>
        <mx:Image id="myImage5" width="149.45001" height="113" visible="true" x="192.3" y="317"/>
        <mx:Label text="背景 - 現在のフレーム" x="192.3" y="291"/>
        <mx:Image id="myImage7" width="149.45001" height="113" visible="true" x="9.95" y="317"/>
        <mx:Label text="現在のフレーム - 過去のフレーム" x="10" y="291"/>
    </mx:Panel>
</mx:Application>