package { import flash.display.*; import flash.events.*; import flash.geom.*; import flash.net.URLRequest; import flash.system.*; import flash.filters.*; import frocessing.color.ColorRGB; import com.bit101.components.*; public class Main extends Sprite { private const WIDTH:int = 250; private const HEIGHT:int = 250; private var window:Window; private var bitmap:Bitmap; private var copybd:BitmapData; public function Main() { window = new Window(this, 0, 0, "Binarization"); window.width = window.height = 465; Security.loadPolicyFile("http://farm3.static.flickr.com/crossdomain.xml"); var loader:Loader = new Loader(); loader.contentLoaderInfo.addEventListener(Event.INIT, initHandler); loader.load(new URLRequest("http://farm1.static.flickr.com/208/503553011_82716cc9b9.jpg"), new LoaderContext(true)); } private function initHandler(event:Event):void { var loader:Loader = event.currentTarget.loader; var matrix:Matrix = new Matrix(); matrix.scale(WIDTH / loader.width, HEIGHT / loader.height); var bd:BitmapData = new BitmapData(WIDTH, HEIGHT); bd.draw(loader, matrix); copybd = bd.clone(); bitmap = new Bitmap(bd); bitmap.x = (465 - bitmap.width) / 2; window.content.addChild(bitmap); var button1:PushButton = new PushButton(window.content, 5, 300, "Original", originalHander); var button2:PushButton = new PushButton(window.content, 5, 320, "Threshold", binarization); var button3:PushButton = new PushButton(window.content, 5, 340, "Halftone", halfTone); var button4:PushButton = new PushButton(window.content, 120, 300, "Random", randomDither); var button5:PushButton = new PushButton(window.content, 120, 320, "Bayer", bayerDither); var button6:PushButton = new PushButton(window.content, 235, 300, "Repeat", errorDiffusion); var button7:PushButton = new PushButton(window.content, 235, 320, "Floyd–Steinberg", errorDiffusion2); var button8:PushButton = new PushButton(window.content, 235, 340, "Jarvis, Judice & Ninke", errorDiffusion3); var button9:PushButton = new PushButton(window.content, 235, 360, "Stucki", errorDiffusion4); var button10:PushButton = new PushButton(window.content, 235, 380, "Burkes", errorDiffusion5); var button11:PushButton = new PushButton(window.content, 350, 300, "Sierra", errorDiffusion6); var button12:PushButton = new PushButton(window.content, 350, 320, "Two-row Sierra", errorDiffusion7); var button13:PushButton = new PushButton(window.content, 350, 340, "Filter Lite", errorDiffusion8); } private function originalHander(event:Event = null):void { bitmap.bitmapData = copybd.clone(); } private function binarization(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; bd.threshold(bd, bd.rect, new Point(), "<", 0x7FFFFF, 0xFF000000, 0xFFFFFF); bd.threshold(bd, bd.rect, new Point(), "!=", 0x0, 0xFFFFFFFF, 0xFFFFFF); } private function halfTone(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; const PSIZE:int = 80; if (bd.width < PSIZE || bd.height < PSIZE) return; var SIZE:int = (bd.width > bd.height) ? bd.width / PSIZE : bd.height / PSIZE; var matrix:Array = new Array(); for (var i:int = 0; i < SIZE * SIZE; i++) matrix.push(1); var filter:ConvolutionFilter = new ConvolutionFilter(SIZE, SIZE, matrix, SIZE * SIZE); bd.applyFilter(bd, bd.rect, new Point(0, 0), filter); var canvas:Sprite = new Sprite(); for (var y:int = Math.floor(SIZE / 2); y < bd.height; y += SIZE) { for (var x:int = Math.floor(SIZE / 2); x < bd.width; x += SIZE) { canvas.graphics.beginFill(0x0); canvas.graphics.drawCircle(x, y, bd.getPixel(x, y) / (255 * 255 * 255 / SIZE)); canvas.graphics.endFill(); } } bitmap.bitmapData = new BitmapData(WIDTH, HEIGHT, false); bitmap.bitmapData.draw(canvas); // ハーフトーンの色が変わる謎現象対策(本来ならこれは外したほうがいいです) bitmap.bitmapData.threshold(bitmap.bitmapData, bd.rect, new Point(), "<", 0x7FFFFF, 0xFF000000, 0xFFFFFF); bitmap.bitmapData.threshold(bitmap.bitmapData, bd.rect, new Point(), "!=", 0x0, 0xFFFFFFFF, 0xFFFFFF); } private function randomDither(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); for (var y:int = 0; y < bd.height; y++) { for (var x:int = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var gray:int = (color.r + color.g + color.b) / 3; if (gray < Math.random() * 256) { color.r = color.g = color.b = 0; } else { color.r = color.g = color.b = 255; } bd.setPixel(x, y, color.value); } } } private function bayerDither(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var pattern:Array = [ [ 0, 8, 2, 10], [12, 4, 14, 6], [ 3, 11, 1, 9], [15, 7, 13, 5] ]; for (var y:int = 0; y < bd.height; y++) { for (var x:int = 0; x < bd.width; x++) { var threshold:int = pattern[x % 4][y % 4]; color.value = bd.getPixel(x, y); color.r /= 16; color.g /= 16; color.b /= 16; var avg:int = (color.r + color.g + color.b) / 3; if (avg < threshold) color.r = color.g = color.b = 0; else color.r = color.g = color.b = 255; bd.setPixel(x, y, color.value); } } } private function errorDiffusion(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); for (var y:int = 0; y < bd.height; y++) { var error:int = 0; for (var x:int = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error; if (avg < 128) { error = -avg; avg = 0; } else { error = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; bd.setPixel(x, y, color.value); } } } private function errorDiffusion2(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var error:Array = new Array(bd.height); var filter:Array = [ [ 0, 0, 0, 7/48, 5/48], [3/48, 5/48, 7/48, 5/48, 3/48], [1/48, 3/48, 5/48, 3/48, 1/48], ]; for (var y:int = 0; y < bd.height; y++) { error[y] = new Array(bd.width); for (var x:int = 0; x < bd.width; x++) { error[y][x] = 0; } } for (y = 0; y < bd.height; y++) { for (x = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error[y][x]; var e:int = 0; if (avg < 128) { e = -avg; avg = 0; } else { e = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; for (var yy:int = 0; yy < 3; yy++) { for (var xx:int = -2; xx <= 2; xx++) { if (y + yy < 0 || bd.height <= y + yy || x + xx < 0 || bd.width <= x + xx) continue; error[y + yy][x + xx] += e * filter[yy][xx + 2]; } } bd.setPixel(x, y, color.value); } } } private function errorDiffusion3(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var error:Array = new Array(bd.height); var filter:Array = [ [ 0, 0, 7 / 16], [3 / 16, 5 / 16, 1 / 16] ]; for (var y:int = 0; y < bd.height; y++) { error[y] = new Array(bd.width); for (var x:int = 0; x < bd.width; x++) { error[y][x] = 0; } } for (y = 0; y < bd.height; y++) { for (x = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error[y][x]; var e:int = 0; if (avg < 128) { e = -avg; avg = 0; } else { e = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; for (var yy:int = 0; yy < 2; yy++) { for (var xx:int = -1; xx <= 1; xx++) { if (y + yy < 0 || bd.height <= y + yy || x + xx < 0 || bd.width <= x + xx) continue; error[y + yy][x + xx] += e * filter[yy][xx + 1]; } } bd.setPixel(x, y, color.value); } } } private function errorDiffusion4(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var error:Array = new Array(bd.height); var filter:Array = [ [ 0, 0, 0, 8/42, 4/42], [2/42, 4/42, 8/42, 4/42, 2/42], [1/42, 2/42, 4/42, 2/42, 1/42] ]; for (var y:int = 0; y < bd.height; y++) { error[y] = new Array(bd.width); for (var x:int = 0; x < bd.width; x++) { error[y][x] = 0; } } for (y = 0; y < bd.height; y++) { for (x = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error[y][x]; var e:int = 0; if (avg < 128) { e = -avg; avg = 0; } else { e = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; for (var yy:int = 0; yy < 3; yy++) { for (var xx:int = -2; xx <= 2; xx++) { if (y + yy < 0 || bd.height <= y + yy || x + xx < 0 || bd.width <= x + xx) continue; error[y + yy][x + xx] += e * filter[yy][xx + 2]; } } bd.setPixel(x, y, color.value); } } } private function errorDiffusion5(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var error:Array = new Array(bd.height); var filter:Array = [ [ 0, 0, 0, 8/32, 4/32], [2/32, 4/32, 8/32, 4/32, 2/32] ]; for (var y:int = 0; y < bd.height; y++) { error[y] = new Array(bd.width); for (var x:int = 0; x < bd.width; x++) { error[y][x] = 0; } } for (y = 0; y < bd.height; y++) { for (x = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error[y][x]; var e:int = 0; if (avg < 128) { e = -avg; avg = 0; } else { e = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; for (var yy:int = 0; yy < 2; yy++) { for (var xx:int = -2; xx <= 2; xx++) { if (y + yy < 0 || bd.height <= y + yy || x + xx < 0 || bd.width <= x + xx) continue; error[y + yy][x + xx] += e * filter[yy][xx + 2]; } } bd.setPixel(x, y, color.value); } } } private function errorDiffusion6(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var error:Array = new Array(bd.height); var filter:Array = [ [ 0, 0, 0, 5/32, 3/32], [2/32, 4/32, 5/32, 4/32, 2/32], [ 0, 2/32, 3/32, 2/32, 0] ]; for (var y:int = 0; y < bd.height; y++) { error[y] = new Array(bd.width); for (var x:int = 0; x < bd.width; x++) { error[y][x] = 0; } } for (y = 0; y < bd.height; y++) { for (x = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error[y][x]; var e:int = 0; if (avg < 128) { e = -avg; avg = 0; } else { e = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; for (var yy:int = 0; yy < 3; yy++) { for (var xx:int = -2; xx <= 2; xx++) { if (y + yy < 0 || bd.height <= y + yy || x + xx < 0 || bd.width <= x + xx) continue; error[y + yy][x + xx] += e * filter[yy][xx + 2]; } } bd.setPixel(x, y, color.value); } } } private function errorDiffusion7(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var error:Array = new Array(bd.height); var filter:Array = [ [ 0, 0, 0, 4/16, 3/16], [1/16, 2/16, 3/16, 2/16, 1/16] ]; for (var y:int = 0; y < bd.height; y++) { error[y] = new Array(bd.width); for (var x:int = 0; x < bd.width; x++) { error[y][x] = 0; } } for (y = 0; y < bd.height; y++) { for (x = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error[y][x]; var e:int = 0; if (avg < 128) { e = -avg; avg = 0; } else { e = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; for (var yy:int = 0; yy < 2; yy++) { for (var xx:int = -2; xx <= 2; xx++) { if (y + yy < 0 || bd.height <= y + yy || x + xx < 0 || bd.width <= x + xx) continue; error[y + yy][x + xx] += e * filter[yy][xx + 2]; } } bd.setPixel(x, y, color.value); } } } private function errorDiffusion8(event:Event = null):void { bitmap.bitmapData = copybd.clone(); var bd:BitmapData = bitmap.bitmapData; var color:ColorRGB = new ColorRGB(); var error:Array = new Array(bd.height); var filter:Array = [ [ 0, 0, 2/4], [1/4, 1/4, 0] ]; for (var y:int = 0; y < bd.height; y++) { error[y] = new Array(bd.width); for (var x:int = 0; x < bd.width; x++) { error[y][x] = 0; } } for (y = 0; y < bd.height; y++) { for (x = 0; x < bd.width; x++) { color.value = bd.getPixel(x, y); var avg:int = (color.r + color.g + color.b) / 3; avg -= error[y][x]; var e:int = 0; if (avg < 128) { e = -avg; avg = 0; } else { e = 255 - avg; avg = 255; } color.r = color.g = color.b = avg; for (var yy:int = 0; yy < 2; yy++) { for (var xx:int = -1; xx <= 1; xx++) { if (y + yy < 0 || bd.height <= y + yy || x + xx < 0 || bd.width <= x + xx) continue; error[y + yy][x + xx] += e * filter[yy][xx + 1]; } } bd.setPixel(x, y, color.value); } } } } } 二値化処理一覧