web-dev-qa-db-fra.com

Formule pour déterminer la luminosité de la couleur RVB

Je recherche une formule ou un algorithme pour déterminer la luminosité d'une couleur en fonction des valeurs RVB. Je sais que ce ne peut pas être aussi simple que d’additionner les valeurs RVB et d’avoir des sommes plus élevées plus brillantes, mais je ne sais pas trop par où commencer.

358
robmerica

Voulez-vous dire la luminosité? Luminosité perçue? Luminance?

  • Luminance (standard pour certains espaces colorimétriques): (0.2126*R + 0.7152*G + 0.0722*B)[1]
  • Luminance (option perçue 1): (0.299*R + 0.587*G + 0.114*B)[2]
  • Luminance (option perçue 2, plus lente à calculer): 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 ) (merci à @ MatthewHerbst ) [3]
435
Anonymous

Je pense que vous recherchez la formule de conversion RVB -> Luma .

Photométrique/numérique ITU BT.709 :

Y = 0.2126 R + 0.7152 G + 0.0722 B

Numérique ITU BT.601 (donne plus de poids aux composants R et B):

Y = 0.299 R + 0.587 G + 0.114 B

Si vous êtes prêt à échanger l'exactitude contre la performance, il existe deux formules d'approximation pour celle-ci:

Y = 0.33 R + 0.5 G + 0.16 B

Y = 0.375 R + 0.5 G + 0.125 B

Ceux-ci peuvent être calculés rapidement comme

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

Y = (R+R+R+B+G+G+G+G)>>3
283
Franci Penov

J'ai comparé les trois algorithmes dans la réponse acceptée. J'ai généré des couleurs dans un cycle où seulement environ 400 couleurs étaient utilisées. Chaque couleur est représentée par 2x2 pixels, les couleurs sont triées du plus foncé au plus clair (de gauche à droite, de haut en bas).

1ère image - Luminance (relative)

0.2126 * R + 0.7152 * G + 0.0722 * B

2ème image - http://www.w3.org/TR/AERT#color-contrast

0.299 * R + 0.587 * G + 0.114 * B

3ème image - Modèle couleur HSP

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

4ème image - WCAG 2.0 SC 1.4.luminance relative et taux de contraste formule (voir @ Synchro's répondre ici )

Les motifs peuvent parfois être repérés sur les 1ère et 2ème images en fonction du nombre de couleurs d'une rangée. Je n'ai jamais repéré aucun motif sur l'image du 3ème ou 4ème algorithme.

Si je devais choisir, je choisirais l'algorithme 3, car il est beaucoup plus facile à mettre en œuvre et environ 33% plus rapide que le 4ème.

Perceived brightness algorithm comparison

96
Petr Hurtak

Vous trouverez ci-dessous le seul algorithme CORRECT permettant de convertir les images sRVB, telles qu’elles sont utilisées dans les navigateurs, en niveaux de gris.

Il est nécessaire d'appliquer un inverse de la fonction gamma pour l'espace colorimétrique avant de calculer le produit intérieur. Ensuite, vous appliquez la fonction gamma à la valeur réduite. Ne pas incorporer la fonction gamma peut entraîner des erreurs allant jusqu'à 20%.

Pour les tâches informatiques typiques, l’espace colorimétrique est sRGB. Les bons chiffres pour sRGB sont env. 0,21, 0,72, 0,07. Gamma pour sRGB est une fonction composite qui approxime l'exponentiation de 1/(2.2). Voici le tout en 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)
    );
}
44
Jive Dadson

J'ai trouvé ce code (écrit en C #) qui fait un excellent travail de calcul de la "luminosité" d'une couleur. Dans ce scénario, le code essaie de déterminer s'il faut mettre du texte blanc ou noir sur la couleur.

10
sitesbyjoe

Fait intéressant, cette formulation pour RGB => HSV utilise seulement v = MAX3 (r, g, b). En d'autres termes, vous pouvez utiliser le maximum de (r, g, b) comme V dans HSV.

J'ai vérifié et à la page 575 de Hearn & Baker c'est ainsi qu'ils calculent la "valeur" également.

From Hearn&Baker pg 319

10
bobobobo

Plutôt que de vous perdre dans la sélection aléatoire des formules mentionnées ici, je vous suggère d’opter pour la formule recommandée par les normes W3C.

Voici une implémentation PHP simple mais exacte de WCAG 2.0 SC 1.4.luminance relative et rapport de contraste formules. Il génère des valeurs appropriées pour évaluer les ratios requis pour la conformité WCAG, comme sur cette page , et en tant que telles, convient à toutes les applications Web. Ceci est trivial pour porter à d'autres langues.

/**
 * 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 <[email protected]>
 */
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 <[email protected]>
 */
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);
}
8
Synchro

Pour ajouter ce que tous les autres ont dit:

Toutes ces équations fonctionnent assez bien dans la pratique, mais si vous devez être très précis, vous devez d’abord convertir la couleur en un espace colorimétrique linéaire (appliquez l’image inverse du gamma), effectuez la moyenne pondérée des couleurs primaires et - si vous le souhaitez. afficher la couleur - ramenez la luminance dans le gamma du moniteur.

La différence de luminance entre maîtriser le gamma et réaliser le gamma approprié va jusqu'à 20% chez les gris sombres.

8
Nils Pipenbrinck

La réponse "acceptée" est incorrecte et incomplète

Les seules réponses qui soient exactes sont les réponses @ jive-dadson et @ EddingtonsMonkey , et à l'appui @ nils-pipenbrinck . Les autres réponses (y compris les acceptées) renvoient à ou citent des sources erronées, non pertinentes, obsolètes ou endommagées.

Brièvement:

  • sRGB doit être LINÉARISÉ avant d'appliquer les coefficients.
  • La luminance (L ou Y) est linéaire comme la lumière.
  • La légèreté perçue (L *) est non linéaire, tout comme la perception humaine.
  • HSV et HSL ne sont même pas très précis en termes de perception.
  • La norme IEC pour sRGB spécifie un seuil de 0,04045 soit PAS 0,03928 (qui correspond à une version antérieure obsolète).
  • Pour être utile (c'est-à-dire par rapport à la perception) , les distances euclidiennes nécessitent un espace vectoriel cartésien perceptuellement uniforme, tel que CIELAB. sRGB n'est pas un.

Ce qui suit est une réponse correcte et complète:

Étant donné que ce fil de discussion apparaît fortement dans les moteurs de recherche, j'ajoute cette réponse pour clarifier les différentes idées fausses sur le sujet.

La luminosité est un attribut perceptuel, elle n'a pas de mesure directe.

La légèreté perçue est mesurée par certains modèles de vision tels que CIELAB, ici L * (Lstar) est une mesure de légèreté perceptuelle , et est non linéaire pour se rapprocher de la courbe de réponse non linéaire de la vision humaine.

La luminance est une mesure linéaire de la lumière pondérée spectralement pour une vision normale mais non ajustée pour une perception non linéaire de la luminosité.

Luma ( prime) est un signal pondéré gamma utilisé dans certains codages vidéo. Il ne faut pas le confondre avec la luminance linéaire.

Le gamma ou courbe de transfert (TRC) est une courbe souvent similaire à la courbe de perception, et est couramment appliquée aux données d'image pour le stockage ou la diffusion afin de réduire bruit perçu et/ou améliorer l'utilisation des données (et les raisons connexes).

Pour déterminer la luminosité perçue , convertissez d’abord les valeurs d’image R´G´B´ encodées en gamma en luminance linéaire (L ou Y), puis à une luminosité perçue non linéaire (L*)


POUR TROUVER LA LUMINANCE:

... Parce qu'apparemment il a été perdu quelque part ...

La première étape:

Convertir toutes les valeurs sRGB sur 8 bits en valeurs décimales 0.0-1.0

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

Deuxième étape:

Convertit un RVB codé gamma en une valeur linéaire. sRGB (standard informatique), par exemple, nécessite une courbe de puissance d'environ V ^ 2,2, bien que la transformation "précise" soit:

sRGB to Linear

Où V´ est le canal R, G ou B codé en gamma de sRGB.
Pseudocode:

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

Troisième étape:

Pour trouver la luminance (Y), appliquez les coefficients standard pour sRGB:

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

Pseudocode utilisant les fonctions ci-dessus:

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

POUR TROUVER LA LUMINOSITÉ PERÇUE:

Quatrième étape:

Prendre la luminance Y d'en haut et la transformer en L *

L* from Y equation
Pseudocode:

_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 * est une valeur de 0 (noir) à 100 (blanc), 50 étant le "gris moyen" perceptuel. L * = 50 est l'équivalent de Y = 18,4 ou, en d'autres termes, une carte grise à 18% représentant le milieu d'une exposition photographique (zone V d'Ansel Adams).

Références:

IEC 61966-2-1:1999 Standard
Wikipedia sRGB
Wikipedia CIELAB
Wikipedia CIEXYZ
FAQ Gamma de Charles Poynton

7
Myndex

L’espace colorimétrique HSV devrait faire l'affaire, voir l'article de wikipedia , selon la langue dans laquelle vous travaillez, vous risquez d'obtenir un conversion de bibliothèque.

H est la teinte qui est une valeur numérique pour la couleur (c'est-à-dire le rouge, le vert ...)

S est la saturation de la couleur, c’est-à-dire à quel point elle est "intense"

V est la "luminosité" de la couleur.

1
Ian Hopkinson

Valeur de luminance RVB = 0,3 R + 0,59 G + 0,11 B

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

Si vous cherchez à quel point le blanc est proche de la couleur, vous pouvez utiliser Distance euclidienne à partir de (255, 255, 255).

Je pense que l’espace colorimétrique RVB est non uniforme du point de vue de la perception de la distance euclidienne L2. Les espaces uniformes incluent CIE LAB et LUV.

1
Gandalf

Voici un peu de code C qui devrait calculer correctement la luminance perçue.

// 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
}
1
EddingtonsMonkey

Je me demande comment ces coefficients RGB ont été déterminés. J'ai fait une expérience moi-même et je me suis retrouvé avec ce qui suit:

Y = 0.267 R + 0.642 G + 0.091 B

Proche mais évidemment différent des coefficients de l’ITU établis depuis longtemps. Je me demande si ces coefficients pourraient être différents pour chaque observateur, car nous pourrions tous avoir une quantité différente de cônes et de bâtonnets sur la rétine de nos yeux, et en particulier le rapport entre les différents types de cônes pourrait être différent.

Pour référence:

UIT 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

J'ai fait le test en déplaçant rapidement une petite barre grise sur un fond rouge vif, vert vif et bleu vif, et en ajustant le gris jusqu'à ce qu'il se confonde autant que possible. J'ai également répété ce test avec d'autres nuances. J'ai répété le test sur différents écrans, même avec un facteur gamma de 3,0, mais cela me semble identique. De plus, les coefficients de l'UIT sont littéralement faux pour mes yeux.

Et oui, je suppose que ma vision des couleurs est normale.

1
vortex

La formule gamma inverse de Jive Dadson doit supprimer le demi-ajustement lorsqu’elle est implémentée en Javascript, c’est-à-dire que le retour de la fonction gam_sRGB doit être return int (v * 255); ne retourne pas int (v * 255 + .5); Ajustez les arrondis à moitié, ce qui peut entraîner une valeur 1 trop élevée sur un trièdre de couleur R = G = B, c'est-à-dire gris. La conversion en niveaux de gris sur un trièdre R = G = B devrait produire une valeur égale à R; c'est une preuve que la formule est valide. Voir Neuf nuances de gris pour la formule en action (sans le demi-réglage).

1
Dave Collier

S'il vous plaît définir la luminosité. Si vous cherchez à quel point la couleur est proche du blanc, vous pouvez utiliser Distance euclidienne à partir de (255, 255, 255)

0
Ben S

Le "V" du HSV est probablement ce que vous recherchez. MATLAB a une fonction rgb2hsv et l'article de Wikipédia précédemment cité est rempli de pseudocodes. Si une conversion RGB2HSV n'est pas possible, un modèle moins précis serait la version en niveaux de gris de l'image.

0
Jacob

Pour plus de clarté, les formules qui utilisent une racine carrée doivent être

sqrt(coefficient * (colour_value^2))

ne pas

sqrt((coefficient * colour_value))^2

La preuve en est la conversion d'un trièdre R = G = B en niveaux de gris R. Cela ne sera vrai que si vous égalisez la valeur de la couleur, et non la valeur de la couleur par son coefficient. Voir Neuf nuances de gris

0
Dave Collier

Pour déterminer la luminosité d'une couleur avec R, je convertis la couleur système RVB en couleur système HSV.

Dans mon script, j'utilise le code système HEX auparavant pour une autre raison, mais vous pouvez également commencer avec le code système RVB avec rgb2hsv {grDevices}. La documentation est ici .

Voici cette partie de mon code:

 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
0

Ce lien explique tout en profondeur, y compris pourquoi ces constantes de multiplicateur existent avant les valeurs R, G et B.

Edit: Il y a une explication à l’une des réponses ici aussi (0.299 * R + 0.587 * G + 0.114 * B)

0
dsignr