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

役に立たない動体検知時計

動体検知のアルゴリズムを採り入れてみた時計です。

カメラに映った人の動きに反応して時計を表示します。

表示された時計は、人の動作に合わせて向きが変化したり
大きさが変化したりします。というか、するはずです。
たぶん、すると思います。まちょっと覚悟はしておけ。

カメラの前を右へ左へと通り過ぎてみたりして、時計が
反応してくれることを期待しながら試してみて下さい。
/**
 * Copyright mousepancyo ( http://wonderfl.net/user/mousepancyo )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/4rGk
 */

// forked from Event's Human Clock

/*
動体検知のアルゴリズムを採り入れてみた時計です。

カメラに映った人の動きに反応して時計を表示します。

表示された時計は、人の動作に合わせて向きが変化したり
大きさが変化したりします。というか、するはずです。
たぶん、すると思います。まちょっと覚悟はしておけ。

カメラの前を右へ左へと通り過ぎてみたりして、時計が
反応してくれることを期待しながら試してみて下さい。
*/

package {
    import flash.display.StageScaleMode;
    import flash.display.StageAlign;
    import flash.events.Event;
    import flash.events.TimerEvent;
    import flash.utils.Timer;
    import flash.display.Graphics;
    import flash.display.Shape;
    import flash.display.Sprite;
    import flash.geom.Point;
    import fl.motion.easing.*;
    import com.flashdynamix.motion.*;
    
    [SWF(width=465, height=465, backgroundColor=0xFFFFFF, frameRate=30)]
    
    public class HumanClock extends Sprite {
        private var _timer:Timer
        
        private var _container:Sprite
        private var _sec:int;
        private var _motions:MotionDetection;
        
        private var _hPanelList:Vector.<TimePanel> = new Vector.<TimePanel>()
        private var _hXList:Vector.<Number> = new Vector.<Number>();
        private var _hYList:Vector.<Number> = new Vector.<Number>();
        private var _hZList:Vector.<Number> = new Vector.<Number>();
        private var _hSizeList:Vector.<Number> = new Vector.<Number>();
        private var _mPanelList:Vector.<TimePanel> = new Vector.<TimePanel>()
        private var _mXList:Vector.<Number> = new Vector.<Number>();
        private var _mYList:Vector.<Number> = new Vector.<Number>();
        private var _mZList:Vector.<Number> = new Vector.<Number>();
        private var _mSizeList:Vector.<Number> = new Vector.<Number>();
        private var _sPanelList:Vector.<TimePanel> = new Vector.<TimePanel>()
        private var _sXList:Vector.<Number> = new Vector.<Number>();
        private var _sYList:Vector.<Number> = new Vector.<Number>();
        private var _sZList:Vector.<Number> = new Vector.<Number>();
        private var _sSizeList:Vector.<Number> = new Vector.<Number>();
        
        private var _offsetH:int = -100
        private var _offsetM:int  = 0
        private var _offsetS:int  = 100
        
        private var _oldx:Number = 0
        private var _oldy:Number = 0
        private var _oldSize:Number = 1
        private var _motionX_flg:String
        private var _motionY_flg:String
        private var _motionSize_flg:String
        private var _motionCount:int = 30
        private var _tween:TweensyGroup;
        
        private const _rad: Number = 250;
        private const _grovalZ: Number = 150;
        private const _centerZ: Number = 380;
                
        public function HumanClock() {
            initView()
        }
        
        private function initView():void {
            stage.align = StageAlign.TOP_LEFT;
            stage.scaleMode = StageScaleMode.NO_SCALE;
            //
            _motions = new MotionDetection(stage.stageWidth, stage.stageHeight)
            addChild(_motions)
            //
            _container = new Sprite();
            _container.x = this.stage.stageWidth/2;
              _container.y = this.stage.stageHeight/2;
              addChild(_container);
            _container.visible = false
            //
            createClock(_hPanelList, _hXList, _hYList, _hZList, _hSizeList, 24, _offsetH)
            createClock(_mPanelList, _mXList, _mYList, _mZList, _mSizeList, 60, _offsetM)
            createClock(_sPanelList, _sXList, _sYList, _sZList, _sSizeList, 60, _offsetS)
            //
            clockStart()
            //
            _motions.addEventListener(MotionDetection.CAM_DEACTIVE, camDeactive)
        }
        
        private function clockStart():void{
            _timer = new Timer(50);
            _timer.addEventListener(TimerEvent.TIMER, onTimer);
            _timer.start();
        }
        
        private function onTimer(e:TimerEvent):void {
            var time:Date = new Date;
            var hour:int = time.getHours();
            var min:int = time.getMinutes();
            var sec:int = time.getSeconds();
            var nx:Number = 0
            var ny:Number = 0
            var ns:Number = 0
            //
                
            if(_motions.getPosition().length != 0 && _motionX_flg == "" && _motionY_flg == ""){
                //_container.visible = true
                if(_tween == null) showObj(_container, 1.5)
                //
                for(var i:int=0; i<_motions.getPosition().length; i++){
                    nx += _motions.getPosition()[i].x
                    ny += _motions.getPosition()[i].y
                    ns += _motions.getPosition()[i].width * _motions.getPosition()[i].height
                }
                if(nx/_motions.getPosition().length < _oldx){
                    _motionX_flg = "left"
                }else{
                    _motionX_flg = "right"
                }
                if(ny/_motions.getPosition().length < _oldy){
                    _motionY_flg = "top"
                }else{
                    _motionY_flg = "bottom"
                }
                if(ns/_motions.getPosition().length < _oldSize){
                    _motionSize_flg = "small"
                }else{
                    _motionSize_flg = "large"
                }
                addEventListener(Event.ENTER_FRAME, movedClock)
                _oldx = nx/_motions.getPosition().length
                _oldy = ny/_motions.getPosition().length
                _oldSize = ns/_motions.getPosition().length
            }else{
                _motionX_flg = ""
                _motionY_flg = ""
            }
            //
               updateView(hour, min, sec);
        }
        
        private function updateView(h:int, m:int, s:int):void {
            updateClock(_hPanelList, _hXList, _hYList, _hZList, _hSizeList, 24, h)
            updateClock(_mPanelList, _mXList, _mYList, _mZList, _mSizeList, 60, m)
            updateClock(_sPanelList, _sXList, _sYList, _sZList, _sSizeList, 60, s)
        }
        
        //created clock init view
        private function createClock(panelList:Vector.<TimePanel>, xList:Vector.<Number>, yList:Vector.<Number>, zList:Vector.<Number>, sizeList:Vector.<Number>, count:int, offset:int):void{
            for(var i:Number = 0; i < count; i++){
                panelList.push(new TimePanel());
                if(i < 10){
                    panelList[panelList.length-1].tx.text = "0"+i.toString();
                }else {
                    panelList[panelList.length-1].tx.text = i.toString();
                }
                _container.addChild(panelList[panelList.length-1]);
                xList.push(offset);
                yList.push(0);
                zList.push(0);
                sizeList.push(1);
            }
        }
        
        //update clock view
        private function updateClock(panelList:Vector.<TimePanel>, xList:Vector.<Number>, yList:Vector.<Number>, zList:Vector.<Number>, sizeList:Vector.<Number>, count:int, time:int):void{
            for(var i:Number = 0; i < count; i++){
                var angle:Number = (time/count * Math.PI * 2 - i/count * Math.PI * 2);
                var py:Number = _rad*Math.sin(angle);
                var pz:Number = _centerZ - _rad*Math.cos(angle);
                yList[i] += (py - yList[i])/4;
                zList[i] += (pz - zList[i])/4;
                if(i == time){
                    sizeList[i] += (4 - sizeList[i])/4;
                }else{
                    sizeList[i] += (1 - sizeList[i])/4;
                }
                panelList[i].x = xList[i] * _grovalZ/zList[i];
                panelList[i].y = yList[i] * _grovalZ/zList[i];
                panelList[i].scaleX = sizeList[i] * _grovalZ/zList[i];
                panelList[i].scaleY = sizeList[i] * _grovalZ/zList[i];
            }
        }
        
        //moved clock view
        private function movedClock(e:Event):void{
            var i:int
            _motionCount--
            if(_motionCount > 0){
                if(_motionX_flg == "right"){
                    for(i=0; i<_hXList.length; i++){
                        _hXList[i] -=15
                    }
                    for(i=0; i<_mXList.length; i++){
                        _mXList[i] -=15
                        _sXList[i] -=15
                    }
                }else if(_motionX_flg == "left"){
                    for(i=0; i<_hXList.length; i++){
                        _hXList[i] +=15
                    }
                    for(i=0; i<_mXList.length; i++){
                        _mXList[i] +=15
                        _sXList[i] +=15
                    }
                }
                if(_motionY_flg == "top"){
                    _container.rotationX += 2
                }else if(_motionY_flg == "bottom"){
                    _container.rotationX -= 2
                }
                if(_motionY_flg == "large"){
                    _container.scaleX += 0.1
                    _container.scaleY += 0.1
                }else if(_motionY_flg == "small"){
                    _container.scaleX -= 0.1
                    _container.scaleY -= 0.1
                }
            }else{
                removeEventListener(Event.ENTER_FRAME, movedClock)
                _motionX_flg = ""
                _motionY_flg = ""
                _motionCount = 30
            }
        }
        
        private function camDeactive(e:Event):void{
            if(_tween == null) hideObj(_container, 1.5)
            removeEventListener(Event.ENTER_FRAME, movedClock)
        }
        
        private function initClock():void{
            for(var i:int=0; i<_hXList.length; i++){
                    _hXList[i] = -100
            }
            for(i=0; i<_mXList.length; i++){
                _mXList[i] = 0
                _sXList[i] = 100
            }
            _container.rotationX = 0
            _container.scaleX = 1
            _container.scaleY = 1
        }
        
        //tween
        public function tween(sp:Sprite, time:Number, xPos:Number, yPos:Number=0, delay:Number=0):void{
            _tween = new TweensyGroup();
            _tween.to(sp, {x:xPos, y:yPos}, time, Linear.easeInOut, delay);
            _tween.onComplete = memoryClear;
            function memoryClear():void{
                _tween.dispose();
                _tween = null;
            }
        }
        
        private function showObj(sp:Sprite, time:Number, delay:Number=0):void{
            _tween = new TweensyGroup();
            sp.visible = true
            _tween.to(sp, {alpha:1}, time, null, delay);
            //
            _tween.onComplete = memoryClear;
            function memoryClear():void{
                _tween.dispose();
                _tween = null;
            }
        }
        
        private function hideObj(sp:Sprite, time:Number, delay:Number=0):void{
            _tween = new TweensyGroup();
            _tween.to(sp, {alpha:0}, time, null, delay);
            _tween.onComplete = memoryClear;
            function memoryClear():void{
                initClock()
                sp.visible = false
                _tween.dispose();
                _tween = null;
            }
        }
    }
}

// class TimePanel
import flash.display.Sprite;
import flash.display.Shape;
import flash.text.TextField;
import flash.text.TextFormat;

class TimePanel extends Sprite{
    private var _tx:TextField = new TextField()
    private var _fmt:TextFormat = new TextFormat("_typewriter", 18, 0xFFFFFF, true, false, false, null, null, "center", null, null, null, 2)
    
    public function TimePanel(){
        var size:int = 30
        var shape:Shape = new Shape()
        shape.graphics.beginFill(0, 0)
        shape.graphics.drawRect(-size/2, -size/2, size, size)
        shape.graphics.endFill()
        //
        _tx.defaultTextFormat = _fmt
        _tx.selectable = false
        _tx.width = size
        _tx.height = size
        _tx.x = -size/2
        _tx.y = -size/3
        //
        addChild(shape)
        addChild(_tx)
    }
    
    public function get tx():TextField{
        return _tx;
    }
    
}


// class MotionDetection
// 動体検知のアルゴリズム参考:http://faces.bascule.co.jp/motiondetection/
import flash.display.Sprite;
import flash.display.BitmapData;
import flash.display.Bitmap;
import flash.display.BlendMode;
import flash.display.DisplayObject;
import flash.display.Shape;
import flash.events.Event;
import flash.events.ActivityEvent;
import flash.geom.ColorTransform;
import flash.geom.Rectangle;
import flash.geom.Point;
import flash.geom.Matrix;
import flash.filters.ConvolutionFilter;
import flash.media.Camera;
import flash.media.Video;

class MotionDetection extends Sprite {
    
    private var _w:int
    private var _h:int
    //
    private var _camera:Camera;
    private var _video:Video;
    private var _bmd:BitmapData;
    private var _bm:Bitmap;
    //
    private var _currentBmd:BitmapData;
    private var _beforeBmd:BitmapData;
    private var _rect:Rectangle;
    private var _mRect:Rectangle;
    private var _pt:Point;
    //
    private var _threshold:uint = 0xFF555555;
    private var _noiseReduction:ConvolutionFilter;
    private var _noize_min_pix:uint = 0;
    private var _inflateVar:uint = 10
    private var _rects:Array = new Array();
    //
    public static const CAM_ACTIVE:String = "cam_active"
    public static const CAM_DEACTIVE:String = "cam_deactive"

    public function MotionDetection(w:int, h:int):void {
        _w = w
        _h = h
        init();
    }

    private function init():void {
        _camera = Camera.getCamera();
        _camera.setMode(_w, _h, 15);
        if (_camera != null) {
            setupCamera();
            _camera.addEventListener(ActivityEvent.ACTIVITY, CamActivityHandler);
        }
        _bmd = new BitmapData(_w, _h ,false, 0xffffff);
        _bm = new Bitmap(_bmd);
        var dObj:DisplayObject = addChild(_bm);
        dObj.x = _w;
        //
        _currentBmd = new BitmapData(_w, _h);
        _beforeBmd = new BitmapData(_w, _h);
        _rect = new Rectangle(0, 0, _w, _h);
        _pt = new Point(0,0);
        //
        _noiseReduction = new ConvolutionFilter();
        _noiseReduction.matrixX = 3;
        _noiseReduction.matrixY = 3;
        _noiseReduction.matrix = [
        1, 1, 1,
        1, 0, 1,
        1, 1, 1
        ];
        _noiseReduction.bias = -0x100 * _noize_min_pix;
    }


    private function setupCamera():void {
        _video = new Video(_w, _h);
        _video.attachCamera(_camera);
        _video.scaleX = -1;
        _video.x = _w;
        addChild(_video);
    }

    private function CamActivityHandler(e:ActivityEvent):void {
        if (_camera.activityLevel > 30) {
            dispatchEvent(new Event(MotionDetection.CAM_ACTIVE))
            addEventListener(Event.ENTER_FRAME, update);
        } else {
            dispatchEvent(new Event(MotionDetection.CAM_DEACTIVE))
            removeEventListener(Event.ENTER_FRAME, update);
        }
    }


    private function update(e:Event):void {
        make2tone();
        rectForBlock();
    }

    private function make2tone():void {
        _currentBmd.fillRect(_rect, 0xFFFFFFFF);
        _currentBmd.draw(_video);
        _currentBmd.draw(_beforeBmd, new Matrix(), new ColorTransform(), BlendMode.DIFFERENCE);
        //
        _currentBmd.threshold(_currentBmd, _rect, _pt, "<", _threshold, 0xFF000000);
        _currentBmd.threshold(_currentBmd, _rect, _pt, "!=", 0xFF000000, 0xFFFFFFFF);
        //
        var _bm_noise:BitmapData = _currentBmd.clone();
        _bm_noise.applyFilter(_bm_noise, _rect, _pt, _noiseReduction);
        _currentBmd.threshold(_bm_noise, _rect, _pt, "==", 0xff000000, 0xff000000, 0xFF);
        //
        _beforeBmd.draw(_video);
        //    
        _bmd.draw(_currentBmd);
        _mRect = _bmd.getColorBoundsRect(0xffffff,0xffffff,true);
    }

    private function rectForBlock():void {
        _rects = new Array();
        while (true) {
        var wbr:Rectangle = _bmd.getColorBoundsRect(0xFFFFFF,0xFFFFFF);
        if (wbr.isEmpty()) {
            break;
        }
        var x:Number = wbr.x;
        for (var y:Number = wbr.y + wbr.height - 1; y >= wbr.y; --y) {
            if (_bmd.getPixel(x,y) == 0xFFFFFF) {
                _bmd.floodFill(x, y, 0xFF00FF);
                var br:Rectangle = _bmd.getColorBoundsRect(0xFFFFFF,0xFF00FF);
                br.inflate(_inflateVar,_inflateVar);
                _bmd.fillRect(br,0x0000FF);
                _rects.push(br);
                break;
                }
            }
        }
        for (var idx:uint=0; idx<_rects.length; idx++) {
            var idx_rec:Rectangle = _rects[idx];
            for (var i:uint=idx+1; i<_rects.length; i++) {
                var tgt_rec:Rectangle = _rects[i];
                if (idx_rec != tgt_rec && idx_rec.intersects(tgt_rec)) {
                    _rects.push(idx_rec.union(tgt_rec));
                    _rects.splice(Number(i), 1);
                    _rects.splice(Number(idx), 1);
                    idx--;
                    break;
                }
            }
        }
    }
    
    public function getPosition():Vector.<Rectangle> {
        var rtList:Vector.<Rectangle> = new Vector.<Rectangle>()
        if (_rects.length >= 1) {
            for (var n:uint=0; n<_rects.length; n++) {
                rtList.push(_rects[n])
            }
        }
        return rtList
    }
}