2010-10-19 24 views
21

Sto cercando un modo per confrontare due colori per scoprire quanto sono simili. Non riesco a trovare risorse sull'argomento, quindi spero di ottenere alcuni suggerimenti qui.Confronta i colori RGB in C#

In teoria, vorrei ottenere un punteggio che indichi quanto siano simili. Ad esempio, da 0 a 100, dove 100 sarebbe uguale e 0 sarebbe completamente diverso.

Grazie!

Edit:

Conoscere un po 'di più su colori dalle risposte ho capito la mia domanda era un po' vago. Proverò a spiegare per cosa ho bisogno di questo.

Ho pixeldata (posizione e colore) di una finestra dell'applicazione a 800x600 dimensioni in modo da poter scoprire se una determinata finestra è aperta o non controllando ogni x-intervallo.

Tuttavia, questo metodo fallisce non appena l'applicazione viene ridimensionata (i contenuti vengono ridimensionati, non spostati). Posso calcolare dove si muovono i pixel, ma a causa dell'arrotondamento e dell'antializzazione il colore può essere leggermente diverso.

La soluzione di Pieter è stata abbastanza buona per me in questo caso, anche se tutte le altre risposte sono state estremamente utili, così ho semplicemente fatto pubblicità a tutti. Penso che la risposta di ColorEye sia la più accurata quando la si guarda da un punto di vista professionale, quindi l'ho contrassegnata come la risposta.

+5

Qual è la sua definizione di * * simili? –

+0

dovresti davvero dirci cosa vuoi realizzare qui? stai diffondendo secondo la percezione dell'occhio umano o qualcos'altro è in ordine? –

risposta

19

Quello che stai cercando si chiama Delta-E.

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

E 'la distanza tra due colori nello spazio di colore LAB. Si dice che l'occhio umano non possa distinguere i colori inferiori a 1 DeltaE (trovo che i miei occhi trovino differenze nei colori inferiori a 1 DeltaE, ogni persona è diversa.)

Ci sono 4 formule per "differenza di colore".

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

Controllare il link matematica su questo sito:

Quindi la risposta corretta è convertire il tuo RGB in LAB usando la formula data, quindi usa DeltaE 1976 per determinare la 'differenza' nei tuoi colori. Un risultato di 0 indica colori identici. Qualsiasi valore superiore a 0 potrebbe essere giudicato dalla regola "Un delta e di 1 o meno è indistinguibile dalla maggior parte delle persone".

+2

Grazie per la tua risposta, temevo che sarebbe stato complicato come questo. Segnerò la tua risposta poiché è la più accurata, anche se probabilmente andrò per una soluzione molto simile a quella di Pieter. – SaphuA

+1

Questo sito ha alcuni utili algoritmi di conversione (vedi http://www.easyrgb.com/index.php?X=MATH e http://www.easyrgb.com/index.php?X=DELT). – rsbarro

+0

Si noti che nello spazio colore Lab CIE 1976 è solo la distanza euclidea tra i punti, quindi 'DE = sqrt ((L2-L1)^2 + (a2-a1)^2 + (b2-b1)^2)'. – hruske

8

Qualcosa di simile a questo:

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

Grazie, penso di poter lavorare su questo per ora, anche se dovrò vedere quanto sia accurato. Ci sono alcuni errori nel codice (256 dovrebbe essere 255 e il risultato del cast di un int non è molto intelligente): D) – SaphuA

+2

Mentre suoni matematicamente questa non è una buona idea dato che non tiene conto di come i colori sono percepito. È possibile trovare facilmente coppie di colori simili ma che produrranno un punteggio basso e colori che sono dissimili ma che produrranno un punteggio elevato. –

+0

Sì hai ragione. Puoi fare tutto questo, ma questo è un modo veloce e sporco per ottenere una differenza prossima. Penso che i metodi di confronto "corretti" richiederebbero poche pagine :). –

12

colori hanno pesi diversi che interessano occhio umano. Quindi convertire i colori in scala di grigi con i loro pesi calcolati:

colore grigio = 0,11 * B + 0,59 * G + 0,30 * R

E la tua differenza sarà (GrayColor1 - GrayColor2) * 100.0/256.0

Questo è in realtà un approccio comunemente utilizzato e molto semplice utilizzato per calcolare le differenze di immagine nell'elaborazione dell'immagine.

-edit questa è la formula molto semplice e ancora utilizzabile - anche in applicazioni commerciali. Se si vuole andare in profondità si dovrebbe verificare i metodi di differenza di colore chiamato: CIE1976, CIE1994, CIE2000 e CMC Qui puoi trovare alcune informazioni più dettagliate: http://en.wikipedia.org/wiki/Color_difference

+3

Questo confronta solo la luminosità senza alcun riguardo per la tonalità. –

+1

Sì, è giusto. Ma è fondamentale e funziona nel mondo reale. Modificato la risposta con qualche informazione in più. – honibis

11

conversione del colore RGB allo spazio colore HSL spesso produce buoni risultati. Controlla wikipedia per la formula di conversione. Sta a te assegnare i pesi alle differenze in H, il colore, S, quanto 'profondo' è il colore e L, quanto è luminoso.

+2

Peso S più pesante degli altri di sicuro. I nostri occhi sono molto più sensibili ai cambiamenti di luminosità rispetto ai cambiamenti di colore. – Brad

11

C'è una libreria .net open-source che ti permette di fare questo facilmente: https://github.com/THEjoezack/ColorMine

Il metodo più comune per i colori confronto è 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

grazie per il link github. – rockXrock

1

ho trovato here un approccio interessante in Java e adattato per 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)); 
} 

spiegazione here

0

ho tradotto il codice per DeltaE2000 nella pagina di Bruce Lindbloom in C.

Qui:

 // 
    // 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 
        ) 
     ); 
    }