forked from: 色の距離
左側画像をクリックしてください。
* クリックしたピクセルと同じような色を探して表示します。
*
* RGBを距離として捉える考え方です。
* 白に変換された部分は距離が遠い、つまり似た色ではないと判断できます。
*
* 閾値は下のスライダーで調整可能です。
均等色空間である L*a*b* 色空間と、ついでに XYZ, HLS 色空間を追加した
適切な閾値は色空間によってかわります
// 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);
}
}