Hilbert Scan
The Hilbert curve has been applied to image processing as a scanning technique (Hilbert scan).
This scan is guided by the Hilbert space filling curve.
see also:
http://en.wikipedia.org/wiki/Hilbert_curve
http://rest-term.com/archives/1204/
スキャンオーダーにヒルベルト曲線を利用
8次で空間充填、ヒルベルトスキャン
/**
* Copyright wellflat ( http://wonderfl.net/user/wellflat )
* MIT License ( http://www.opensource.org/licenses/mit-license.php )
* Downloaded from: http://wonderfl.net/c/7qCc
*/
package {
import flash.system.LoaderContext;
import flash.net.URLRequest;
import com.bit101.components.HSlider;
import com.bit101.components.PushButton;
import flash.display.*;
import flash.events.Event;
import flash.events.MouseEvent;
import flash.text.*;
[SWF(width = "465", height = "465", backgroundColor = "#333333", frameRate = "12")]
public class Main extends Sprite {
private var hilbert:HilbertScanView;
private var base:BitmapData;
private var cover:BitmapData;
private var tf:TextField;
private var iter:uint = 0;
private var slider:HSlider;
private var button:PushButton;
private var loaderA:Loader;
private var loaderB:Loader;
private var loadedImage:uint = 0;
public function Main() {
graphics.beginFill(0x333333);
graphics.drawRect(0, 0, stage.stageWidth, stage.stageHeight);
graphics.endFill();
var urlA:String = "http://assets.wonderfl.net/images/related_images/5/56/5609/56092450a3c04a561fe0bfae3338c59cb035d2ac";
var urlB:String = "http://assets.wonderfl.net/images/related_images/c/cf/cf27/cf27879c502f10c504e40f97151b0430dc11bf5b";
loaderA = new Loader();
loaderA.load(new URLRequest(urlA), new LoaderContext(true));
loaderA.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteA);
loaderB = new Loader();
loaderB.load(new URLRequest(urlB), new LoaderContext(true));
loaderB.contentLoaderInfo.addEventListener(Event.COMPLETE, onCompleteB);
tf = new TextField();
tf.autoSize = TextFieldAutoSize.LEFT;
tf.defaultTextFormat = new TextFormat("Courier New", 14, 0xcccccc, true);
tf.x = 10;
tf.y = 270;
tf.text = "Hilbert Order: 0";
addChild(tf);
slider = new HSlider(this, 150, 275);
slider.minimum = 0;
slider.maximum = 8;
slider.tick = 1;
slider.addEventListener(Event.CHANGE, onSliderChange);
button = new PushButton(this, 150, 300);
button.label = "Tiffany to Lenna";
button.addEventListener(MouseEvent.MOUSE_DOWN, onButtonDown);
}
private function onCompleteA(e:Event):void {
var bmpData:BitmapData = new BitmapData(256, 256, false);
bmpData.draw(loaderA);
base = bmpData;
loadedImage++;
if(loadedImage == 2) {
createHilbert();
}
}
private function onCompleteB(e:Event):void {
var bmpData:BitmapData = new BitmapData(256, 256, false);
bmpData.draw(loaderB);
cover = bmpData;
loadedImage++;
if(loadedImage == 2) {
createHilbert();
}
}
private function createHilbert():void {
hilbert = new HilbertScanView(0, cover, base);
addChild(hilbert);
}
private function onSliderChange(e:Event):void {
var order:uint = e.target.value;
if(0 <= order && order <= 8) {
if(hilbert != null){
hilbert.dispose();
removeChild(hilbert);
}
if(order != 8) tf.text = "Hilbert Order: " + order;
else tf.text = "Hilbert Scan";
hilbert = new HilbertScanView(order, cover, base);
addChild(hilbert);
}
}
private function onButtonDown(e:MouseEvent):void {
iter = 0;
stage.addEventListener(Event.ENTER_FRAME, onEnterFrame);
}
private function onEnterFrame(e:Event):void {
slider.value = iter;
if(iter != 8) tf.text = "Hilbert Order: " + iter;
else tf.text = "Hilbert Scan";
if(iter >= 8) {
stage.removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
if(hilbert != null){
hilbert.dispose();
removeChild(hilbert);
}
hilbert = new HilbertScanView(iter, cover, base);
addChild(hilbert);
iter++;
}
}
}
import flash.display.*;
import flash.geom.Point;
class HilbertScanView extends Sprite {
private var order:int;
private var h:Number;
private var pt:Point;
private var bmp:BitmapData;
private var tmp:BitmapData;
private var dst:Bitmap;
public function HilbertScanView(order:uint, cover:BitmapData, base:BitmapData) {
bmp = base.clone();
tmp = cover;
order = order;
pt = new Point();
dst = new Bitmap();
h = 1;
for(var i:int = 2; i <= order; i++) h = h/(2 + h);
h *= cover.width;
bmp.lock();
rightUpLeft(order); // start path "コ"
bmp.unlock();
dst.bitmapData = bmp.clone();
addChild(dst);
bmp.dispose();
}
public function dispose():void {
dst.bitmapData.dispose();
}
private function rightUpLeft(i:int):void {
if(i == 0) return;
upRightDown(i - 1); scanRelative( h, 0);
rightUpLeft(i - 1); scanRelative( 0, h);
rightUpLeft(i - 1); scanRelative(-h, 0);
downLeftUp(i - 1);
}
private function downLeftUp(i:int):void {
if(i == 0) return;
leftDownRight(i - 1); scanRelative( 0, -h);
downLeftUp(i - 1); scanRelative(-h, 0);
downLeftUp(i - 1); scanRelative( 0, h);
rightUpLeft(i - 1);
}
private function leftDownRight(i:int):void {
if(i == 0) return;
downLeftUp(i - 1); scanRelative(-h, 0);
leftDownRight(i - 1); scanRelative( 0, -h);
leftDownRight(i - 1); scanRelative( h, 0);
upRightDown(i - 1);
}
private function upRightDown(i:int):void {
if(i == 0) return;
rightUpLeft(i - 1); scanRelative( 0, h);
upRightDown(i - 1); scanRelative( h, 0);
upRightDown(i - 1); scanRelative( 0, -h);
leftDownRight(i - 1);
}
private function scanRelative(dx:int, dy:int):void {
if(dx < 0) {
for(var x:int = 0; x >= dx; x--) {
bmp.setPixel(pt.x + x, pt.y, tmp.getPixel(pt.x + x, pt.y));
}
} else if(dy < 0) {
for(var y:int = 0; y >= dy; y--){
bmp.setPixel(pt.x, pt.y + y, tmp.getPixel(pt.x, pt.y + y));
}
} else {
for(var ay:int = 0; ay <= dy; ay++) {
for(var ax:int = 0; ax <= dx; ax++) {
bmp.setPixel(pt.x + ax, pt.y + ay, tmp.getPixel(pt.x + ax, pt.y + ay));
}
}
}
pt.x += dx;
pt.y += dy;
}
}