Decidir si dos colores se parecen puede parecer sencillo, basta con medir la distancia entre ambos. En formato RGB la distancia entre dos colores es:
SQRT((R1-R2)^2 + (G1-G2)^2 + (B1-B2)^2)
Desgraciadamente no funciona demasiado bien en el espacio de color RGB, que es el que se usa habitualmente en los ordenadores , por lo que tenemos que usar otro espacio. Tenemos varias alternativas las más prometedoras son:
Vamos a apostar por el último que suele ser el que mejor funciona. Esta ideado para representar el espacio de color de forma próxima a como el ojo humano los percibe.
El primer problema es que no hay una conversión directa RGB a Lab. La solución es pasar de RGB a XYZ y luego de XYZ a Lab. En esas conversiones se pierde algo de precisión pero el resultado es lo suficientemente exacto.
Debajo está el código en JavaScript para realizar la conversión de RGB a LAB
function RGBtoLAB(r,g,b){
//RGBtoXYZ
var x = RGBtoXYZ_RtoX[r] + RGBtoXYZ_GtoX[g] + RGBtoXYZ_BtoX[b];
var y = RGBtoXYZ_RtoY[r] + RGBtoXYZ_GtoY[g] + RGBtoXYZ_BtoY[b];
var z = RGBtoXYZ_RtoZ[r] + RGBtoXYZ_GtoZ[g] + RGBtoXYZ_BtoZ[b];
if (x > 0.008856)
x = Math.cbrt(x);
else
x = (7.787 * x) + 0.13793103448275862;
if (y > 0.008856)
y = Math.cbrt(y);
else
y = (7.787 * y) + 0.13793103448275862;
if (z > 0.008856)
z = Math.cbrt(z);
else
z = (7.787 * z) + 0.13793103448275862;
L = (116 * y) - 16;
a = 500 * (x - y);
b = 200 * (y - z);
return [L,a,b];
}
RGBtoXYZ_RtoX = [];
RGBtoXYZ_GtoX = [];
RGBtoXYZ_BtoX = [];
RGBtoXYZ_RtoY = [];
RGBtoXYZ_GtoY = [];
RGBtoXYZ_BtoY = [];
RGBtoXYZ_RtoZ = [];
RGBtoXYZ_GtoZ = [];
RGBtoXYZ_BtoZ = [];
for(var i = 0; i < 256; i++){ //i from 0 to 255
r = parseFloat(i/255) ; //r from 0 to 1
if (r > 0.04045 )
r = Math.pow((r+0.055)/1.055 , 2.4);
else
r = r/12.92;
r = r * 100
var ref_X = 95.047;
var ref_Y = 100.000;
var ref_Z = 108.883;
RGBtoXYZ_RtoX[i] = r * 0.4124/ref_X;
RGBtoXYZ_GtoX[i] = r * 0.3576/ref_X;
RGBtoXYZ_BtoX[i] = r * 0.1805/ref_X;
RGBtoXYZ_RtoY[i] = r * 0.2126/ref_Y;
RGBtoXYZ_GtoY[i] = r * 0.7152/ref_Y;
RGBtoXYZ_BtoY[i] = r * 0.0722/ref_Y;
RGBtoXYZ_RtoZ[i] = r * 0.0193/ref_Z;
RGBtoXYZ_GtoZ[i] = r * 0.1192/ref_Z;
RGBtoXYZ_BtoZ[i] = r * 0.9505/ref_Z;
}
En el código se usan algunas optimizaciones como usar tablas de consulta para acelerar los cálculos (RGBtoXYX_*).
Los nuevos valores obtenidos ya se pueden comparar usando la distancia euclídea.
SQRT((L1-L2)^2 + (a1-a2)^2 + (b1-b2)^2)
El resultado indica la proximidad entre dos colores, lo parecidos que son. Como referencia un resultado menor de 4 quiere decir que la diferencia entre colores apenas es perceptible a simple vista. Eso no quiere decir que este valor solo se pueda usar para saber si dos colores son iguales, también para agrupar colores similares, encontrar un color en una imagen pese a variaciones de la iluminación (buscando el color más parecido) ,…
Veamos un ejemplo, unos de los puntos débiles más fáciles de ver del espacio de color RGB son los grises. Comparamos el gris medio (128,128,128) con otros dos colores: gris oscuro (28,28,28) y dorado oscuro (128,128,0). Veamos cual de los dos sistemas es más exacto.
RGB | Lab | |
Gris oscuro | 173,20 | 43,31 |
Dorado Oscuro | 128 | 58,16 |
Usando RGB el dorado oscuro está más cerca del gris medio que el gris oscuro, mientras que Lab da el resultado correcto.