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

エッジ保存平均化(ちょっと重いです)

Flickrから猫の画像をとってきて、それを絵画調にしてます(画像はランダム)。
画像は350×350に整形してるからつぶれるのもあるかも。
エッジ保存平均化というもので、kuwaharaという手法を利用しています。
最初のほうは画像を取りに行ってるので真っ暗です。
スペックによってはかなり重いかもしれません。

クリックで元の画像と入れ替わります。
Get Adobe Flash player
by sakef 07 Oct 2010
/**
 * Copyright sakef ( http://wonderfl.net/user/sakef )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/jxZu
 */

/*
    Flickrから猫の画像をとってきて、それを絵画調にしてます(画像はランダム)。
    画像は350×350に整形してるからつぶれるのもあるかも。
    エッジ保存平均化というもので、kuwaharaという手法を利用しています。
    最初のほうは画像を取りに行ってるので真っ暗です。
    スペックによってはかなり重いかもしれません。
    
    クリックで元の画像と入れ替わります。
*/
package
{
    import flash.display.Bitmap;
    import flash.display.BitmapData;
    import flash.display.Loader;
    import flash.display.Sprite;
    import flash.events.Event;
    import flash.events.MouseEvent;
    import flash.geom.Matrix;
    import flash.net.URLLoader;
    import flash.net.URLRequest;
    import flash.system.LoaderContext;
    import flash.system.Security;
    import flash.text.TextField;
    import flash.text.TextFieldAutoSize;
    
    [SWF(width="465", height="465", backgroundColor="0xFFFFFF", frameRate="40")]
    public class Main extends Sprite
    {
        private static const KEYWORD:String = "cat";
        private var xml_loader:URLLoader;
        private var img_loader:Loader;
        private var tf:TextField;
        private var source:BitmapData;
        private var canvas:BitmapData;
        private var bmp:Bitmap;
        private var w:Number;
        private var h:Number;
        private var aves:Array;
        private var block:Number;
        private var size:Number;
        private var click:int;
        
        public function Main()
        {
            // crossdomain.xmlを読み込む
            Security.loadPolicyFile("http://api.flickr.com/crossdomain.xml");
            Security.loadPolicyFile("http://farm1.static.flickr.com/crossdomain.xml");
            Security.loadPolicyFile("http://farm2.static.flickr.com/crossdomain.xml");
            Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml");
            Security.loadPolicyFile("http://farm4.static.flickr.com/crossdomain.xml");
            
            // 計算中に表示するテキスト
            tf = addChild(new TextField) as TextField;
            tf.autoSize = TextFieldAutoSize.LEFT;
            tf.text = "画像ロード & 計算中・・・。";
            tf.x = tf.y = 40;
            
            // 画像のロード準備 
            xml_loader=new URLLoader();
            xml_loader.addEventListener(Event.COMPLETE, onCompleteSearch);
            xml_loader.load(new URLRequest("http://api.flickr.com/services/rest/?method=flickr.photos.search&api_key=25c5f4bc0087edf4d6efdc567daf0a64&tags=" + KEYWORD + "&per_page=10"));
        }
        
        // XMLロード後に実行される関数
        private function onCompleteSearch(e:Event):void
        {
            xml_loader.removeEventListener(Event.COMPLETE, onCompleteSearch);
            var xml:XML=XML(xml_loader.data);
            
            if (xml.@stat == "ok")
            {
                var photo:XML=xml.photos.photo[10*Math.random() >> 0] as XML;
                var url:String="http://farm" + photo.@farm + ".static.flickr.com/" + photo.@server + "/" + photo.@id + "_" + photo.@secret + ".jpg";
                img_loader=new Loader();
                img_loader.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompletePhoto);
                img_loader.load(new URLRequest(url), new LoaderContext(true));
            }
        }
        
        // 画像のロード後に実行されっる関数
        private function onCompletePhoto(e:Event):void
        {
            // 画像の作成
            img_loader.contentLoaderInfo.removeEventListener(Event.COMPLETE, onCompletePhoto);
            var raw_img:BitmapData = (img_loader.content as Bitmap).bitmapData;
            var x_scale:Number=350 / raw_img.width;
            var y_scale:Number=350 / raw_img.height;
            source = new BitmapData(350, 350, false, 0x000000);
            canvas = new BitmapData(350, 350, false, 0x000000);
            source.draw(raw_img, new Matrix(x_scale, 0, 0, y_scale));
            
            // 計算の準備
            block = 5;
            w = canvas.width;
            h = canvas.height;
            size = block * block;
            aves = [];
            
            // 計算開始
            kuwahara();
            
            // 画像の表示
            removeChild(tf);
            bmp= addChild(new Bitmap(canvas)) as Bitmap;
            bmp.x=bmp.y=57.5;
            
            // クリック用
            click = 0;
            stage.addEventListener(MouseEvent.CLICK, onClick);
            
        }
        
        // 画像クリック用の関数
        private function onClick(e:MouseEvent):void
        {
            if(click%2 == 0) bmp.bitmapData = source;
            else bmp.bitmapData = canvas;
            
            click ++;
        }
        
        // 画像処理を行う関数
        private function kuwahara():void
        {
            source.lock();
            canvas.lock();
            for(var i:int=0 ; i<w ; i++)
            {
                for(var j:int=0 ; j<h ; j++)
                {
                    var min:uint = 0xff;
                    var select:int = -1;
                    var tmp:uint;
                    
                    var x0:int = (i - block + 1);
                    var y0:int = (j - block + 1);
                    var x1:int = (i + block - 1);
                    var y1:int = (j + block - 1);
                    
                    // 左上のブロックを計算
                    if (x0 >= 0 && y0 >= 0)
                    {
                        tmp=calcColor(x0, y0, 0);
                        if (min > tmp)
                        {
                            min=tmp;
                            select=0;
                        }
                    }
                    
                    // 右上のブロックを計算
                    if (x1 < w && y0 >= 0)
                    {
                        tmp=calcColor(i, y0, 1);
                        if (min > tmp)
                        {
                            min=tmp;
                            select=1;
                        }
                    }
                    
                    // 右下のブロックを計算
                    if (x1 < w&& y1 < h)
                    {
                        tmp=calcColor(i, j, 2);
                        if (min > tmp)
                        {
                            min=tmp;
                            select=2;
                        }
                    }
                    
                    // 左下のブロックを計算
                    if (x0 >=0 && y1 < h)
                    {
                        tmp=calcColor(x0, j, 3);
                        if (min > tmp)
                        {
                            min=tmp;
                            select=3;
                        }
                    }
                    
                    var color:uint = (select == -1) ? (source.getPixel(i, j)):(aves[select]);
                    canvas.setPixel(i, j, color);
                }
            }
            
            source.unlock();
            canvas.unlock();
        }
        
        // 各領域の平均と、最大最小の差を計算する
        private function calcColor(xx:int, yy:int, n:int):uint
        {
            var r:uint=0;
            var g:uint=0;
            var b:uint=0;
            var sr:uint=0;
            var sg:uint=0;
            var sb:uint=0;
            var maxw:int = xx + block;
            var maxh:int = yy + block;
            var rmax:uint=0x00;
            var gmax:uint=0x00;
            var bmax:uint=0x00;
            var rmin:uint=0xff;
            var gmin:uint=0xff;
            var bmin:uint=0xff;
            var color:uint;
            
            for (var i:int=xx; i < maxw; i++)
            {
                for (var j:int=yy; j < maxh; j++)
                {
                    color = source.getPixel(i, j);
                    r = (color >> 16) & 0xFF;
                    g = (color >> 8) & 0xFF;
                    b = color & 0xFF;
                    
                    if (rmax < r) rmax=r;
                    if (gmax < g) gmax=g;
                    if (bmax < b) bmax=b;
                    if (rmin > r) rmin=r;
                    if (gmin > g) gmin=g;
                    if (bmin > b) bmin=b;
                    
                    sr += r;
                    sg += g;
                    sb += b;
                }
            }
            
            aves[n] = ((sr / size) << 16) | ((sg / size) << 8) | (sb / size);
            return (rmax - rmin + gmax - gmin + bmax - bmin) / 3;
        }
    }
}