Beautifl - Flash Gallery

Preview

自動新技術化アルゴリズムになる予定だった何か
beinteractive 2010年1月9日 MIT License
?
自動新技術化アルゴリズムになる予定だった何か.  
  
もう飽きたので誰か夢を叶えてください。  
  
- ステージクリックで画像ファイルを選択出来ます  
- 肌色以外のところをいい感じに隠してくれ (たらいいなぁ…) ます  
- 処理時間かかります
      package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.LoaderInfo;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.filters.BlurFilter;
    import flash.filters.ColorMatrixFilter;
    import flash.filters.GlowFilter;
    import flash.geom.Matrix;
    import flash.geom.Point;
    import flash.geom.Rectangle;
    import flash.net.FileReference;
    import flash.utils.ByteArray;
    import frocessing.color.ColorHSV;
    
    /**
     * 自動新技術化アルゴリズムになる予定だった何か.
     *
     * もう飽きたので誰か夢を叶えてください。
     *
     * - ステージクリックで画像ファイルを選択出来ます
     * - 肌色以外のところをいい感じに隠してくれ (たらいいなぁ…) ます
     * - 処理時間かかります
     */
    public class CheckmateFinal extends Sprite
    {
        //----------------------------------------
        // Constatns
        //----------------------------------------
        
        private static const YIQFILTER:ColorMatrixFilter = new ColorMatrixFilter([
            0.0, 0.0, 0.0, 0.0, 0.0,
            0.0, 0.0, 0.0, 0.0, 0.0,
            0.596, -0.274, -0.322, 0.0, 0.0,
            0.0, 0.0, 0.0, 1.0, 0.0
        ]);
        private static const BLURFILTER:BlurFilter = new BlurFilter(8, 8);
        private static const MASKBLURFILTER:BlurFilter = new BlurFilter(18, 18);
        
        private static const ZERO:Point = new Point(0, 0);
        
        private static const SKIN_THRESHOLD_MIN_I:uint = 20;
        private static const SKIN_THRESHOLD_MAX_I:uint = 65;
        
        private static const DIVIDE_MAX_LEVEL:uint = 7;
        
        //----------------------------------------
        // Constructor
        //----------------------------------------
        
        public function CheckmateFinal()
        {
            Wonderfl.capture_delay(20);
            setupBackground();
            setupEventHandler();
        }
        
        //----------------------------------------
        // Properties
        //----------------------------------------
        
        private var _file:FileReference;
        private var _displayBitmap:Bitmap;
        
        //----------------------------------------
        // Initializing
        //----------------------------------------
        
        private function setupBackground():void
        {
            var bg:Sprite = new Sprite();
            bg.graphics.beginFill(0xffffff);
            bg.graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
            bg.graphics.endFill();
            addChild(bg);
        }
        
        private function setupEventHandler():void
        {
            stage.addEventListener(MouseEvent.CLICK, stageClickHandler);
        }
        
        //----------------------------------------
        // Stage Event Handlers
        //----------------------------------------
        
        private function stageClickHandler(e:MouseEvent):void
        {
            selectImageFile();
        }
        
        //----------------------------------------
        // File Selection
        //----------------------------------------
        
        private function selectImageFile():void
        {
            _file = new FileReference();
            _file.addEventListener(Event.SELECT, fileSelectHandler);
            _file.browse();
        }
        
        //----------------------------------------
        // FileReference Event Handlers
        //----------------------------------------
        
        private function fileSelectHandler(e:Event):void
        {
            _file.addEventListener(Event.COMPLETE, fileLoadCompleteHandler);
            _file.load();
        }
        
        private function fileLoadCompleteHandler(e:Event):void
        {
            processImageData(_file.data);
            _file = null;
        }
        
        //----------------------------------------
        // Image Processing
        //----------------------------------------
        
        private function processImageData(bytes:ByteArray):void
        {
            var loader:Loader = new Loader();
            loader.contentLoaderInfo.addEventListener(Event.COMPLETE, imageDataLoadCompleteHandler);
            loader.loadBytes(bytes);
        }
        
        private function imageDataLoadCompleteHandler(e:Event):void
        {
            var loaderInfo:LoaderInfo = e.target as LoaderInfo;
            var matrix:Matrix = getScaleMatrixToFitStage(loaderInfo.width, loaderInfo.height);
            var image:BitmapData = new BitmapData(stage.stageWidth, stage.stageHeight, false, 0x000000);
            image.draw(loaderInfo.content, matrix);
            makeImaginationInterpolation(image);
            displayImage(image);
        }
        
        private function getScaleMatrixToFitStage(w:uint, h:uint):Matrix
        {
            var scale:Number = 1.0;
            
            if (w > stage.stageWidth || h > stage.stageHeight) {
                if (w > h) {
                    scale = stage.stageWidth / w;
                }
                else {
                    scale = stage.stageHeight / h;
                }
            }
            
            var x:Number = (stage.stageWidth - (w * scale)) / 2.0;
            var y:Number = (stage.stageHeight - (h * scale)) / 2.0;
            
            var matrix:Matrix = new Matrix();
            matrix.scale(scale, scale);
            matrix.translate(x, y);
            
            return matrix;
        }
        
        private function makeImaginationInterpolation(bitmapData:BitmapData):void
        {
            // Create working bitmapdata
            var aBitmapData:BitmapData = bitmapData.clone();
            
            // YIQ Convertion
            aBitmapData.applyFilter(aBitmapData, aBitmapData.rect, ZERO, YIQFILTER);
            aBitmapData.applyFilter(aBitmapData, aBitmapData.rect, ZERO, BLURFILTER);
            
            // Extract Skin Color
            aBitmapData.threshold(aBitmapData, aBitmapData.rect, ZERO, '>', SKIN_THRESHOLD_MAX_I, 0xff000000, 0x000000ff);
            aBitmapData.threshold(aBitmapData, aBitmapData.rect, ZERO, '<', SKIN_THRESHOLD_MIN_I, 0xff000000, 0x000000ff);
            aBitmapData.threshold(aBitmapData, aBitmapData.rect, ZERO, '!=', 0x000000, 0xffffffff, 0x00ffffff);
            
            // Reduce Noise
            aBitmapData.applyFilter(aBitmapData, aBitmapData.rect, ZERO, BLURFILTER);
            aBitmapData.threshold(aBitmapData, aBitmapData.rect, ZERO, '<', 0x555555, 0xff000000, 0x00ffffff);
            aBitmapData.threshold(aBitmapData, aBitmapData.rect, ZERO, '!=', 0x000000, 0xffffffff, 0x00ffffff);
            
            // Divide Image
            var dividedRects:Array = [];
            divideImage(aBitmapData, aBitmapData.clone(), aBitmapData.rect, 0, dividedRects);
            
            // Make mask
            var mask:Sprite = new Sprite();
            var color:uint = new ColorHSV(Math.random() * 360, 0.8, 0.8).value;
            var l:uint = dividedRects.length;
            mask.graphics.beginFill(color);
            for (var i:uint = 0; i < l; ++i) {
                var r:Rectangle = dividedRects[i];
                mask.graphics.drawRect(r.x, r.y, r.width, r.height);
            }
            mask.graphics.endFill();
            
            var maskBitmapData:BitmapData = new BitmapData(bitmapData.width,  bitmapData.height, true, 0x00000000);
            maskBitmapData.draw(mask);
            maskBitmapData.applyFilter(maskBitmapData, maskBitmapData.rect, ZERO, new GlowFilter(color, 1.0, 24, 24, 24));
            bitmapData.copyPixels(maskBitmapData, maskBitmapData.rect, ZERO, maskBitmapData, ZERO, true);
        }
        
        private function divideImage(bitmapData:BitmapData, tempBitmapData:BitmapData, rect:Rectangle, level:uint, dividedRects:Array):void
        {
            if (level >= DIVIDE_MAX_LEVEL) {
                return;
            }
            
            tempBitmapData.fillRect(tempBitmapData.rect, 0xff00ffff);
            tempBitmapData.copyPixels(bitmapData, rect, ZERO);
            
            var whiteBounds:Rectangle = tempBitmapData.getColorBoundsRect(0xffffff, 0xffffff);
            
            if (whiteBounds.isEmpty()) {
                if (rect.width <= stage.stageWidth / 8 && rect.height <= stage.stageHeight / 8) {
                    if (rect.width >= stage.stageWidth / 128 && rect.height >= stage.stageHeight / 128) {
                        dividedRects.push(rect);
                    }
                }
                return;
            }
            
            var blackBounds:Rectangle = tempBitmapData.getColorBoundsRect(0xffffff, 0x000000);
            
            if (blackBounds.isEmpty()) {
                return;
            }
            
            
            var x:Number = blackBounds.x + rect.x;
            var y:Number = blackBounds.y + rect.y;
            var w:Number = blackBounds.width / 2.0;
            var h:Number = blackBounds.height / 2.0;
            
            if (w < 1.0 || h < 1.0) {
                return;
            }
            
            var lv:uint = level + 1;
            
            divideImage(bitmapData, tempBitmapData, new Rectangle(x, y, w, h), lv, dividedRects);
            divideImage(bitmapData, tempBitmapData, new Rectangle(x + w, y, w, h), lv, dividedRects);
            divideImage(bitmapData, tempBitmapData, new Rectangle(x, y + h, w, h), lv, dividedRects);
            divideImage(bitmapData, tempBitmapData, new Rectangle(x + w, y + h, w, h), lv, dividedRects);
        }
        
        //----------------------------------------
        // Display
        //----------------------------------------
        
        private function displayImage(image:BitmapData):void
        {
            if (_displayBitmap == null) {
                _displayBitmap = addChild(new Bitmap(image)) as Bitmap;
            }
            else {
                _displayBitmap.bitmapData = image;
            }
        }
    }
}