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: 色の距離

左側画像をクリックしてください。
* クリックしたピクセルと同じような色を探して表示します。
* 
* RGBを距離として捉える考え方です。
* 白に変換された部分は距離が遠い、つまり似た色ではないと判断できます。
* 
* 閾値は下のスライダーで調整可能です。

均等色空間である L*a*b* 色空間と、ついでに XYZ, HLS 色空間を追加した
適切な閾値は色空間によってかわります
Get Adobe Flash player
by heriet 10 Jan 2010
// forked from rsakane's 色の距離
/*
 * 左側画像をクリックしてください。
 * クリックしたピクセルと同じような色を探して表示します。
 * 
 * RGBを距離として捉える考え方です。
 * 白に変換された部分は距離が遠い、つまり似た色ではないと判断できます。
 * 
 * 閾値は下のスライダーで調整可能です。
 */

// 均等色空間である L*a*b* 色空間と、ついでに XYZ, HLS 色空間を追加した
// 適切な閾値は色空間によってかわります

package
{
	import flash.display.Sprite;
	import flash.display.Bitmap;
	import flash.display.BitmapData;
	import flash.display.Loader;
	import flash.events.Event;
	import flash.events.MouseEvent;
	import flash.geom.Matrix;
	import flash.net.URLRequest;
	import flash.system.LoaderContext;
	import flash.system.Security;
	import com.bit101.components.HUISlider;
	import com.bit101.components.Panel;
	import com.bit101.components.RadioButton;
 
	public class Main extends Sprite
	{
		private const WIDTH:int = 232;
		private const HEIGHT:int = 232;
		
		private var bitmapA:Bitmap;
		private var bitmapB:Bitmap;
		private var bd:BitmapData;
		
		private var slider:HUISlider;
		private var panel:Panel;
		
		private static const COLOR_SPACE_MODES:Array = ['lab', 'hls', 'xyz', 'rgb'];
		
		private var colorSpaceMode:String = COLOR_SPACE_MODES[0];
		
		public function Main()
		{
			panel = new Panel(this);
			panel.width = panel.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://farm3.static.flickr.com/2133/1991035050_f169d55a13.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);
 
			bd = new BitmapData(WIDTH, HEIGHT);
			bd.draw(loader, matrix);
			
			bitmapA = new Bitmap(bd);
			panel.content.addChild(bitmapA);
			var destbd:BitmapData = bd.clone();
			bitmapB = new Bitmap(destbd);
			bitmapB.x = WIDTH + 1;
			panel.content.addChild(bitmapB);
			
			slider = new HUISlider(this, 5, 300, "distance");
			slider.value = 100;
			slider.minimum = 0;
			slider.maximum = 300;
			
			stage.addEventListener(MouseEvent.CLICK, onMouseClick);
			
			var n:int = COLOR_SPACE_MODES.length;
			for (var i:int = 0; i < n; i++ ){
				var button:RadioButton = new RadioButton(panel.content, 5, 340 + 16 * i, COLOR_SPACE_MODES[i], i==0, onRadioButtonSelect);
			}
		}
		
		private function onMouseClick(event:MouseEvent):void
		{
			if (!bitmapA.hitTestPoint(mouseX, mouseY)) return;
			bitmapB.bitmapData = bd.clone();
			search(bd.getPixel(mouseX, mouseY));
		}
		private function onRadioButtonSelect(event:Event):void
		{
			colorSpaceMode = (event.currentTarget as RadioButton).label;
		}
		private function search(c:int):void
		{	
			var colorA:ColorPoint = new ColorPoint();
			var colorB:ColorPoint = new ColorPoint();
			colorA.color = c;
			
			for (var y:int = 0; y < bd.height; y++)
			{
				for (var x:int = 0; x < bd.width; x++)
				{
					colorB.color = bd.getPixel(x, y);
					
					var distance:Number;
					switch(colorSpaceMode) {
						case 'lab':
							distance = ColorPoint.distanceLab(colorA, colorB);
							break;
						case 'xyz':
							distance = ColorPoint.distanceXYZ(colorA, colorB);
							break;
						case 'hls':
							distance = ColorPoint.distanceHLS(colorA, colorB);
							break;
						default:
							distance = ColorPoint.distanceRGB(colorA, colorB);
							break;
					}
					
					if (slider.value < distance)
					{
						bitmapB.bitmapData.setPixel(x, y, 0xFFFFFF);
					}
				}
			}
		}
	}
}

class ColorPoint {
	
	private var _color:uint;
	
	public var red:int;
	public var green:int;
	public var blue:int;
	
	public var l:Number;
	public var a:Number;
	public var b:Number;
	
	public var x:Number;
	public var y:Number;
	public var z:Number;
	
	public var hue:int;
	public var lightness:Number;
	public var saturation:Number;
	public var value:Number;
	
	public function ColorPoint(color:uint = 0) 
	{
		this.color = color;
	}
	public function get color():uint { return _color; }
	public function set color(value:uint):void 
	{
		_color = value;
		red = (color & 0xFF0000) >>> 16;
		green = (color & 0xFF00) >>> 8;
		blue = (color & 0xFF);
	}
	public static function distanceLab(ca:ColorPoint, cb:ColorPoint):Number
	{
		ca.calcLab();
		cb.calcLab();
		
		var dl:Number = ca.l - cb.l;
		var da:Number = ca.a - cb.a;
		var db:Number = ca.b - cb.b;
		
		return d3(dl, da, db);
	}
	public static function distanceXYZ(ca:ColorPoint, cb:ColorPoint):Number
	{
		ca.calcXYZ();
		cb.calcXYZ();
		
		var dx:Number = ca.x - cb.x;
		var dy:Number = ca.y - cb.y;
		var dz:Number = ca.z - cb.z;
		
		return d3(dx, dy, dz);
	}
	public static function distanceHLS(ca:ColorPoint, cb:ColorPoint):Number
	{
		ca.calcHLS();
		cb.calcHLS();
		
		var dh:Number = ca.hue - cb.hue;
		var dl:Number = ca.lightness - cb.lightness;
		var ds:Number = ca.saturation - cb.saturation;
		
		return d3(dh, dl, ds);
	}
	public static function distanceRGB(ca:ColorPoint, cb:ColorPoint):Number
	{
		var dr:Number = ca.red - cb.red;
		var dg:Number = ca.green - cb.green;
		var db:Number = ca.blue - cb.blue;
		
		return d3(dr, dg, db);
	}
	public function calcHLS():void
	{
		var max:int = red;
		var min:int = red;
		
		if (max < green)
			max = green;
		if (max < blue)
			max = blue;
			
		if (green < min)
			min = green;
		if (blue < min)
			min = blue;
		
		var maxR:Number = max / 255;
		var minR:Number = min / 255;
		
		lightness = (maxR + minR) / 2;
		
		if (max == min) {
			saturation = 0;
			hue = 0;
		}
		else {
			saturation = lightness <= 0.5 ? (maxR - minR) / (maxR + minR) : (maxR - minR) / (2 - maxR - minR);
			var cr:Number = (maxR - red / 255) / (maxR - minR);
			var cg:Number = (maxR - green / 255) / (maxR - minR);
			var cb:Number = (maxR - blue / 255) / (maxR - minR);
			
			if (red == max)
				hue = (cb - cg) * 60;
			else if (green == max)
				hue = (2 + cr - cb) * 60;
			else
				hue = (4 + cg - cr) * 60;
			
			hue = (hue + 360) % 360;
		}
	}
	public function calcLab():void
	{
		calcXYZ();
		
		var fx:Number = f(x / 0.95045);
		var fy:Number = f(y);
		var fz:Number = f(z / 1.08892);
		
		l = 116 * fy - 16;
		a = 500 * (fx - fy);
		b = 200 * (fy - fz);
		
		function f(value:Number):Number
		{
			return value > 0.008856 ? Math.pow(value, 1 / 3) : (903.3 * value + 16) / 116;
		}
	}
	public function calcXYZ():void
	{
		x = (0.412391 * red/255 + 0.357584 * green/255 + 0.180481 * blue/255) * 100;
		y = (0.212639 * red/255 + 0.715169 * green/255 + 0.072192 * blue/255) * 100;
		z = (0.019331 * red/255 + 0.119195 * green/255 + 0.950532 * blue/255) * 100;
	}
	private static function d3(a:Number, b:Number, c:Number):Number
	{
		return Math.sqrt(a*a + b*b + c*c);
	}
}