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: フラクタルで画像を描画する

2009/12/17
* Rectangle と BitmapData.histogram を使って、ENTER_FRAME を排除

フラクタルで画像を描画

パクリ元ネタ:
fladdict » コンピューターに絵画を描かせる
http://fladdict.net/blog/2009/05/computer-painting.html

標準偏差:
http://www.cap.or.jp/~toukei/kandokoro/html/14/14_2migi.htm

画像の読み込み処理:
http://wonderfl.kayac.com/code/3fb2258386320fe6d2b0fe17d6861e7da700706a

RGB->HSB変換:
http://d.hatena.ne.jp/flashrod/20060930#1159622027
Get Adobe Flash player
by Aquioux 17 Dec 2009

    Talk

    ep91ckok at 18 Dec 2009 10:09
    BitmapData.histogram(rect)で実際に切り取られる範囲が何だかややこしいことになってるようなので、 平均を出すときに用いる値 _numOfPixel を _numOfPixel = _rect.width * _rect.height; の代わりに _numOfPixel = 0; for (i = 0; i < 256; i++) { _numOfPixel += _histVector[0][i]; } とすると良いのかも。

    Tags

    Embed
/**
 * Copyright Aquioux ( http://wonderfl.net/user/Aquioux )
 * MIT License ( http://www.opensource.org/licenses/mit-license.php )
 * Downloaded from: http://wonderfl.net/c/9IDW
 */

// forked from ep91ckok's forked from: フラクタルで画像を描画する
// forked from fumix's フラクタルで画像を描画する

/*
 * 2009/12/17
 * Rectangle と BitmapData.histogram を使って、ENTER_FRAME を排除
 */

/**
フラクタルで画像を描画

パクリ元ネタ:
fladdict » コンピューターに絵画を描かせる
http://fladdict.net/blog/2009/05/computer-painting.html

標準偏差:
http://www.cap.or.jp/~toukei/kandokoro/html/14/14_2migi.htm

画像の読み込み処理:
http://wonderfl.kayac.com/code/3fb2258386320fe6d2b0fe17d6861e7da700706a

RGB->HSB変換:
http://d.hatena.ne.jp/flashrod/20060930#1159622027

**/
package 
{
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.display.Sprite;
	import flash.events.Event;
	import flash.filters.ColorMatrixFilter;
	import flash.geom.Point;
	import flash.geom.Rectangle;
	import flash.net.URLRequest;
    import flash.system.LoaderContext;
	[SWF(width = "465", height = "465", frameRate = "30", backgroundColor = "#ffffff")]

    public class Main extends Sprite 
    {
        
		private const IMAGE_URL:String = "http://farm4.static.flickr.com/3639/3538831894_cca4aabd68.jpg";
        //標準偏差の閾値。小さくすると細かくなるけど、小さすぎるとただのモザイクみたくなる。
        private const THRESHOLD:Number = 30;

		private const LIMIT_OF_MINIMUN:uint = 4;	// 分割サイズ最小値
		
		private var _colorBitmapData:BitmapData;	// 読込画像の BitmapData
		private var _grayBitmapData:BitmapData;	// グレイスケール化した BitmapData
		private var _canvasBitmapData:BitmapData;
		private var _histVector:Vector.<Vector.<Number>>;	// BitmapData.histogram() の返り値として共用する
		private var _rect:Rectangle;				// 走査範囲 Rectangle として共用する
		private var _numOfPixel:uint;			// Rectangle 内のピクセル数として共用する

        public function Main():void 
        {
            if (stage) init();
            else addEventListener(Event.ADDED_TO_STAGE, init);

        }
        
        private function init(e:Event = null):void 
        {
            removeEventListener(Event.ADDED_TO_STAGE, init);
            //画像の読み込み
			var req:URLRequest = new URLRequest(IMAGE_URL);
			var loader:Loader = new Loader();
			loader.contentLoaderInfo.addEventListener(Event.COMPLETE, loadComplete);    
			loader.load( req, new LoaderContext(true));
			// take a capture after 5 sec
			//Wonderfl.capture_delay( 5 );
        }
        
        //画像読み込み後の処理
        private function loadComplete(e:Event = null):void 
        {
			e.target.removeEventListener(Event.COMPLETE, loadComplete);
			
			// BitmapData の生成
			_colorBitmapData = e.target.loader.content.bitmapData;
			_grayBitmapData  = _colorBitmapData.clone();
			grayscale(_grayBitmapData);
			_canvasBitmapData = _colorBitmapData.clone();
			
			// キャンバスの生成
			addChild(new Bitmap(_canvasBitmapData));
			
			// 再帰処理
			divideCheck(new Rectangle(0, 0, _colorBitmapData.width, _colorBitmapData.height));
        }
        
        
		// 再帰処理
		private function divideCheck(rect:Rectangle):void {
			// Rectangle を共用変数に格納(以下、getStandardDeviation, getAverageColor では _rect を使用する)
			_rect = rect;
			
			// 現在のチェック対象矩形の縦または横の長さが指定より小さい場合、再帰を停止させる
			var isDivide:Boolean = (_rect.width <= LIMIT_OF_MINIMUN || _rect.height <= LIMIT_OF_MINIMUN) ? false : true;
			// 再帰判定
			if (isDivide) {
				var deviation:Number = getStandardDeviation();
				if (deviation > THRESHOLD) {
					// 標準偏差が指定より大きい場合、4分木再帰を続行
					var halfWidth:Number  = _rect.width / 2;
					var halfHeight:Number = _rect.height / 2;
					var left:Number = _rect.x;
					var top:Number  = _rect.y;
					var center:Number = left + halfWidth;
					var middle:Number = top  + halfHeight;
					// 4分木再帰
					divideCheck(new Rectangle(left,   top,    halfWidth, halfHeight));
					divideCheck(new Rectangle(center, top,    halfWidth, halfHeight));
					divideCheck(new Rectangle(left,   middle, halfWidth, halfHeight));
					divideCheck(new Rectangle(center, middle, halfWidth, halfHeight));
				} else {
					// 標準偏差が指定より小さい場合、再帰を停止し、描画をおこなう
					isDivide = false;
				}
			}
			
			if (!isDivide) draw();
		}
		

		// 対象 BitmapData の指定矩形範囲の標準偏差を求める(グレイスケール bitmapData を使用)
		private function getStandardDeviation():Number {
			_numOfPixel = _rect.width * _rect.height;		// 走査範囲のピクセル数
			_histVector = _grayBitmapData.histogram(_rect);	// 走査範囲のヒストグラム
			var vector:Vector.<Number> = _histVector[0];	// グレイスケールなので一つだけで処理
			var sum:Number = 0;								// 累積用変数
			
			// 輝度の平均を求める
			for (var i:int = 0; i < 256; i++) {
				sum += vector[i] * i;
			}
			var average:Number = sum / _numOfPixel;
			
			// 平均との差の二乗を累積
			var diff:Number;
			sum = 0;
			for (i = 0; i < 256; i++) {
				diff =  i - average;
				sum += diff * diff * vector[i];
			}
			return Math.sqrt(sum / _numOfPixel);
		}
		
		// キャンバスに描画
		private function draw():void {
			//var rect:Rectangle = new Rectangle(_rect.x + 1, _rect.y + 1, _rect.width - 2, _rect.height - 2);
			//_canvasBitmapData.fillRect(_rect, 0x999999);
			_canvasBitmapData.fillRect(_rect, getAverageColor());
		}
		
		// 対象 BitmapData の指定矩形範囲の平均色を求める(カラー bitmapData を使用)
		private function getAverageColor():uint {
			_numOfPixel = _rect.width * _rect.height;		// 走査範囲のピクセル数
			_histVector = _colorBitmapData.histogram(_rect);// 走査範囲のヒストグラム
			var sumVector:Vector.<Number> = new Vector.<Number>(3, true);	// 累積用変数格納 Vector
			
			// r, g, b それぞれの平均値を求める
			for (var i:int = 0; i < 256; i++) {
				for (var j:int = 0; j < 3; j++) {
					sumVector[j] += _histVector[j][i] * i;
				}
			}
			var r:uint = sumVector[0] / _numOfPixel;
			var g:uint = sumVector[1] / _numOfPixel;
			var b:uint = sumVector[2] / _numOfPixel;
			
			// Math.min(value, 0xFF)
			// http://www.be-interactive.org/index.php?itemid=519
			r = (r | (((r & 0xFFFFFF00) + 0x7FFFFFFF) >> 31)) & 0xFF;
			g = (g | (((g & 0xFFFFFF00) + 0x7FFFFFFF) >> 31)) & 0xFF;
			b = (b | (((b & 0xFFFFFF00) + 0x7FFFFFFF) >> 31)) & 0xFF;
			
			return r << 16 | g << 8 | b;
		}
		
		
		// グレイスケール
		// Foundation ActionScript 3.0 Image Effects(P106)
		// http://www.amazon.co.jp/gp/product/1430218711?ie=UTF8&tag=laxcomplex-22
		// (NTSC 系加重平均)
		private function grayscale(bitmapData:BitmapData):void {
			var matrix:Array = [
				0.3, 0.59, 0.11, 0, 0,
				0.3, 0.59, 0.11, 0, 0,
				0.3, 0.59, 0.11, 0, 0,
				0,   0,    0,    1, 0
			];
			bitmapData.applyFilter(bitmapData, bitmapData.rect, new Point(), new ColorMatrixFilter(matrix));
		}
	}	
}