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
/**
* 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));
}
}
}