2010-10-19 35 views
21

Estoy tratando de encontrar una manera de comparar dos colores para descubrir cuánto se parecen. Parece que no puedo encontrar ningún recurso sobre el tema, así que espero obtener algunos consejos aquí.Comparar colores RGB en C#

Idealmente, me gustaría obtener un puntaje que diga cuánto se parecen. Por ejemplo, de 0 a 100, donde 100 sería igual y 0 sería totalmente diferente.

Gracias!

Editar:

Llegar a conocer un poco más acerca de los colores de las respuestas entiendo que mi pregunta era un poco vago. Trataré de explicar para qué necesitaba esto.

Tengo pixeldata (ubicación y color) de una ventana de la aplicación en un tamaño de 800x600 para poder averiguar si una determinada ventana está abierta o no al verificar cada intervalo x.

Sin embargo, este método falla tan pronto como se cambia el tamaño de la aplicación (los contenidos se cambian de escala, no se mueven). Puedo calcular dónde se mueven los píxeles, pero debido al redondeo y antialising, el color puede ser ligeramente diferente.

La solución de Pieter fue lo suficientemente buena para mí en este caso, aunque todas las otras respuestas fueron extremadamente útiles también, así que acabo de votar a todos. Creo que la respuesta de ColorEye es la más precisa cuando se mira desde una perspectiva profesional, por lo que la marqué como la respuesta.

+5

¿Cuál es su definición de * * por igual? –

+0

¿realmente debería decirnos qué quiere lograr aquí? ¿Estás difiriendo según la percepción del ojo humano, o hay algo más en orden? –

Respuesta

19

Lo que estás buscando se llama Delta-E.

http://www.colorwiki.com/wiki/Delta_E:_The_Color_Difference

Es la distancia entre dos colores en el espacio de color LAB. Se dice que el ojo humano no puede distinguir colores por debajo de 1 DeltaE (me parece que mis ojos pueden encontrar diferencias en colores por debajo de 1 DeltaE, cada persona es diferente).

Hay 4 fórmulas para 'diferencia de color'.

  • Delta E (CIE 1976)
  • Delta E (CIE 1994)
  • Delta E (CIE 2000)
  • Delta E (CMC)

Compruebe el enlace de matemáticas en este sitio:

Así que la respuesta correcta es convertir su RGB en LAB utilizando la fórmula dada, luego use DeltaE 1976 para determinar la 'diferencia' en sus colores. Un resultado de 0 indicaría colores idénticos. Cualquier valor superior a 0 podría ser juzgado por la regla "Un delta e de 1 o menos es indistinguible para la mayoría de la gente".

+2

Gracias por su respuesta, temía que fuera algo tan complicado como esto. Marcaré su respuesta ya que es la más precisa, aunque probablemente vaya por una solución muy parecida a la de Pieter. – SaphuA

+1

Este sitio tiene algunos algoritmos de conversión útiles (vea http://www.easyrgb.com/index.php?X=MATH y http://www.easyrgb.com/index.php?X=DELT). – rsbarro

+0

Tenga en cuenta que en Lab el espacio de color CIE 1976 es solo la distancia euclídea entre puntos, entonces 'DE = sqrt ((L2-L1)^2 + (a2-a1)^2 + (b2-b1)^2)'. – hruske

8

Algo como esto:

public static int CompareColors(Color a, Color b) 
    { 
     return 100 * (int)(
      1.0 - ((double)(
       Math.Abs(a.R - b.R) + 
       Math.Abs(a.G - b.G) + 
       Math.Abs(a.B - b.B) 
      )/(256.0 * 3)) 
     ); 
    } 
+0

Gracias, creo que puedo trabajar con esto por ahora, aunque tendré que ver qué tan preciso es esto. Sin embargo, hay algunos errores en el código (256 deberían ser 255 y arrojar el resultado a un int. No es muy inteligente tampoco: D) – SaphuA

+2

Si bien es matemáticamente correcto, esta no es una buena idea ya que no toma en cuenta cómo son los colores percibido. Puede encontrar fácilmente pares de colores que son similares pero que arrojarán un puntaje bajo y colores que son diferentes, pero producirán un puntaje alto. –

+0

Sí, tienes razón. Puedes salir con esto, pero esta es una forma rápida y sucia de obtener una diferencia próxima. Creo que los métodos de comparación "correctos" tomarían algunas páginas :). –

12

colores tienen diferentes pesos que afectan el ojo humano. Así convertir los colores a escala de grises utilizando sus pesos calculados:

gris color = 0,11 * B + 0,59 * G + 0,30 * R

Y su diferencia será (GrayColor1 - GrayColor2) * 100.0/256.0

Este es un enfoque muy común y muy simple que se usa para calcular las diferencias de imagen en el procesamiento de imágenes.

-edit esta es la fórmula muy simple y aún utilizable, incluso en aplicaciones comerciales. Si desea profundizar los que debe salir los métodos de diferencia de color se llama: CIE1976, CIE1994, CIE2000 y CMC Aquí puede encontrar algo de información más detallada: http://en.wikipedia.org/wiki/Color_difference

+3

Eso solo compara la luminosidad sin tener en cuenta el tono. –

+1

Sí, eso es correcto. Pero es básico y funciona en el mundo real. Editó la respuesta con más información. – honibis

11

conversión de color RGB al espacio de color HSL menudo produce buenos resultados Compruebe wikipedia para ver la fórmula de conversión. Depende de usted asignar pesos a las diferencias en H, el color, S, qué tan "profundo" es el color y L, qué tan brillante es.

+2

Peso L más pesado que los otros con certeza. Nuestros ojos son mucho más sensibles a los cambios de brillo que a los cambios de color. – Brad

11

Hay una biblioteca .NET de código abierto que le permite hacer esto fácilmente: https://github.com/THEjoezack/ColorMine

El método más común para los colores que comparaban es CIE76:

var a = new Rgb { R = 149, G = 13, B = 12 } 
var b = new Rgb { R = 255, G = 13, B = 12 } 

var deltaE = a.Compare(b,new Cie1976Comparison()); 
+0

gracias por el enlace github. – rockXrock

1

me encontré here un enfoque interesante en Java y adaptado a C#

public static double ColourDistance(Color e1, Color e2) 
{ 
    long rmean = ((long)e1.R + (long)e2.R)/2; 
    long r = (long)e1.R - (long)e2.R; 
    long g = (long)e1.G - (long)e2.G; 
    long b = (long)e1.B - (long)e2.B; 
    return Math.Sqrt((((512 + rmean) * r * r) >> 8) + 4 * g * g + (((767 - rmean) * b * b) >> 8)); 
} 

explicación here

0

he traducido el código para DeltaE2000 en la página de Bruce C. Lindbloom en

aquí:

 // 
    // deltae2000.c 
    // 
    // Translated by Dr Cube on 10/1/16. 
    // Translated to C from this javascript code written by Bruce LindBloom: 
    // http://www.brucelindbloom.com/index.html?Eqn_DeltaE_CIE2000.html 
    // http://www.brucelindbloom.com/javascript/ColorDiff.js 

    #include <stdio.h> 
    #include <math.h> 

    #define Lab2k struct Lab2kStruct 
    Lab2k 
    { 
     float L; 
     float a; 
     float b; 
    }; 

    // function expects Lab where: 0 >= L <=100.0 , -100 >=a <= 100.0 and -100 >= b <= 100.0 

    float 
    DeltaE2000(Lab2k Lab1,Lab2k Lab2) 
    { 
     float kL = 1.0; 
     float kC = 1.0; 
     float kH = 1.0; 
     float lBarPrime = 0.5 * (Lab1.L + Lab2.L); 
     float c1 = sqrtf(Lab1.a * Lab1.a + Lab1.b * Lab1.b); 
     float c2 = sqrtf(Lab2.a * Lab2.a + Lab2.b * Lab2.b); 
     float cBar = 0.5 * (c1 + c2); 
     float cBar7 = cBar * cBar * cBar * cBar * cBar * cBar * cBar; 
     float g = 0.5 * (1.0 - sqrtf(cBar7/(cBar7 + 6103515625.0))); /* 6103515625 = 25^7 */ 
     float a1Prime = Lab1.a * (1.0 + g); 
     float a2Prime = Lab2.a * (1.0 + g); 
     float c1Prime = sqrtf(a1Prime * a1Prime + Lab1.b * Lab1.b); 
     float c2Prime = sqrtf(a2Prime * a2Prime + Lab2.b * Lab2.b); 
     float cBarPrime = 0.5 * (c1Prime + c2Prime); 
     float h1Prime = (atan2f(Lab1.b, a1Prime) * 180.0)/M_PI; 
     float dhPrime; // not initialized on purpose 

     if (h1Prime < 0.0) 
      h1Prime += 360.0; 
     float h2Prime = (atan2f(Lab2.b, a2Prime) * 180.0)/M_PI; 
     if (h2Prime < 0.0) 
      h2Prime += 360.0; 
     float hBarPrime = (fabsf(h1Prime - h2Prime) > 180.0) ? (0.5 * (h1Prime + h2Prime + 360.0)) : (0.5 * (h1Prime + h2Prime)); 
     float t = 1.0 - 
     0.17 * cosf(M_PI * (  hBarPrime - 30.0)/180.0) + 
     0.24 * cosf(M_PI * (2.0 * hBarPrime  )/180.0) + 
     0.32 * cosf(M_PI * (3.0 * hBarPrime + 6.0)/180.0) - 
     0.20 * cosf(M_PI * (4.0 * hBarPrime - 63.0)/180.0); 
     if (fabsf(h2Prime - h1Prime) <= 180.0) 
      dhPrime = h2Prime - h1Prime; 
     else 
      dhPrime = (h2Prime <= h1Prime) ? (h2Prime - h1Prime + 360.0) : (h2Prime - h1Prime - 360.0); 
     float dLPrime = Lab2.L - Lab1.L; 
     float dCPrime = c2Prime - c1Prime; 
     float dHPrime = 2.0 * sqrtf(c1Prime * c2Prime) * sinf(M_PI * (0.5 * dhPrime)/180.0); 
     float sL = 1.0 + ((0.015 * (lBarPrime - 50.0) * (lBarPrime - 50.0))/sqrtf(20.0 + (lBarPrime - 50.0) * (lBarPrime - 50.0))); 
     float sC = 1.0 + 0.045 * cBarPrime; 
     float sH = 1.0 + 0.015 * cBarPrime * t; 
     float dTheta = 30.0 * expf(-((hBarPrime - 275.0)/25.0) * ((hBarPrime - 275.0)/25.0)); 
     float cBarPrime7 = cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime * cBarPrime; 
     float rC = sqrtf(cBarPrime7/(cBarPrime7 + 6103515625.0)); 
     float rT = -2.0 * rC * sinf(M_PI * (2.0 * dTheta)/180.0); 
     return(sqrtf(
          (dLPrime/(kL * sL)) * (dLPrime/(kL * sL)) + 
          (dCPrime/(kC * sC)) * (dCPrime/(kC * sC)) + 
          (dHPrime/(kH * sH)) * (dHPrime/(kH * sH)) + 
          (dCPrime/(kC * sC)) * (dHPrime/(kH * sH)) * rT 
        ) 
     ); 
    }