450 votes

Formule permettant de déterminer la luminosité perçue d'une couleur RVB

Je cherche une formule ou un algorithme permettant de déterminer la luminosité d'une couleur à partir des valeurs RVB. Je sais que ça ne peut pas être aussi simple que d'additionner les valeurs RVB et d'avoir des sommes plus élevées pour une plus grande luminosité, mais je ne sais pas trop par où commencer.

10 votes

La luminosité perçue est ce que je pense rechercher, merci.

2 votes

Il existe un bon article ( Manipulation des couleurs en .NET - Partie 1 ) sur les espaces de couleur et les conversations entre eux, y compris la théorie et le code (C#). Pour la réponse, voir Conversion entre les modèles sujet dans l'article.

4 votes

Je suis membre depuis de nombreuses années, et je n'ai jamais fait cela auparavant. Puis-je vous suggérer de revoir les réponses et de repenser à celle que vous allez accepter ?

526voto

Anonymous Points 11017

La méthode peut varier en fonction de vos besoins. Voici 3 façons de calculer la luminance :

  • Luminance (standard pour certains espaces couleurs) : (0.2126*R + 0.7152*G + 0.0722*B) source img

  • Luminance (option 1 de perception) : (0.299*R + 0.587*G + 0.114*B) source img

  • Luminance (option 2 perçue, 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 ) source img

[Edition : ajout d'exemples utilisant des couleurs css nommées et triées avec chaque méthode].

33 votes

Notez que ces deux exemples mettent l'accent sur les aspects physiologiques : le globe oculaire humain est le plus sensible à la lumière verte, moins au rouge et moins au bleu.

0 votes

Oui, tout dépend de l'application. Tous ces modèles, y compris la perception subjective humaine...

19 votes

Notez également que toutes ces données sont probablement pour le RVB linéaire 0-1, et que vous avez probablement un RVB 0-255 corrigé en gamma. Ils ne sont pas convertis comme vous le pensez.

329voto

Franci Penov Points 45358

Je pense que ce que vous cherchez est le RGB -> Luma formule de conversion.

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

Y = 0.2126 R + 0.7152 G + 0.0722 B

Digital UIT BT.601 (donne plus de poids aux composantes R et B) :

Y = 0.299 R + 0.587 G + 0.114 B

Si vous êtes prêt à échanger la précision 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

On peut les calculer rapidement comme suit

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

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

52 votes

J'aime le fait que vous ayez indiqué des valeurs précises, mais aussi un raccourci rapide du type "assez proche". +1.

1 votes

Comment se fait-il que vos valeurs "calculées rapidement" n'incluent pas du tout le bleu dans l'approximation ?

3 votes

@Jonathan Dumaine - les deux formules de calcul rapide incluent toutes deux le bleu - la première est (2*Red + Blue + 3*Vert)/6, le 2ème est (3*Rouge + Blue + 4*Vert)>>3. Il est vrai que dans les deux approximations rapides, le bleu a le poids le plus faible, mais il est toujours là.

115voto

Petr Hurtak Points 84

J'ai fait une comparaison des trois algorithmes dans la réponse acceptée. J'ai généré des couleurs dans un cycle où seule une couleur sur 400 est utilisée. 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 photo - Luminance (relative)

0.2126 * R + 0.7152 * G + 0.0722 * B

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

0.299 * R + 0.587 * G + 0.114 * B

3ème photo - Modèle de couleur HSP

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

4ème photo - WCAG 2.0 SC 1.4.3 luminance relative y rapport de contraste formule (voir @Synchro's réponse aquí )

Un motif peut parfois être repéré sur la première et la deuxième image en fonction du nombre de couleurs dans une rangée. Je n'ai jamais vu de motif sur l'image du 3ème ou 4ème algorithme.

Si je devais choisir, j'opterais pour l'algorithme numéro 3, car il est beaucoup plus facile à mettre en œuvre et il est environ 33 % plus rapide que le quatrième.

Perceived brightness algorithm comparison

3 votes

Pour moi, c'est la meilleure réponse car vous utilisez un modèle d'image qui vous permet de percevoir si différentes teintes sont rendues avec la même luminance. Pour moi et mon moniteur actuel, la troisième image est la plus belle, car elle est aussi plus rapide que la quatrième, ce qui est un plus.

9 votes

Votre image de comparaison est incorrecte car vous n'avez pas fourni l'entrée correcte à toutes les fonctions. La première fonction requiert linéaire Je ne peux reproduire l'effet de bande qu'en fournissant une entrée RGB. non linéaire (c'est-à-dire corrigé en gamma) RVB. En corrigeant ce problème, vous n'obtenez aucun artefact de bande et la première fonction est clairement gagnante.

1 votes

@Max le ^2 y sqrt inclus dans la troisième formule sont un moyen plus rapide d'obtenir une approximation de RVB linéaire à partir de RVB non linéaire au lieu de la formule ^2.2 y ^(1/2.2) ce serait plus correct. L'utilisation d'entrées non linéaires au lieu d'entrées linéaires est malheureusement très courante.

64voto

Jive Dadson Points 3563

Voici le seul algorithme CORRECT pour convertir les images sRGB, telles qu'utilisées dans les navigateurs etc., en niveaux de gris.

Il est nécessaire d'appliquer un inverse de la fonction gamma pour l'espace couleur avant de calculer le produit interne. Ensuite, vous appliquez la fonction gamma à la valeur réduite. Le fait de ne pas intégrer la fonction gamma peut entraîner des erreurs allant jusqu'à 20 %.

Pour le matériel informatique typique, l'espace couleur est sRGB. Les bons chiffres pour sRGB sont approximativement 0,21, 0,72, 0,07. Le gamma pour sRGB est une fonction composite qui se rapproche de l'exponentiation par 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)
    );
}

0 votes

Pourquoi avez-vous utilisé une fonction composite pour approximer l'exposant ? Pourquoi ne pas simplement faire un calcul direct ? Merci

6 votes

C'est simplement la façon dont sRGB est défini. Je pense que la raison en est que cela permet d'éviter certains problèmes numériques à proximité de zéro. Cela ne ferait pas une grande différence si vous éleviez simplement les chiffres aux puissances de 2,2 et 1/2,2.

8 votes

JMD - dans le cadre de mon travail dans un laboratoire de perception visuelle, j'ai effectué des mesures directes de luminance sur des moniteurs CRT et je peux confirmer qu'il existe une région linéaire de luminance au bas de la gamme de valeurs.

11voto

sitesbyjoe Points 580

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.

1 votes

C'est exactement ce dont j'avais besoin. Je faisais une démonstration classique de "barres de couleur", et je voulais les étiqueter au-dessus de la couleur avec le meilleur choix de noir ou de blanc !

Prograide.com

Prograide est une communauté de développeurs qui cherche à élargir la connaissance de la programmation au-delà de l'anglais.
Pour cela nous avons les plus grands doutes résolus en français et vous pouvez aussi poser vos propres questions ou résoudre celles des autres.

Powered by:

X