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

forked from: [WebCam] NeonMan

[WebCam] NeonMan
@author Aquioux(Yoshida, Akio)
Get Adobe Flash player
by Cao 27 Apr 2011
/**
 * Copyright Cao ( http://wonderfl.net/user/Cao )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/hnWk
 */

// forked from Aquioux's [WebCam] NeonMan
package {
    import flash.display.Sprite;
    import net.hires.debug.Stats;
    [SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#FFFFFF")]
    /**
     * [WebCam] NeonMan
     * @author Aquioux(Yoshida, Akio)
     */
    public class Main extends Sprite {
        
        public function Main():void {
            Wonderfl.capture_delay(20);

            // model
            try {
                var model:Model = new Model(stage);
            } catch (err:Error) {
                trace(err.message);
                return;
            }
            
            // view
            var view:View = new View(model);
            addChild(view);
            
            // controller
            var controller:Controller = new Controller(model);
            addChild(controller);
            
            //addChild(new Stats());
        }
    }
}


    import flash.display.BitmapData;
    import flash.display.Stage;
    import flash.events.ActivityEvent;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.media.Camera;
    import flash.media.Video;
    /**
     * Model
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Model extends EventDispatcher {
        // ---------- パブリックプロパティ ----------
        //
        // View へ渡すデータ
        public function get data():BitmapData { return _data; }
        private var _data:BitmapData;

        
        // ---------- ローカルプロパティ ----------
        //
        private var stage_:Stage;
        private var cameraWidth_:uint;
        private var cameraHeight_:uint;
        private var camera_:Camera;
        private var video_:Video;
        private var matrix_:Matrix;

        // 各エフェクタ
        private var smooth_:Smooth;
        private var posterize_:Posterize;
        private var effector_:Effector;
        
        private const STRENGTH_MAX:uint = 16;
        private var ratio:uint;
        

        // ---------- パブリックメソッド ----------
        //
        /**
         * コンストラクタ
         * @param    stage    ステージ
         * @param    cw        カメラ幅(省略時はステージ幅)
         * @param    ch        カメラ高(省略時はステージ高)
         */
        public function Model(stage:Stage, cw:uint = 0, ch:uint = 0) {
            // 引数の処理
            stage_ = stage;
            var w:uint = stage_.stageWidth;
            var h:uint = stage_.stageHeight;
            cameraWidth_  = (cw == 0) ? w : cw;
            cameraHeight_ = (ch == 0) ? h : ch;

            // View へ渡すデータの生成
            _data = new BitmapData(w, h, true, 0x00000000);
            
            // 鏡像になるよう、Matrix で左右反転
            var tx:uint = (w - cameraWidth_)  / 2 + cameraWidth_;
            var ty:uint = (h - cameraHeight_) / 2;
            matrix_ = new Matrix( -1, 0, 0, 1, tx, ty);
            
            // カメラ準備
            camera_ = Camera.getCamera();
            if (camera_) {
                // camera のセットアップ
                camera_.setMode(cameraWidth_, cameraHeight_, stage_.frameRate);
                // video のセットアップ
                video_ = new Video(cameraWidth_, cameraHeight_);
                video_.attachCamera(camera_);
                // カメラがアクティブになるまで待つ
                camera_.addEventListener(ActivityEvent.ACTIVITY, activeHandler);
            } else {
                throw new Error("カメラがありません。");
            }
            
            ratio = w / (STRENGTH_MAX - 1);

            // エフェクタ
            smooth_ = new Smooth();
            smooth_.strength = 16;
            posterize_ = new Posterize();
            posterize_.degree = 2;
            effector_ = new Effector();
        }
        
        /**
         * isNegative_ の切り替え
         * Controller とのインターフェース
         */
        public function notifyFromController(value:Number):void {
            var strength:uint = value / ratio + 2;
            smooth_.strength = strength;
        }
        
        
        // ---------- ローカルメソッド ----------
        //
        // ACTIVITY イベントハンドラ
        private function activeHandler(e:ActivityEvent):void {
            camera_.removeEventListener(ActivityEvent.ACTIVITY, arguments.callee);
            stage_.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        // ENTER_FRAME イベントハンドラ
        private function enterFrameHandler(event:Event):void {
            _data.draw(video_, matrix_);
            
            smooth_.applyEffect(_data);        // 平滑化
            posterize_.applyEffect(_data);
            effector_.applyEffect(_data);

            dispatchEvent(new Event(Event.CHANGE));
        }
    }


    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.events.Event;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    /**
     * View
     * @author YOSHIDA, Akio (Aquioux)
     */
    class View extends Bitmap {
        // ---------- パブリックプロパティ ----------
        //
        // Model の参照
        public function set model(value:Model):void { _model = value; }
        private var _model:Model;
        
        
        // ---------- パブリックメソッド ----------
        //
        /**
         * コンストラクタ
         * @param    model    Model
         */
        public function View(model:Model) {
            _model = model;
            _model.addEventListener(Event.CHANGE, changeHandler);
        }
        

        // ---------- ローカルメソッド ----------
        //
        // Model から Event.CHANGE が発行されたときの処理
        private function changeHandler(e:Event):void {
            bitmapData = _model.data;
        }
    }


    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.KeyboardEvent;
    import flash.events.MouseEvent;
    /**
     * Controller
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Controller extends Sprite {
        // ---------- パブリックプロパティ ----------
        //
        // Model の参照
        public function set model(value:Model):void { _model = value; }
        private var _model:Model;
        

        // ---------- パブリックメソッド ----------
        //
        /**
         * コンストラクタ
         * @param    model    Model
         */
        public function Controller(model:Model) {
            _model = model;
            addEventListener(Event.ADDED_TO_STAGE, addToStageHandler);
        }
        

        // ---------- ローカルメソッド ----------
        //
        // イベントハンドラ
        // 自分がステージに登録されたとき
        private function addToStageHandler(e:Event):void {
            removeEventListener(Event.ADDED_TO_STAGE, arguments.callee);
            stage.addEventListener(MouseEvent.MOUSE_MOVE, moveHandler);
        }
        
        // イベントハンドラ
        private function moveHandler(e:MouseEvent):void {
            _model.notifyFromController(mouseX);
        }
    }




    import flash.display.BitmapData;
    /**
     * BitmapDataEffector 用 interface
     * @author YOSHIDA, Akio (Aquioux)
     */
    interface IEffector {
        function applyEffect(value:BitmapData):BitmapData;
    }


    import flash.geom.Point;
    /**
     * bitmapDataEffector パッケージ内のクラスで共通に使う定数など
     * @author YOSHIDA, Akio (Aquioux)
     */
    class EffectorUtils {
        // ---------- パブリックプロパティ ----------
        //
        // BitmapData が備える各種メソッドの destPoint 用
        static public const ZERO_POINT:Point = new Point(0, 0);

        
        // ---------- パブリックメソッド ----------
        //
        // 一つのチャンネルにおける濃度の平均値を求める(引数のヒストグラムで調整する)
        static public function getAverageOfBrightness1(hist:Vector.<Number>):uint {
            var sum:uint = 0;
            var numOfPixel:uint = 0;
            for (var i:int = 0; i < 256; i++) {
                sum        += i * hist[i];
                numOfPixel += hist[i];
            }
            return sum / numOfPixel >> 0;
        }
        // RGB チャンネルにおける濃度の各平均値を求める
        static public function getAverageOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
            var rSum:uint = 0;
            var gSum:uint = 0;
            var bSum:uint = 0;
            var numOfPixel:uint = 0;
            for (var i:int = 0; i < 256; i++) {
                rSum += i * hist[0][i];
                gSum += i * hist[1][i];
                bSum += i * hist[2][i];
                numOfPixel += hist[0];
            }
            return Vector.<uint>([rSum / numOfPixel >> 0, gSum / numOfPixel >> 0, bSum / numOfPixel >> 0]);
        }
        
        // 一つのチャンネルにおける濃度の平均値を求める(引数のヒストグラムで調整する)
        static public function getSumOfBrightness1(hist:Vector.<Number>):uint {
            var sum:uint = 0;
            for (var i:int = 0; i < 256; i++) {
                sum += i * hist[i];
            }
            return sum;
        }
        // RGB チャンネルにおける濃度の各平均値を求める
        static public function getSumOfBrightness3(hist:Vector.<Vector.<Number>>):Vector.<uint> {
            var rSum:uint = 0;
            var gSum:uint = 0;
            var bSum:uint = 0;
            for (var i:int = 0; i < 256; i++) {
                rSum += i * hist[0][i];
                gSum += i * hist[1][i];
                bSum += i * hist[2][i];
            }
            return Vector.<uint>([rSum, gSum, bSum]);
        }
    }


    import flash.display.BitmapData;
    import flash.display.BitmapDataChannel;
    import flash.filters.ConvolutionFilter;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    /**
     * 今回のメインエフェクタ
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Effector implements IEffector {
        // ---------- ローカルプロパティ ----------
        //
        private var bufferBmd_:BitmapData;
        private var rBmd_:BitmapData;
        private var gBmd_:BitmapData;
        private var bBmd_:BitmapData;
        
        private var rect_:Rectangle;
        
        private var edge_:Edge2 = new Edge2();
        
        private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;
        

        
        // ---------- パブリックメソッド ----------
        //
        /*
         * 効果適用
         * @param    value    効果対象 BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            if (!rBmd_) {
                rBmd_ = new BitmapData(value.width, value.height, false, 0x000000);
                gBmd_ = rBmd_.clone();
                bBmd_ = rBmd_.clone();
                rect_ = value.rect;
            }
            
            rBmd_.copyChannel(value, rect_, ZERO_POINT, BitmapDataChannel.RED, BitmapDataChannel.RED);
            gBmd_.copyChannel(value, rect_, ZERO_POINT, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            bBmd_.copyChannel(value, rect_, ZERO_POINT, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            edge_.applyEffect(rBmd_);
            edge_.applyEffect(gBmd_);
            edge_.applyEffect(bBmd_);

            value.fillRect(value.rect, 0xFF000000);
            
            value.copyChannel(rBmd_, rBmd_.rect, ZERO_POINT, BitmapDataChannel.RED, BitmapDataChannel.RED);
            value.copyChannel(gBmd_, gBmd_.rect, ZERO_POINT, BitmapDataChannel.GREEN, BitmapDataChannel.GREEN);
            value.copyChannel(bBmd_, bBmd_.rect, ZERO_POINT, BitmapDataChannel.BLUE, BitmapDataChannel.BLUE);
            
            return value;
        }
    }


    import flash.display.BitmapData;
    import flash.filters.BitmapFilterQuality;
    import flash.filters.BlurFilter;
    import flash.geom.Point;
    /**
     * BlurFilter による平滑化
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Smooth implements IEffector {
        // ---------- パブリックプロパティ ----------
        //
        /*
         * ぼかしの強さ
         * @param    value    数値
         */
        public function set strength(value:Number):void {
            filter_.blurX = filter_.blurY = value;
        }
        /*
         * ぼかしの質
         * @param    value    数値
         */
        public function set quality(value:int):void {
            filter_.quality = value;
        }


        // ---------- ローカルプロパティ ----------
        //
        private var filter_:BlurFilter;        // ブラーフィルタ
        private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;


        // ---------- パブリックメソッド ----------
        //
        /*
         * コンストラクタ
         */
        public function Smooth() {
            filter_ = new BlurFilter(2, 2, BitmapFilterQuality.MEDIUM);
        }
        
        /*
         * 効果適用
         * @param    value    効果対象 BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            value.applyFilter(value, value.rect, ZERO_POINT, filter_);
            return value;
        }
    }


    import flash.display.BitmapData;
    import flash.geom.Point;
    /**
     * paletteMap による BitmapData の減色
     * 参考:「実践画像処理入門」 培風館 内村圭一・上瀧剛 P16 「2.5 濃度値の量子化による減色処理」
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Posterize implements IEffector {
        // ---------- パブリックプロパティ ----------
        //
        /*
         * 減色の段階
         * @param    value    段階
         */
        public function set degree(value:uint):void {
            // value の有効範囲は 2 ~ 256
            if (value <   2) value =   2;
            if (value > 256) value = 256;

            for (var i:int = 0; i < 256; i++) {
                var val:uint = uint(i / (256 / value)) * 255 / (value - 1);
                rArray_[i] = val << 16;
                gArray_[i] = val <<  8;
                bArray_[i] = val;
            }
        }


        // ---------- ローカルプロパティ ----------
        //
        // paletteMap の引数となる各 Channel 用の Array
        private var rArray_:Array = [];
        private var gArray_:Array = [];
        private var bArray_:Array = [];

        private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;

        
        // ---------- パブリックメソッド ----------
        //
        /*
         * コンストラクタ
         */
        public function Posterize() {
            degree = 8;    // degree のデフォルト
        }
        
        /*
         * 効果適用
         * @param    value    効果対象 BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            value.paletteMap(value, value.rect, ZERO_POINT, rArray_, gArray_, bArray_);
            return value;
        }
    }


    import flash.display.BitmapData;
    import flash.filters.ConvolutionFilter;
    import flash.geom.Point;
    /**
     * ConvolutionFilter によるエッジ検出 2次微分
     * 「OpenGL+GLSLによる画像処理プログラミング」 工学社 酒井幸市 P104 「5.1 差分フィルタ」
     * 「C言語で学ぶ実践画像処理」 オーム社 井上誠喜・他 P47 「4.7 ラプラシアンとゼロ交差により輪郭線を求める」
     * http://msdn.microsoft.com/ja-jp/academic/cc998604.aspx
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Edge2 implements IEffector {
        // ---------- ローカルプロパティ ----------
        //
        private const MATRIX:Array = [
            -1, -1, -1,
            -1,  8, -1,
            -1, -1, -1
        ];
        private const FILTER:ConvolutionFilter = new ConvolutionFilter(3, 3, MATRIX);

        private const ZERO_POINT:Point = EffectorUtils.ZERO_POINT;

        
        // ---------- パブリックメソッド ----------
        //
        /*
         * 効果適用
         * @param    value    効果対象 BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            value.applyFilter(value, value.rect, ZERO_POINT, FILTER);
            return value;
        }
    }