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: forked from: [WebCam]エッジの方向

http://aquioux.blog48.fc2.com/blog-entry-680.html の内容を WebCam に適用したものです。

各種フィルタを使ったウェブカム画像の加工
@author YOSHIDA, Akio (Aquioux)
Get Adobe Flash player
by xzardaz 16 May 2013
    Embed
/**
 * Copyright xzardaz ( http://wonderfl.net/user/xzardaz )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/wLu7
 */

// forked from bezoomy's forked from: [WebCam]エッジの方向
// forked from Aquioux's [WebCam]エッジの方向
// http://aquioux.blog48.fc2.com/blog-entry-680.html の内容を WebCam に適用したものです。
package {
    import flash.display.Sprite;
    import flash.events.Event;
    /**
     * 各種フィルタを使ったウェブカム画像の加工
     * @author YOSHIDA, Akio (Aquioux)
     */
    [SWF(width = "465", height = "465", frameRate = "25", backgroundColor = "#FFFFFF")]
    
    public class Main extends Sprite {
        
        public function Main() {
            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);
            view.commands = model.commands;
            
            // 開始
            model.start();
        }
    }
}


    import flash.display.BitmapData;
    import flash.display.GraphicsPathCommand;
    import flash.display.Stage;
    import flash.events.Event;
    import flash.events.EventDispatcher;
    import flash.filters.ConvolutionFilter;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.media.Camera;
    import flash.media.Video;
    /**
     * Web Camera の映像にエフェクトをかける(MVC の Model)
     * エフェクトロジックは effector クラスとして外部で定義する
     * @author YOSHIDA, Akio (Aquioux)
     */
    class Model extends EventDispatcher {
        // --------------------------------------------------
        // 定数
        // --------------------------------------------------
        // 描画間隔
        private const INTERVAL:uint = 6;
        // エッジ検出の強さ
        private const DEPTH:Number = 5.0;

        
        // --------------------------------------------------
        // View へ渡すデータ(プロパティ)
        // --------------------------------------------------
        public function get commands():Vector.<int> { return _commands; }
        private var _commands:Vector.<int>;

        public function get data():Vector.<Number> { return _data; }
        private var _data:Vector.<Number>;

        
        // --------------------------------------------------
        // 外部との通信をおこなうメソッド
        // --------------------------------------------------
        /**
         * 対 View 用メソッド
         * このメソッドの終了時にイベントを発行するので、View との通信手段となる
         * @private
         */
        // ConvolutionFilter 用マトリクス
        private const HORISON_MATRIX:Array = [
            -1,     0, 1,
            -DEPTH, 0, DEPTH,
            -1,     0, 1
        ];
        private const VERTICAL_MATRIX:Array = [
            -1, -DEPTH, -1,
             0,  0,      0,
             1,  DEPTH,  1
        ];
        private const HORISON_FILTER:ConvolutionFilter  = new ConvolutionFilter(3, 3, HORISON_MATRIX);
        private const VERTICAL_FILTER:ConvolutionFilter = new ConvolutionFilter(3, 3, VERTICAL_MATRIX);
        private const ZERO_POINT:Point = new Point(0, 0);
        private function update():void {
            bmd.draw(video, matrix);    // ウェブカム映像取り込み
            grayscale.applyEffect(bmd);    // グレイスケール適用
            cloneBmd = bmd.clone();        // 複製
            // ConvolutionFilter 適用
            bmd.applyFilter(bmd, rect, ZERO_POINT, HORISON_FILTER);
            cloneBmd.applyFilter(cloneBmd, rect, ZERO_POINT, VERTICAL_FILTER);
            // 平滑化適用
            smoothing.applyEffect(bmd);
            smoothing.applyEffect(cloneBmd);
            
            // View 用データ data の決定
            var cnt:uint = 0;
            for (var i:int = 0; i < numY; i++) {
                for (var j:int = 0; j < numX; j++) {
                    var startX:uint = j * INTERVAL;
                    var startY:uint = i * INTERVAL;
                    var colorX:uint = bmd.getPixel(startX, startY);
                    var colorY:uint = cloneBmd.getPixel(startX, startY);
                    var xx:uint = colorX & 0xFF;
                    var yy:uint = colorY & 0xFF;
                    var radian:Number = Math.atan2(yy, xx);
                    var strength:Number = Math.sqrt(xx * xx + yy * yy);
                    var endX:Number = Math.cos(radian) * strength / INTERVAL + startX;
                    var endY:Number = Math.sin(radian) * strength / INTERVAL + startY;
                    _data[cnt * 4]     = startX;
                    _data[cnt * 4 + 1] = startY;
                    _data[cnt * 4 + 2] = endX;
                    _data[cnt * 4 + 3] = endY;
                    cnt++;
                }
            }
            
            dispatchEvent(new Event(Event.CHANGE));
        }
        
        // --------------------------------------------------
        // その他のメソッド
        // --------------------------------------------------
        /**
         * コンストラクタ
         * コンストラクタの引数はステージとする。各種データはアクセサーによって取り込むものとする
         * @param    stage    ステージ
         */
        private var stage:Stage;

        // カメラが表示するサイズ
        private var cameraWidth:uint;
        private var cameraHeight:uint;
        // カメラ
        private var camera:Camera;
        private var video:Video;
        private var bmd:BitmapData;
        private var cloneBmd:BitmapData;
        private var matrix:Matrix;
        private var rect:Rectangle;
        private var numX:uint;
        private var numY:uint;
        public function Model(stage:Stage, cw:Number = 0, ch:Number = 0) {
            this.stage = stage;
            this.cameraWidth  = (cw == 0) ? stage.stageWidth  : cw;
            this.cameraHeight = (ch == 0) ? stage.stageHeight : ch;
            
            bmd      = new BitmapData(cameraWidth, cameraHeight, false);
            cloneBmd = bmd.clone();
            matrix   = new Matrix( -1, 0, 0, 1, cameraWidth, 0);
            rect     = bmd.rect;
            
            numX = cameraWidth  / INTERVAL;
            numY = cameraHeight / INTERVAL;
            // View 用データの生成
            _commands = new Vector.<int>(numX * numY * 2, true);
            _data     = new Vector.<Number>(numX * numY * 4, true);
            // View 用データ commands の決定
            var n:uint = _commands.length / 2;
            for (var i:int = 0; i < n; i++) {
                _commands[i * 2]     = GraphicsPathCommand.MOVE_TO;
                _commands[i * 2 + 1] = GraphicsPathCommand.LINE_TO;
            }
            
            // カメラ
            camera = Camera.getCamera();
            if (camera) {
                // camera のセットアップ
                camera.setMode(cameraWidth, cameraHeight, stage.frameRate);
                // video のセットアップ
                video = new Video(cameraWidth, cameraHeight);
                video.attachCamera(camera);
            } else {
                throw new Error("カメラがありません。");
            }
        }
        
        /**
         * 処理開始
         */
        private var grayscale:EffectorGrayScale;
        private var smoothing:EffectorSmoothing;
        public function start():void {
            grayscale = new EffectorGrayScale();
            smoothing = new EffectorSmoothing();
            smoothing.strength = 8;
            stage.addEventListener(Event.ENTER_FRAME, enterFrameHandler);
        }
        /**
         * イベントハンドラ
         * @private
         */
        private function enterFrameHandler(event:Event):void {
            update();
        }
    }


    import flash.display.Graphics;
    import flash.display.GraphicsEndFill;
    import flash.display.GraphicsPath;
    import flash.display.GraphicsPathCommand;
    import flash.display.GraphicsSolidFill;
    import flash.display.GraphicsStroke;
    import flash.display.IGraphicsData;
    import flash.display.Sprite;
    import flash.events.Event;
    /**
     * Web Camera のスクリーン(MVC の View)
     * @author YOSHIDA, Akio (Aquioux)
     */
    class View extends Sprite {
        /**
         * コンストラクタ
         * @param    model    Model
         */
        private var model:Model;
        public function View(model:Model) {
            init();
            this.model = model;
            this.model.addEventListener(Event.CHANGE, changeHandler);
        }
        
        private var graphicsData:Vector.<IGraphicsData>;
        private var path:GraphicsPath;
        private function init():void{
            var stroke:GraphicsStroke = new GraphicsStroke();
            stroke.thickness = 0;
            stroke.fill = new GraphicsSolidFill(0x000000);

            var commands:Vector.<int> = new Vector.<int>();
            var data:Vector.<Number> = new Vector.<Number>();
            path = new GraphicsPath(commands, data);

            var endfill:GraphicsEndFill = new GraphicsEndFill();

            graphicsData = new Vector.<IGraphicsData>();
            graphicsData.push(stroke);
            graphicsData.push(path);
            graphicsData.push(endfill);
        }
        
        public function set commands(commands:Vector.<int>):void {
            path.commands = commands;
        }
        
        /**
         * Model との通信手段
         * @param    event    発生したイベント
         */
        private function changeHandler(event:Event):void {
            // Model からデータを受け取り、視覚化
            path.data = model.data;
            
            var g:Graphics = this.graphics;
            g.clear();
            g.drawGraphicsData(graphicsData);
        }
    }


    import flash.display.BitmapData;
    import flash.geom.Point;
    /**
     * BitmapData エフェクト用抽象クラス
     * @author YOSHIDA, Akio
     */
    class AbstractEffector {
        /*
         * BitmapData.applyFilter で destPoint として使用する Point オブジェクト
         */
        protected const ZERO_POINT:Point = new Point(0, 0);
        
        /*
         * コンストラクタ
         */
        public function AbstractEffector() {}
        
        /*
         * 効果の適用
         * @param    value    効果をかける BitmapData
         */
        public function applyEffect(value:BitmapData):BitmapData {
            return effect(value);
        }
        
        /*
         * 効果内容、具体的なコードはサブクラスで定義する
         * @param    value    効果をかける BitmapData
         */
        protected function effect(value:BitmapData):BitmapData {
            return value;
        }
    }


    import flash.display.BitmapData;
    import flash.filters.ColorMatrixFilter;
    /**
     * ColorMatrixFilter による BitmapData のグレイスケール化(NTSC 系加重平均による)
     * 参考:Foundation ActionScript 3.0 Image Effects(P106)
     *         http://www.amazon.co.jp/gp/product/1430218711?ie=UTF8&tag=laxcomplex-22
     * @author YOSHIDA, Akio (Aquioux)
     */
    class EffectorGrayScale extends AbstractEffector {
        // ColorMatrixFilter
        private const GRAYSCALE_MATRIX:Array = [
            0.3, 0.6, 0.1, 0, 0,
            0.3, 0.6, 0.1, 0, 0,
            0.3, 0.6, 0.1, 0, 0,
            0,   0,   0,   1, 0
        ];
        private const GRAYSCALE_FILTER:ColorMatrixFilter = new ColorMatrixFilter(GRAYSCALE_MATRIX);
        
        /*
         * グレイスケール実行
         * @param    value    効果をかける BitmapData
         */
        override protected function effect(value:BitmapData):BitmapData {
            value.applyFilter(value, value.rect, ZERO_POINT, GRAYSCALE_FILTER);
            return value;
        }
    }


    import flash.display.BitmapData;
    import flash.filters.BitmapFilterQuality;
    import flash.filters.BlurFilter;
    /**
     * BlurFilter による平滑化
     * @author YOSHIDA, Akio (Aquioux)
     */
    class EffectorSmoothing extends AbstractEffector {
        /*
         * ぼかしの量
         * @param    value    数値
         */
        public function set strength(value:Number):void {
            blurFilter.blurX = blurFilter.blurY = value;
        }
        /*
         * ぼかしの質
         * @param    value    数値
         */
        public function set quality(value:int):void {
            blurFilter.quality = value;
        }
        // ブラーフィルタ
        private var blurFilter:BlurFilter;
        public function EffectorSmoothing() {
            blurFilter = new BlurFilter(2, 2, BitmapFilterQuality.MEDIUM);
        }
        
        /*
         * 平滑化実行
         * @param    value    効果をかける BitmapData
         */
        override protected function effect(value:BitmapData):BitmapData {
            value.applyFilter(value, value.rect, ZERO_POINT, blurFilter);
            return value;
        }
    }