2008-08-04 10 views
44

Original QuestionSeguimiento: Encontrar una "distancia" entre los colores exactos

Estoy buscando una función que intenta cuantificar la "lejana" (o distintas) son dos colores. Esta pregunta es realmente en dos partes:

  1. ¿Qué espacio de color representa mejor la visión humana?
  2. Qué distancia métrica en ese espacio representa mejor la visión humana (euclidiana?)
+1

que terminó el trazado de algunas de las soluciones a continuación cuando se trata de una situación similar. Otros pueden encontrar las parcelas http://stackoverflow.com/q/5774152/156755 interesante – Basic

Respuesta

43

Convierte a La * b * (también conocido simplemente como "Laboratorio", y también verás la referencia a "CIELAB"). Un buen measaure rápida de diferencia de color es

(L1-L2)^2 + (A1-A2)^2 + (B1-B2)^2

científicos de color tienen otras medidas más refinadas , lo que puede no valer la pena, dependiendo de la precisión necesaria para lo que estás haciendo.

Los valores a y b representan colores opuestos de forma similar a cómo funcionan los conos, y pueden ser negativos o positivos. Colores neutros: blanco, grises son a=0, b=0. El L es el brillo definido de una manera particular, desde cero (oscuridad absoluta) hasta lo que sea.

Explicación bruta: >> Dado un color, nuestros ojos distinguen entre dos amplios rangos de longitud de onda: azul frente a longitudes de onda más largas. y luego, gracias a una mutación genética más reciente, los conos de longitud de onda más largos se bifurcaron en dos, distinguiéndonos rojo contra verde. Por cierto, será grandioso que su carrera supere a sus colegas de color cavernícola que solo conocen "RGB" o "CMYK", que son excelentes para los dispositivos pero que aspiran a un trabajo de percepción serio. ¡He trabajado para científicos de imágenes que no sabían nada de esto!

Para más divertido leer sobre la teoría de la diferencia de color, pruebe:

Más detalles en Lab al http://en.kioskea.net/video/cie-lab.php3 No puedo encontrar en este momento una página no fea que en realidad tenga las fórmulas de conversión b Pero estoy seguro de que alguien editará esta respuesta para incluir una.

+4

En cuanto a la fealdad de las fórmulas de conversión : son feos por una razón, ya que pasar de RGB a XYZ a LAB depende de las condiciones de visualización. cf: (advertencia, la fealdad) http://www.easyrgb.com/index.php?X=MATH –

+1

Posiblemente sería la pena añadir una descripción de las métricas de distancia de color estándar y seudométricas definidos por la CIE: http: // en .wikipedia.org/wiki/Color_difference – BartoszKP

2

puede verse como spam, pero no, este enlace es muy interesante para los espacios de color :)

http://www.compuphase.com/cmetric.htm

+0

sólo se parece a su sitio web 90 promedio, lo que, conincidentally, es también un aspecto popular sitio web para 2010+ Académicos. – Domi

2

El la más fácil distancia sería, por supuesto, considerar los colores como vectores 3D que se originan en el mismo origen, y tomando la distancia entre sus puntos finales.

Si necesita considerar factores tales que el verde es más prominente al juzgar la intensidad, puede ponderar los valores.

ImageMagic proporciona las siguientes escalas:

  • rojo: 0,3
  • verde: 0,6
  • azul: 0,1

Por supuesto, valores como esto sólo sería significativo en relación con otros valores para otros colores, no como algo que sería significativo para los humanos, por lo que todo lo que podría usar para los valores sería el orden de similiaridad.

4

HSL y HSV son mejores para la percepción del color humano. Según Wikipedia:

a veces es preferible en el trabajo con materiales de la técnica, las imágenes digitalizadas, u otros medios de comunicación, para utilizar el modelo de HSV o color HSL sobre modelos alternativos tales como RGB o CMYK, debido a diferencias en las formas los modelos emulan cómo los humanos perciben el color. RGB y CMYK son modelos aditivos y sustractivos, respectivamente, que modelan la forma en que las luces de colores primarios o los pigmentos (respectivamente) se combinan para formar nuevos colores cuando se mezclan.

Graphical depiction of HSV

+0

Cuidado: el rojo está a 0 °, por lo que el rojo amarillento está a + 10 ° y el rojo azulado está a -10 ° o 350 °. Calcular la distancia no es tan fácil como restar los dos valores ahora. –

+2

No es realmente útil en el contexto de la otra respuesta. Las métricas definidas por CIE son mejores para la percepción del color humano que para HLS y HSV. – BartoszKP

+0

En este trabajo, no es una fórmula para la distancia de color en HSV http://citeseerx.ist.psu.edu/viewdoc/download?doi=10.1.1.84.2498&rep=rep1&type=pdf espacio – fyts

2

Bueno, como un primer punto de escala, yo diría que una de las métricas comunes HSV (matiz, saturación y valor) o HSL son mejores representativa de cómo los seres humanos perciben el color RGB o de decir CYMK. Ver HSL, HSV on Wikipedia.

Supongo ingenuamente trazar los puntos en el espacio HSL para los dos colores y calcular la magnitud del vector de diferencia. Sin embargo, esto significaría que el amarillo brillante y el verde brillante se considerarían tan diferentes como el verde o el verde oscuro. Pero luego muchos consideran rojo y rosa dos colores diferentes.

Además, los vectores de diferencia en la misma dirección en este espacio de parámetros no son iguales. Por ejemplo, el ojo humano toma el verde mucho mejor que otros colores. Un cambio en matiz de verde en la misma cantidad que un cambio de rojo puede parecer mayor.También un cambio en la saturación de una pequeña cantidad a cero es la diferencia entre el gris y el rosa, en otros lugares el cambio sería la diferencia entre dos tonos de rojo.

Desde el punto de vista de los programadores, tendría que trazar los vectores de diferencia, pero modificados por una matriz de proporcionalidad que ajustaría las longitudes según corresponda en varias regiones del espacio HSL; esto sería bastante arbitrario y estaría basado en varios las ideas de la teoría del color, pero deben ajustarse de forma bastante arbitraria según lo que desee aplicar a esto.

Aún mejor, se podía ver si alguien ya ha hecho tal cosa en línea ...

2

Como alguien que es daltónico, creo que es bueno intentar agregar más separación que la visión normal. La forma más común de daltonismo es la deficiencia de rojo/verde. No significa que no se puede ver rojo o verde, significa que es más difícil de ver y más difícil de ver las diferencias. Por lo tanto, se necesita una separación mayor antes de que una persona daltónica sepa la diferencia.

8

como cmetric.htm el enlace anterior falló para mí, así como muchas otras implementaciones para la distancia de color que encontré (después de una jurney muy larga).) La forma de calcular la mejor distancia de color y .. más científicamente exacta uno: delta E y de 2 RGB() valores usando OpenCV:

Esto requiere 3 conversiones de espacio de color + alguna conversión de código de JavaScript (http://svn.int64.org/viewvc/int64/colors/colors.js) a C++

Y por último el código (parece que funciona nada más sacarlo de la caja, espero que nadie encuentra un error grave allí ... pero parece bien después de una serie de pruebas)

#include <opencv2/core/core.hpp> 
#include <opencv2/imgproc/imgproc.hpp> 
#include <opencv2/highgui/highgui.hpp> 
#include <opencv2/photo/photo.hpp> 
#include <math.h> 

using namespace cv; 
using namespace std; 

#define REF_X 95.047; // Observer= 2°, Illuminant= D65 
#define REF_Y 100.000; 
#define REF_Z 108.883; 

void bgr2xyz(const Vec3b& BGR, Vec3d& XYZ); 
void xyz2lab(const Vec3d& XYZ, Vec3d& Lab); 
void lab2lch(const Vec3d& Lab, Vec3d& LCH); 
double deltaE2000(const Vec3b& bgr1, const Vec3b& bgr2); 
double deltaE2000(const Vec3d& lch1, const Vec3d& lch2); 


void bgr2xyz(const Vec3b& BGR, Vec3d& XYZ) 
{ 
    double r = (double)BGR[2]/255.0; 
    double g = (double)BGR[1]/255.0; 
    double b = (double)BGR[0]/255.0; 
    if(r > 0.04045) 
     r = pow((r + 0.055)/1.055, 2.4); 
    else 
     r = r/12.92; 
    if(g > 0.04045) 
     g = pow((g + 0.055)/1.055, 2.4); 
    else 
     g = g/12.92; 
    if(b > 0.04045) 
     b = pow((b + 0.055)/1.055, 2.4); 
    else 
     b = b/12.92; 
    r *= 100.0; 
    g *= 100.0; 
    b *= 100.0; 
    XYZ[0] = r * 0.4124 + g * 0.3576 + b * 0.1805; 
    XYZ[1] = r * 0.2126 + g * 0.7152 + b * 0.0722; 
    XYZ[2] = r * 0.0193 + g * 0.1192 + b * 0.9505; 
} 

void xyz2lab(const Vec3d& XYZ, Vec3d& Lab) 
{ 
    double x = XYZ[0]/REF_X; 
    double y = XYZ[1]/REF_X; 
    double z = XYZ[2]/REF_X; 
    if(x > 0.008856) 
     x = pow(x , .3333333333); 
    else 
     x = (7.787 * x) + (16.0/116.0); 
    if(y > 0.008856) 
     y = pow(y , .3333333333); 
    else 
     y = (7.787 * y) + (16.0/116.0); 
    if(z > 0.008856) 
     z = pow(z , .3333333333); 
    else 
     z = (7.787 * z) + (16.0/116.0); 
    Lab[0] = (116.0 * y) - 16.0; 
    Lab[1] = 500.0 * (x - y); 
    Lab[2] = 200.0 * (y - z); 
} 

void lab2lch(const Vec3d& Lab, Vec3d& LCH) 
{ 
    LCH[0] = Lab[0]; 
    LCH[1] = sqrt((Lab[1] * Lab[1]) + (Lab[2] * Lab[2])); 
    LCH[2] = atan2(Lab[2], Lab[1]); 
} 

double deltaE2000(const Vec3b& bgr1, const Vec3b& bgr2) 
{ 
    Vec3d xyz1, xyz2, lab1, lab2, lch1, lch2; 
    bgr2xyz(bgr1, xyz1); 
    bgr2xyz(bgr2, xyz2); 
    xyz2lab(xyz1, lab1); 
    xyz2lab(xyz2, lab2); 
    lab2lch(lab1, lch1); 
    lab2lch(lab2, lch2); 
    return deltaE2000(lch1, lch2); 
} 

double deltaE2000(const Vec3d& lch1, const Vec3d& lch2) 
{ 
    double avg_L = (lch1[0] + lch2[0]) * 0.5; 
    double delta_L = lch2[0] - lch1[0]; 
    double avg_C = (lch1[1] + lch2[1]) * 0.5; 
    double delta_C = lch1[1] - lch2[1]; 
    double avg_H = (lch1[2] + lch2[2]) * 0.5; 
    if(fabs(lch1[2] - lch2[2]) > CV_PI) 
     avg_H += CV_PI; 
    double delta_H = lch2[2] - lch1[2]; 
    if(fabs(delta_H) > CV_PI) 
    { 
     if(lch2[2] <= lch1[2]) 
      delta_H += CV_PI * 2.0; 
     else 
      delta_H -= CV_PI * 2.0; 
    } 

    delta_H = sqrt(lch1[1] * lch2[1]) * sin(delta_H) * 2.0; 
    double T = 1.0 - 
      0.17 * cos(avg_H - CV_PI/6.0) + 
      0.24 * cos(avg_H * 2.0) + 
      0.32 * cos(avg_H * 3.0 + CV_PI/30.0) - 
      0.20 * cos(avg_H * 4.0 - CV_PI * 7.0/20.0); 
    double SL = avg_L - 50.0; 
    SL *= SL; 
    SL = SL * 0.015/sqrt(SL + 20.0) + 1.0; 
    double SC = avg_C * 0.045 + 1.0; 
    double SH = avg_C * T * 0.015 + 1.0; 
    double delta_Theta = avg_H/25.0 - CV_PI * 11.0/180.0; 
    delta_Theta = exp(delta_Theta * -delta_Theta) * (CV_PI/6.0); 
    double RT = pow(avg_C, 7.0); 
    RT = sqrt(RT/(RT + 6103515625.0)) * sin(delta_Theta) * -2.0; // 6103515625 = 25^7 
    delta_L /= SL; 
    delta_C /= SC; 
    delta_H /= SH; 
    return sqrt(delta_L * delta_L + delta_C * delta_C + delta_H * delta_H + RT * delta_C * delta_H); 
} 

espero que ayuda a alguien :)

Cuestiones relacionadas