Domanda

Sto cercando una sorta di formula o algoritmo per determinare la luminosità di un colore dati i valori RGB. So che non può essere così semplice come aggiungere i valori RGB insieme e avere somme più elevate è più luminosa, ma sono in qualche modo in perdita su da dove cominciare.

È stato utile?

Soluzione

Intendi luminosità? Luminosità percepita? Luminanza?

  • Luminanza (standard per determinati spazi di colore): (0.2126*R + 0.7152*G + 0.0722*B) [1]
  • Luminanza (opzione percepita 1): (0.299*R + 0.587*G + 0.114*B) [2]
  • Luminanza (opzione percepita 2, più lenta da calcolare): sqrt( 0.241*R^2 + 0.691*G^2 + 0.068*B^2 )sqrt( 0.299*R^2 + 0.587*G^2 + 0.114*B^2 ) (grazie a @Matthewherbst) [3]

Altri suggerimenti

Penso che quello che stai cercando sia l'RGB -> Luma formula di conversione.

Fotometrico/digitale Itu Bt.709:

Y = 0.2126 R + 0.7152 G + 0.0722 B

Digitale Itu Bt.601 (dà più peso ai componenti R e B):

Y = 0.299 R + 0.587 G + 0.114 B

Se sei disposto a scambiare precisione per performance, ci sono due formule di approssimazione per questo:

Y = 0.33 R + 0.5 G + 0.16 B

Y = 0.375 R + 0.5 G + 0.125 B

Questi possono essere calcolati rapidamente come

Y = (R+R+B+G+G+G)/6

Y = (R+R+R+B+G+G+G+G)>>3

Ho fatto un confronto tra i tre algoritmi nella risposta accettata. Ho generato colori nel ciclo in cui venivano utilizzati solo circa ogni 400 ° colore. Ogni colore è rappresentato da pixel 2x2, i colori sono ordinati da più scuri a leggeri (da sinistra a destra, dall'alto verso il basso).

1a foto - Luminanza (relativo)

0.2126 * R + 0.7152 * G + 0.0722 * B

2a foto - http://www.w3.org/tr/aert#color-contrast

0.299 * R + 0.587 * G + 0.114 * B

3a foto - Modello di colore HSP

sqrt(0.299 * R^2 + 0.587 * G^2 + 0.114 * B^2)

4a foto - WCAG 2.0 SC 1.4.3 luminanza relativa e Rapporto di contrasto formula (vedi @Synchro's Rispondere qui)

Il motivo può essere talvolta individuato la prima e la seconda immagine a seconda del numero di colori in una riga. Non ho mai individuato alcun modello sull'immagine del 3 ° o 4 ° algoritmo.

Se dovessi scegliere, andrei con l'algoritmo numero 3 poiché è molto più facile da implementare ed è circa il 33% più veloce del 4 °.

Perceived brightness algorithm comparison

Di seguito è riportato l'unico algoritmo corretto per la conversione di immagini SRGB, come usato nei browser ecc. Per la scala di grigi.

È necessario applicare un inverso della funzione gamma per lo spazio colore prima di calcolare il prodotto interno. Quindi si applica la funzione gamma al valore ridotto. La mancata integrazione della funzione gamma può comportare errori fino al 20%.

Per le cose tipiche del computer, lo spazio colore è SRGB. I numeri giusti per SRGB sono ca. 0,21, 0,72, 0,07. Gamma per SRGB è una funzione composita che si avvicina all'esponentezione di 1/(2.2). Ecco tutto in C ++.

// sRGB luminance(Y) values
const double rY = 0.212655;
const double gY = 0.715158;
const double bY = 0.072187;

// Inverse of sRGB "gamma" function. (approx 2.2)
double inv_gam_sRGB(int ic) {
    double c = ic/255.0;
    if ( c <= 0.04045 )
        return c/12.92;
    else 
        return pow(((c+0.055)/(1.055)),2.4);
}

// sRGB "gamma" function (approx 2.2)
int gam_sRGB(double v) {
    if(v<=0.0031308)
        v *= 12.92;
    else 
        v = 1.055*pow(v,1.0/2.4)-0.055;
    return int(v*255+0.5); // This is correct in C++. Other languages may not
                           // require +0.5
}

// GRAY VALUE ("brightness")
int gray(int r, int g, int b) {
    return gam_sRGB(
            rY*inv_gam_sRGB(r) +
            gY*inv_gam_sRGB(g) +
            bY*inv_gam_sRGB(b)
    );
}

È interessante notare, Questa formulazione per RGB => HSV usa solo v = max3 (r, g, b). In altre parole, puoi usare il massimo di (r, g, b) come v in hsv.

Ho controllato e a pagina 575 di Hearn & Baker È così che calcolano anche il "valore".

From Hearn&Baker pg 319

ho trovato Questo codice (Scritto in C#) che fa un ottimo lavoro nel calcolo della "luminosità" di un colore. In questo scenario, il codice sta cercando di determinare se mettere il testo bianco o nero sul colore.

Per aggiungere ciò che tutti gli altri hanno detto:

Tutte queste equazioni funzionano un po 'bene in pratica, ma se devi essere molto preciso devi prima convertire il colore in spazio di colore lineare (applica l'immagine inversa inversa), fai la media del peso dei colori primari e - se lo si desidera Visualizza il colore: riportare la luminanza nella gamma monitor.

La differenza di luminanza tra gamma ingnoring e la gamma adeguata è fino al 20% nei grigi scuri.

Invece di perdersi tra la selezione casuale di formule menzionate qui, ti suggerisco di andare per la formula consigliata dagli standard W3C.

Ecco un'implementazione PHP semplice ma esatta del WCAG 2.0 SC 1.4.3 luminanza relativa e Rapporto di contrasto formule. Produce valori appropriati per la valutazione dei rapporti richiesti per la conformità WCAG, come su questa pagina, e come tale è adatto e appropriato per qualsiasi app Web. Questo è banale al porto verso altre lingue.

/**
 * Calculate relative luminance in sRGB colour space for use in WCAG 2.0 compliance
 * @link http://www.w3.org/TR/WCAG20/#relativeluminancedef
 * @param string $col A 3 or 6-digit hex colour string
 * @return float
 * @author Marcus Bointon <marcus@synchromedia.co.uk>
 */
function relativeluminance($col) {
    //Remove any leading #
    $col = trim($col, '#');
    //Convert 3-digit to 6-digit
    if (strlen($col) == 3) {
        $col = $col[0] . $col[0] . $col[1] . $col[1] . $col[2] . $col[2];
    }
    //Convert hex to 0-1 scale
    $components = array(
        'r' => hexdec(substr($col, 0, 2)) / 255,
        'g' => hexdec(substr($col, 2, 2)) / 255,
        'b' => hexdec(substr($col, 4, 2)) / 255
    );
    //Correct for sRGB
    foreach($components as $c => $v) {
        if ($v <= 0.03928) {
            $components[$c] = $v / 12.92;
        } else {
            $components[$c] = pow((($v + 0.055) / 1.055), 2.4);
        }
    }
    //Calculate relative luminance using ITU-R BT. 709 coefficients
    return ($components['r'] * 0.2126) + ($components['g'] * 0.7152) + ($components['b'] * 0.0722);
}

/**
 * Calculate contrast ratio acording to WCAG 2.0 formula
 * Will return a value between 1 (no contrast) and 21 (max contrast)
 * @link http://www.w3.org/TR/WCAG20/#contrast-ratiodef
 * @param string $c1 A 3 or 6-digit hex colour string
 * @param string $c2 A 3 or 6-digit hex colour string
 * @return float
 * @author Marcus Bointon <marcus@synchromedia.co.uk>
 */
function contrastratio($c1, $c2) {
    $y1 = relativeluminance($c1);
    $y2 = relativeluminance($c2);
    //Arrange so $y1 is lightest
    if ($y1 < $y2) {
        $y3 = $y1;
        $y1 = $y2;
        $y2 = $y3;
    }
    return ($y1 + 0.05) / ($y2 + 0.05);
}

La risposta "accettata" è errata e incompleta

Le uniche risposte accurate sono le @Jive-Dadson e @Eddingtonsmonkey Risposte e in supporto @nils-pipenbrinck. Le altre risposte (incluso il accettato) stanno collegando o citando fonti che sono sbagliate, irrilevanti, obsolete o rotte.

Brevemente:

  • SRGB deve essere Linearizzato Prima di applicare i coefficienti.
  • La luminanza (L o Y) è lineare come la luce.
  • La leggerezza percepita (L*) non è lineare come la percezione umana.
  • HSV e HSL non sono nemmeno lontanamente accurati in termini di percezione.
  • Lo standard IEC per SRGB specifica una soglia di 0,04045 è NON 0,03928 (che proveniva da una bozza obsoleta).
  • Essere utile (cioè relativo alla percezione), Le distanze euclidi richiedono uno spazio vettoriale cartesiano percettivamente uniforme come il Cielab. SRGB non è uno.

Ciò che segue è una risposta corretta e completa:

Poiché questo thread appare molto nei motori di ricerca, sto aggiungendo questa risposta per chiarire le varie idee sbagliate sull'argomento.

Luminosità è un attributo percettivo, non ha una misura diretta.

Percepita leggerezza è misurato da alcuni modelli di visione come Cielab, qui l* (lstar) è una misura di Lightness percettuale, ed è non lineare per approssimare la visione umana Curva di risposta non lineare.

Luminanza è una misura lineare della luce, ponderata spettralmente per la visione normale ma non regolata per la percezione non lineare della leggerezza.

Luma ( Prime) è un segnale gamma codificato e ponderato utilizzato in alcuni codifiche video. Non deve essere confuso con luminanza lineare.

Gamma o la curva di trasferimento (TRC) è una curva che è spesso simile alla curva percettiva ed è comunemente applicata ai dati delle immagini per l'archiviazione o trasmissione per ridurre il rumore percepito e/o migliorare l'utilizzo dei dati (e motivi correlati).

Per determinare la leggerezza percepita, prima convertire i valori dell'immagine R´g´b codificati in gamma alla luminanza lineare (L o Y ) e poi a una leggerezza percepita non lineare (L*)


Per trovare luminanza:

... perché a quanto pare si è perso da qualche parte ...

Primo passo:

Converti tutti i valori interi SRGB a 8 bit in decimale 0,0-1,0

  vR = sR / 255;
  vG = sG / 255;
  vB = sB / 255;

Passo due:

Convertire un RGB codificato in gamma in un valore lineare. Srgb (standard per computer), ad esempio, richiede una curva di potenza di circa V^2.2, sebbene la trasformazione "accurata" sia:

sRGB to Linear

Dove V´ è il canale R, G o B codificato da gamma di SRGB.
Pseudocodi:

function sRGBtoLin(colorChannel) {
        // Send this function a decimal sRGB gamma encoded color value
        // between 0.0 and 1.0, and it returns a linearized value.

    if ( colorChannel <= 0.04045 ) {
            return colorChannel / 12.92;
        } else {
            return pow((( colorChannel + 0.055)/1.055),2.4));
        }
    }

Passaggio terzo:

Per trovare la luminanza (Y) applicare i coefficienti standard per SRGB:

Apply coefficients Y = R * 0.2126 + G * 0.7152 + B *  0.0722

Pseudocodice usando le funzioni sopra:

Y = (0.2126 * sRGBtoLin(vR) + 0.7152 * sRGBtoLin(vG) + 0.0722 * sRGBtoLin(vB))

Per trovare la leggerezza percepita:

Passaggio quattro:

Prendi la luminanza y dall'alto e trasforma in l*

L* from Y equation
Pseudocodi:

function YtoLstar(Y) {
        // Send this function a luminance value between 0.0 and 1.0,
        // and it returns L* which is "perceptual lightness"

    if ( Y <= (216/24389) {       // The CIE standard states 0.008856 but 216/24389 is the intent for 0.008856451679036
            return Y * (24389/27);  // The CIE standard states 903.3, but 24389/27 is the intent, making 903.296296296296296
        } else {
            return pow(Y,(1/3)) * 116 - 16;
        }
    }

L* è un valore da 0 (nero) a 100 (bianco) dove 50 è il "grigio medio" percettivo. L* = 50 è l'equivalente di y = 18,4, o in altre parole una carta grigia al 18%, che rappresenta il centro di un'esposizione fotografica (Ansel Adams Zone V).

Riferimenti:

IEC 61966-2-1:1999 Standard
Wikipedia sRGB
Wikipedia CIELAB
Wikipedia CIEXYZ
FAQ gamma di Charles Poynton

Lo spazio colorato HSV dovrebbe fare il trucco, vedere il Articolo di Wikipedia A seconda della lingua in cui stai lavorando potrebbe ottenere una conversione della biblioteca.

H è tonalità che è un valore numerico per il colore (cioè rosso, verde ...)

S è la saturazione del colore, cioè quanto sia "intenso"

V è la "luminosità" del colore.

Valore di luminanza RGB = 0,3 R + 0,59 g + 0,11 B

http://www.scantips.com/lumin.html

Se stai cercando quanto sia vicino al bianco il colore puoi usare la distanza euclidea da (255, 255, 255)

Penso che lo spazio colore RGB sia percettivamente non uniforme rispetto alla distanza euclida L2. Gli spazi uniformi includono Cie Lab e Luv.

La formula inversa-gamma di Jive Dadson deve essere rimossa la metà quando implementata in JavaScript, ovvero il ritorno dalla funzione Gam_srgb deve essere restituito int (V*255); non restituire int (v*255+.5); La metà si aggiusta, e questo può causare un valore troppo alto su una triade di colore grigio r = b ie. La conversione della cassa su una triade r = g = b dovrebbe produrre un valore pari a R; È una prova che la formula è valida. Vedere Nove sfumature di Greyscale per la formula in azione (senza la metà regolata).

Ecco un po 'di codice C che dovrebbe calcolare correttamente la luminanza percepita.

// reverses the rgb gamma
#define inverseGamma(t) (((t) <= 0.0404482362771076) ? ((t)/12.92) : pow(((t) + 0.055)/1.055, 2.4))

//CIE L*a*b* f function (used to convert XYZ to L*a*b*)  http://en.wikipedia.org/wiki/Lab_color_space
#define LABF(t) ((t >= 8.85645167903563082e-3) ? powf(t,0.333333333333333) : (841.0/108.0)*(t) + (4.0/29.0))


float
rgbToCIEL(PIXEL p)
{
   float y;
   float r=p.r/255.0;
   float g=p.g/255.0;
   float b=p.b/255.0;

   r=inverseGamma(r);
   g=inverseGamma(g);
   b=inverseGamma(b);

   //Observer = 2°, Illuminant = D65 
   y = 0.2125862307855955516*r + 0.7151703037034108499*g + 0.07220049864333622685*b;

   // At this point we've done RGBtoXYZ now do XYZ to Lab

   // y /= WHITEPOINT_Y; The white point for y in D65 is 1.0

    y = LABF(y);

   /* This is the "normal conversion which produces values scaled to 100
    Lab.L = 116.0*y - 16.0;
   */
   return(1.16*y - 0.16); // return values for 0.0 >=L <=1.0
}

Mi chiedo come siano stati determinati quei coefficienti RGB. Ho fatto un esperimento da solo e ho finito con quanto segue:

Y = 0.267 R + 0.642 G + 0.091 B

Vicino ma ovviamente diverso dai coefficienti ITU stabiliti da tempo. Mi chiedo se quei coefficienti possano essere diversi per ogni singolo osservatore, perché tutti potremmo avere una quantità diversa di coni e canne sulla retina nei nostri occhi, e in particolare il rapporto tra i diversi tipi di coni può differire.

Per riferimento:

Itu bt.709:

Y = 0.2126 R + 0.7152 G + 0.0722 B

Itu bt.601:

Y = 0.299 R + 0.587 G + 0.114 B

Ho fatto il test spostando rapidamente una piccola barra grigia su uno sfondo rosso brillante, verde brillante e blu luminoso e regolando il grigio fino a quando non si fondeva il più possibile. Ho anche ripetuto quel test con altre tonalità. Ho ripetuto il test su display diversi, anche uno con un fattore gamma fisso di 3.0, ma mi sembra tutto lo stesso. Inoltre, i coefficienti ITU sono letteralmente sbagliati per i miei occhi.

E sì, presumibilmente ho una normale visione a colori.

Si prega di definire la luminosità. Se stai cercando quanto è vicino al bianco il colore puoi usare Distanza euclidea da (255, 255, 255)

La "V" di HSV è probabilmente quello che stai cercando. MATLAB ha una funzione RGB2HSV e l'articolo di Wikipedia precedentemente citato è pieno di pseudocodi. Se una conversione RGB2HSV non è fattibile, un modello meno accurato sarebbe la versione in scala di grigi dell'immagine.

Questo link Spiega tutto in profondità, incluso il motivo per cui quelle costanti moltiplicanti esistono prima dei valori R, G e B.

EDIT: ha una spiegazione anche a una delle risposte qui (0,299*R + 0,587*G + 0,114*B)

Per determinare la luminosità di un colore con R, converto il colore del sistema RGB nel colore del sistema HSV.

Nel mio script, utilizzo il codice di sistema esadecimale prima per altri motivi, ma puoi anche iniziare con il codice di sistema RGB con rgb2hsv {grDevices}. La documentazione è qui.

Ecco questa parte del mio codice:

 sample <- c("#010101", "#303030", "#A6A4A4", "#020202", "#010100")
 hsvc <-rgb2hsv(col2rgb(sample)) # convert HEX to HSV
 value <- as.data.frame(hsvc) # create data.frame
 value <- value[3,] # extract the information of brightness
 order(value) # ordrer the color by brightness

Per chiarezza, le formule che usano una radice quadrata devono essere

sqrt(coefficient * (colour_value^2))

non

sqrt((coefficient * colour_value))^2

La prova di questo risiede nella conversione di una triade r = g = b in Greyscale R. Questo sarà vero solo se si quadrate il valore del colore, non il coefficiente di valore del valore del colore. Vedere Nove sfumature di Greyscale

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top