// inspired by http://wonderfl.net/c/4kAe
package {
import flash.display.Bitmap;
import flash.display.BitmapData;
import flash.display.Loader;
import flash.display.Sprite;
import flash.events.Event;
import flash.geom.Matrix;
import flash.net.URLRequest;
import flash.system.LoaderContext;
[SWF(width=465,height=465)]
public class Circles extends Sprite {
public function Circles () {
var loader:Loader = new Loader;
loader.contentLoaderInfo.addEventListener (Event.COMPLETE, onComplete);
loader.load (new URLRequest ("http://assets.wonderfl.net/images/related_images/d/d9/d9b9/d9b9e27367920f3ef42cc14e1155ec0f18908b3b"), new LoaderContext (true));
}
private function onComplete (e:Event):void {
var bitmap:Bitmap = e.target.content;
bd = new BitmapData (256, 256, false, 0);
bd.draw (bitmap, new Matrix (bd.width / 465, 0, 0, bd.height / 450), null, null, null, true);
ir = new Integral (bd, 2);
ig = new Integral (bd, 1);
ib = new Integral (bd, 0);
x = 0.5 * (465 - bd.width);
y = 0.5 * (465 - bd.height);
var r:Rect = new Rect (0, 0, bd.width, bd.height);
drawCircle (r);
}
private var bd:BitmapData, ir:Integral, ig:Integral, ib:Integral;
private function drawCircle(r:Rect):void {
var a:Number = r.w * r.h, w2:int = r.w / 2, h2:int = r.h / 2;
if ((a > 9) && (Math.max (
Math.abs (ir.featureH (r)), Math.abs (ig.featureH (r)), Math.abs (ib.featureH (r)),
Math.abs (ir.featureV (r)), Math.abs (ig.featureV (r)), Math.abs (ib.featureV (r)),
Math.abs (ir.featureD (r)), Math.abs (ig.featureD (r)), Math.abs (ib.featureD (r))
) / a > 9)) {
drawCircle (new Rect (r.x, r.y, w2, h2));
drawCircle (new Rect (r.x, r.y + h2, w2, r.h - h2));
drawCircle (new Rect (r.x + w2, r.y, r.w - w2, h2));
drawCircle (new Rect (r.x + w2, r.y + h2, r.w - w2, r.h - h2));
} else {
var R:int = ir.sum (r) / a;
var G:int = ig.sum (r) / a;
var B:int = ib.sum (r) / a;
graphics.beginFill ((R << 16) | (G << 8) | B);
// equal area radius
R = w2 * 1.128379167;
var dx:int = (R * 0.2 + 2) * (Math.random () - Math.random ());
var dy:int = (R * 0.2 + 2) * (Math.random () - Math.random ());
graphics.drawCircle (r.x + w2 + dx, r.y + h2 + dy, R);
//graphics.drawRect (r.x, r.y, r.w, r.h);
graphics.endFill ();
}
}
}
}
class Rect {
public var x:int, w:int;
// these are used by Integral image and must be reset when y or h changes
internal var iwy:int, iwh:int, iwh2:int;
// therefore setters
protected var _y:int, _h:int;
public function get y ():int { return _y; }
public function set y (Y:int):void { _y = Y; iwy = -1; }
public function get h ():int { return _h; }
public function set h (H:int):void { _h = H; iwh = -1; iwh2 = -1; }
public function Rect (left:int = 0, top:int = 0, width:int = 0, height:int = 0) {
x = left; y = top; w = width; h = height;
}
public function copy (r:Rect):void {
x = r.x; w = r.w;
iwy = r.iwy; iwh = r.iwh; iwh2 = r.iwh2;
_y = r._y; _h = r._h;
}
public function get x2 ():int { return x + w - 1; }
public function get y2 ():int { return _y + _h - 1; }
}
import flash.display.BitmapData;
class Integral {
public var width:uint = 0;
public var height:uint = 0;
public var data:Vector.<int>;
public function Integral (bitmapData:BitmapData = null, shift:int = 0) {
if (bitmapData != null) {
calculate (bitmapData, shift);
}
}
public function calculate (bitmapData:BitmapData, shift:int = 0):void {
var w:int = bitmapData.width, w1:int = w + 1, w2:int = w + 2;
var h:int = bitmapData.height, h1:int = h + 1;
if ((data == null) || (data.length != w1 * h1)) {
data = new Vector.<int> (w1 * h1, true);
}
width = w1;
height = h1;
var bits:int = 8 * shift;
var mask:int = 255 << bits;
var rgba:Vector.<uint> = bitmapData.getVector (bitmapData.rect);
var i/*nput*/:int = 0, o/*utput*/:int = w2, s:int;
for (var y:int = 0; y < h; y++, o++) {
s = 0;
for (var x:int = 0; x < w; x++, o++, i++) {
// * data[o-w1]
// s data[o]
s += (rgba [i] & mask) >> bits;
data [o] = data [int (o - w1)] + s;
}
}
}
public function sum (rect:Rect):int {
if (rect.iwh < 0) rect.iwh = width * rect.h;
if (rect.iwy < 0) rect.iwy = width * rect.y;
// a b
// d c
var pa:int = rect.x + rect.iwy;
var pb:int = pa + rect.w;
var pc:int = pb + rect.iwh;
var pd:int = pc - rect.w;
// a - b + c - d
return data [pa] - data [pb] + data [pc] - data [pd];
}
// haar-like features: horizontal, vertical, diagonal
public function featureH (rect:Rect):int {
if (rect.iwh < 0) rect.iwh = width * rect.h;
if (rect.iwy < 0) rect.iwy = width * rect.y;
if (rect.iwh2 < 0) rect.iwh2 = width * (rect.h >> 1);
// a b
// f e
// d c
var pa:int = rect.x + rect.iwy;
var pb:int = pa + rect.w;
var pc:int = pb + rect.iwh, pe:int = pb + rect.iwh2;
var pd:int = pc - rect.w, pf:int = pe - rect.w;
// a - b + e - f - (f - e + c - d)
return data [pa] - data [pb] + ((data [pe] - data [pf]) << 1) - data [pc] + data [pd];
}
public function featureV (rect:Rect):int {
if (rect.iwh < 0) rect.iwh = width * rect.h;
if (rect.iwy < 0) rect.iwy = width * rect.y;
// a g b
// d i c
var w2:int = rect.w >> 1;
var pa:int = rect.x + rect.iwy;
var pb:int = pa + rect.w, pg:int = pb - w2;
var pc:int = pb + rect.iwh;
var pd:int = pc - rect.w, pi:int = pc - w2;
// a - g + i - d - (g - b + c - i)
return data [pa] + ((data [pi] - data [pg]) << 1) - data [pd] + data [pb] - data [pc];
}
public function featureD (rect:Rect):int {
if (rect.iwh < 0) rect.iwh = width * rect.h;
if (rect.iwy < 0) rect.iwy = width * rect.y;
if (rect.iwh2 < 0) rect.iwh2 = width * (rect.h >> 1);
// a g b
// f h e
// d i c
var w2:int = rect.w >> 1;
var pa:int = rect.x + rect.iwy;
var pb:int = pa + rect.w, pg:int = pb - w2;
var pc:int = pb + rect.iwh, pe:int = pb + rect.iwh2;
var pd:int = pc - rect.w, pi:int = pc - w2, pf:int = pe - rect.w;
var ph:int = pe - w2;
// a - g + h - f + h - e + c - i - (g - b + e - h) - (f - h + i - d)
// = a + b + c + d + 4h - 2e - 2f - 2g - 2i
return data [pa] + data [pb] + data [pc] + data [pd] + (data [ph] << 2) - ((data [pe] + data [pf] + data [pg] + data [pi]) << 1);
}
}