In case Flash no longer exists; a copy of this site is included in the Flashpoint archive's "ultimate" collection.

Dead Code Preservation :: Archived AS3 works from wonderfl.net

動体検知 高速化

まだまだ途中バージョン
* 作っている自分も良くわかってません。
* videoのサイズ大きいと負荷が高いのかPCのファンが高速回転汗
* 参考URL
* 動体検知:Flash8で動体検知
* http://faces.bascule.co.jp/motiondetection/
* bitmap操作関連:ActionScript 3.0 でラベリング (改)を勝手に添削
* http://void.heteml.jp/blog/archives/2007/10/as3_labeling.html

modified by utabi 2009.10.09
高速化させてみました。
thresholdが0xff111111ぐらいだと物体の動き向け、
thresholdが0xff222222ぐらいだとカメラが空間移動したとき向け
のような具合です。そこ変えると負荷かわります。
minimumSizeとmaximumSizeをかえることでも負荷がかわります。
Get Adobe Flash player
by utabi 09 Oct 2009
// forked from fumix's 動体検知
// forked from fumix's forked from: 動体検知
// forked from ll_koba_ll's 動体検知
// write as3 code here..
/***
 * まだまだ途中バージョン
 * 作っている自分も良くわかってません。
 * videoのサイズ大きいと負荷が高いのかPCのファンが高速回転汗
 * 参考URL
 * 動体検知:Flash8で動体検知
 * http://faces.bascule.co.jp/motiondetection/
 * bitmap操作関連:ActionScript 3.0 でラベリング (改)を勝手に添削
 * http://void.heteml.jp/blog/archives/2007/10/as3_labeling.html
***/
/*
	modified by utabi 2009.10.09
	高速化させてみました。
	thresholdが0xff111111ぐらいだと物体の動き向け、
	thresholdが0xff222222ぐらいだとカメラが空間移動したとき向け
	のような具合です。そこ変えると負荷かわります。
	minimumSizeとmaximumSizeをかえることでも負荷がかわります。
*/
package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.BlendMode;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.filters.ConvolutionFilter;
    import flash.geom.ColorTransform;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.media.Camera;
    import flash.media.Video;
    import flash.text.TextField;
	import net.hires.debug.*;
	
    [SWF(width = "465", height = "465", frameRate = "30",backgroundColor="0x000000")]
   
   public class MotionDetector extends Sprite
    {
        private var camera:Camera;
        private var video:Video;
        private var now:BitmapData;
        private var before:BitmapData;
        private var bmd:BitmapData;
        private var rect:Rectangle;
        private var pt:Point;
        private var gaussianFilter:ConvolutionFilter;
        private var noiseReduction:ConvolutionFilter;
        
		private var threshold:uint = 0xff111111;
		
        private var blockRect:Rectangle;
		private var blockArea:Rectangle;
		private var temp:BitmapData;
		private var recs:Vector.<Rectangle>;
		private var drawMap:BitmapData;
		private var br:Rectangle;
		private var dst:BitmapData;
		private var lno:int = 0;
		private var idx:int=0;
		private var idx_rec:Rectangle;
		private var tgt_rec:Rectangle;
		private var i:int;
		private const minimumSize:int = 10;
		private const maximumSize:int = 400;
        private var size:int = 465;
        
        public function MotionDetector()
        {
            super();
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);
        }
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            camera = Camera.getCamera();
            //カメラあり
            if(camera != null){
                setUpCamera();
            //カメラ無し
            }else{
                var txt:TextField = new TextField();
                txt.text ='カメラ無し';
                addChild(txt);
            }
            
            noiseReduction = new ConvolutionFilter(3, 3,[
                1,  2, 1,
                2,  4, 2,
                1,  2, 1
            ],52);
            bmd = new BitmapData(size,size/camera.width * camera.height,false,0x000000);
            addChild(new Bitmap(bmd));
			
            now = new BitmapData(size,size/camera.width * camera.height,false);
            before = new BitmapData(size,size/camera.width * camera.height,false);
            rect = new Rectangle(0, 0, size,size/camera.width * camera.height);
            pt = new Point(0,0);
			
			temp = new BitmapData(rect.width,1,false,0x000000);
			blockRect = new Rectangle(0,0,0,0);
			blockArea = new Rectangle(0,0,0,0);
			dst = new BitmapData(size,size/camera.width * camera.height,false);
			drawMap = new BitmapData(size,size/camera.width * camera.height,false);
			
			addChild(new Stats);
			addEventListener(Event.ENTER_FRAME,loop);
        }
        /**
         *カメラのセットアップ 
         * 
         */
        private function setUpCamera():void
        {
            camera.setMode(Math.floor(size/2), Math.floor(size/2), 30);
            video = new Video(size,size/camera.width * camera.height);
            video.attachCamera(camera);
            addChild(video);
        }
        private function loop(e:Event=null):void
        {
            now.draw(video);
            now.draw(before,new Matrix(), new ColorTransform(),BlendMode.DIFFERENCE);
			now.applyFilter(now, rect, pt, noiseReduction);
			now.threshold(now,rect,pt,">",threshold,0xffffffff);
            
			before.draw(video);
            
            //動体検知処理
            //参照:http://void.heteml.jp/blog/archives/2007/10/as3_labeling.html
            dst.copyPixels(now,rect,pt);
			
            //ブロック化
            blockRect = dst.getColorBoundsRect(0xffffff,0xffffff,true);
            blockArea = new Rectangle(0,0,dst.width,1);
            
            recs = new Vector.<Rectangle>();
			
            while( !blockRect.isEmpty()){
                
				blockArea.y = blockRect.top;
                temp.copyPixels(dst,blockArea,pt);
                blockRect = temp.getColorBoundsRect(0xffffff,0xffffff,true); //白いとこだけ取り出す
                dst.floodFill(blockRect.x,blockArea.y,0xff00ff); //左上から別の色で塗りつぶす
                br = dst.getColorBoundsRect(0xFFFFFF, 0xFF00FF); //塗りつぶれたとこだけ取り出す
                dst.fillRect(br, 0x0000ff); //取り出しおわったので、関係ない色にする
                blockRect = dst.getColorBoundsRect( 0xffffff, 0xffffff, true ); //blockRectを、brなしの状態で上書き
                
				if(br.width+br.height < maximumSize){ //大きすぎるのは拾わない
					if(br.width+br.height > minimumSize){ //小さすぎるのは拾わない
						recs.push(br);
					}
				}
				
            }
            //rectangleが重なってたら、同じものとみなして、数を絞る
            for(idx =0; idx < recs.length; idx++){
                idx_rec = recs[idx];
                
                for(i = idx+1; i<recs.length; i++){
                    tgt_rec = recs[i];
                    
					if( idx_rec!=tgt_rec && idx_rec.intersects(tgt_rec) ){

						recs.push(idx_rec.union(tgt_rec));
                        recs.splice(Number(i), 1);
                        recs.splice(Number(idx), 1);
                        idx --;
                        break;
						
                    }
                }
            }
			drawMap.draw(video);
			if(recs.length > 0){
            	
				recs.forEach(function(element:Rectangle, index:int, arr:Vector.<Rectangle>):void{
						
					drawMap.fillRect(element,0xff00ff00);

           		});
            
            }
			bmd.draw(drawMap);
        }
    }
}