Quelles sont les différences pratiques lorsque vous travaillez avec des couleurs dans un espace RVB linéaire et non linéaire?


88

Quelle est la propriété de base d'un espace RVB linéaire et quelle est la propriété fondamentale d'un espace non linéaire? Quand on parle des valeurs à l'intérieur de chaque canal dans ces 8 bits (ou plus), qu'est-ce qui change?

Dans OpenGL, les couleurs sont des valeurs 3 + 1, et avec cela, je veux dire RVB + alpha, avec 8 bits réservés à chaque canal, et c'est la partie que j'obtiens clairement.

Mais en ce qui concerne la correction gamma, je ne comprends pas quel est l'effet de travailler dans un espace RVB non linéaire.

Puisque je sais utiliser une courbe dans un logiciel graphique pour la retouche photo, mon explication est que dans un espace RVB linéaire, vous prenez les valeurs telles qu'elles sont, sans manipulation et sans fonction mathématique attachée, à la place quand elles sont non linéaires chacune le canal évolue généralement selon un comportement classique de la fonction de puissance.

Même si je prends cette explication comme la vraie, je ne comprends toujours pas ce qu'est un espace linéaire réel, car après le calcul, tous les espaces RVB non linéaires deviennent linéaires et le plus important de tous, je n'obtiens pas la partie où -L'espace colorimétrique linéaire est plus adapté à l'œil humain car à la fin, tous les espaces RVB sont linéaires pour ce que je comprends.


Sur une note pratique, vous pouvez spécifier un RVB linéaire ou standard comme espace colorimétrique en SVG et je n'ai aucune idée de l'effet, mis à part le fait que cela semble être important :-)
Michael Mullany

@MichaelMullany cette chose linéaire ressemble plus à un indice pour l'utilisateur qu'à une vraie qualité distinctive.
Ken

Quelque chose qui m'a aidé: je pense que c'est un professeur de mathématiques qui m'a dit "pense à la ligne quand tu entends linéaire". Je ne sais pas si cela aide, mais pour moi, c'était un "Oh ouais!" moment
Joe Plante

Réponses:


229

Disons que vous travaillez avec des couleurs RVB: chaque couleur est représentée avec trois intensités ou luminosités. Vous devez choisir entre "RVB linéaire" et "sRVB". Pour l'instant, nous allons simplifier les choses en ignorant les trois intensités différentes et en supposant que vous n'avez qu'une seule intensité: c'est-à-dire que vous n'avez affaire qu'à des nuances de gris.

Dans un espace colorimétrique linéaire, la relation entre les nombres que vous stockez et les intensités qu'ils représentent est linéaire. Pratiquement, cela signifie que si vous doublez le nombre, vous doublez l'intensité (la clarté du gris). Si vous souhaitez ajouter deux intensités ensemble (parce que vous calculez une intensité basée sur les contributions de deux sources de lumière, ou parce que vous ajoutez un objet transparent au-dessus d'un objet opaque), vous pouvez le faire en ajoutant simplement le deux nombres ensemble. Si vous faites n'importe quel type de fusion 2D ou d'ombrage 3D, ou presque n'importe quel traitement d'image, alors vous voulez que vos intensités dans un espace colorimétrique linéaire, vous pouvez donc simplement ajouter, soustraire, multiplier et diviser des nombres pour avoir le même effet sur les intensités. La plupart des algorithmes de traitement des couleurs et de rendu ne donnent des résultats corrects qu'avec RVB linéaire, sauf si vous ajoutez des poids supplémentaires à tout.

Cela semble très simple, mais il y a un problème. La sensibilité de l'œil humain à la lumière est plus fine à faible intensité qu'à haute intensité. C'est-à-dire que si vous faites une liste de toutes les intensités que vous pouvez distinguer, il y en a plus de sombres que de claires. Pour le dire autrement, vous pouvez mieux distinguer les nuances de gris sombres que les nuances de gris claires. En particulier, si vous utilisez 8 bits pour représenter votre intensité et que vous le faites dans un espace colorimétrique linéaire, vous vous retrouverez avec trop de nuances claires et pas assez de nuances sombres. Vous obtenez des bandes dans vos zones sombres, tandis que dans vos zones claires, vous gaspillez des morceaux sur différentes nuances de presque blanc que l'utilisateur ne peut pas distinguer.

Pour éviter ce problème et exploiter au mieux ces 8 bits, nous avons tendance à utiliser sRGB . La norme sRGB vous indique une courbe à utiliser pour rendre vos couleurs non linéaires. La courbe est moins profonde en bas, vous pouvez donc avoir plus de gris foncés et plus raide en haut, donc vous avez moins de gris clairs. Si vous doublez le nombre, vous doublez plus que l'intensité. Cela signifie que si vous ajoutez des couleurs sRGB ensemble, vous obtenez un résultat plus clair qu'il ne devrait l'être. De nos jours, la plupart des moniteurs interprètent leurs couleurs d'entrée comme sRGB. Ainsi, lorsque vous mettez une couleur sur l'écran ou que vous la stockez dans une texture 8 bits par canal, stockez-la en tant que sRGB , afin de tirer le meilleur parti de ces 8 bits.

Vous remarquerez que nous avons maintenant un problème: nous voulons que nos couleurs soient traitées dans un espace linéaire, mais stockées en sRVB. Cela signifie que vous finissez par effectuer une conversion sRGB en linéaire en lecture et une conversion linéaire en sRGB en écriture. Comme nous l'avons déjà dit, les intensités linéaires 8 bits n'ont pas assez de noirceur, cela poserait des problèmes, il y a donc une autre règle pratique: n'utilisez pas de couleurs linéaires 8 bits si vous pouvez l'éviter. Il devient conventionnel de suivre la règle selon laquelle les couleurs 8 bits sont toujours sRGB, donc vous effectuez votre conversion sRGB-linéaire en même temps que vous élargissez votre intensité de 8 à 16 bits, ou d'un entier à virgule flottante; de même, lorsque vous avez terminé votre traitement en virgule flottante, vous réduisez à 8 bits en même temps que la conversion en sRGB. Si vous suivez ces règles,

Lorsque vous lisez une image sRVB et que vous voulez des intensités linéaires, appliquez cette formule à chaque intensité:

float s = read_channel();
float linear;
if (s <= 0.04045) linear = s / 12.92;
else linear = pow((s + 0.055) / 1.055, 2.4);

Dans l'autre sens, lorsque vous souhaitez écrire une image en sRVB, appliquez cette formule à chaque intensité linéaire:

float linear = do_processing();
float s;
if (linear <= 0.0031308) s = linear * 12.92;
else s = 1.055 * pow(linear, 1.0/2.4) - 0.055; ( Edited: The previous version is -0.55 )

Dans les deux cas, la valeur de la virgule flottante va de 0 à 1, donc si vous lisez des entiers 8 bits, vous voulez d'abord diviser par 255, et si vous écrivez des entiers 8 bits, vous voulez multiplier par 255 enfin, de la même manière que vous le feriez habituellement. C'est tout ce que vous devez savoir pour travailler avec sRGB.

Jusqu'à présent, je n'ai traité qu'une seule intensité, mais il y a des choses plus intelligentes à faire avec les couleurs. L'œil humain peut mieux distinguer différentes luminosités que différentes teintes (plus techniquement, il a une meilleure résolution de luminance que la chrominance), vous pouvez donc utiliser encore mieux vos 24 bits en stockant la luminosité séparément de la teinte. C'est ce que les représentations YUV, YCrCb, etc. essaient de faire. Le canal Y est la clarté globale de la couleur et utilise plus de bits (ou a une résolution spatiale plus élevée) que les deux autres canaux. De cette façon, vous n'avez pas (toujours) besoin d'appliquer une courbe comme vous le faites avec les intensités RVB. YUV est un espace colorimétrique linéaire, donc si vous doublez le nombre dans le canal Y, vous doublez la clarté de la couleur, mais vous ne pouvez pas ajouter ou multiplier les couleurs YUV ensemble comme vous le pouvez avec des couleurs RVB, donc c'est

Je pense que cela répond à votre question, alors je terminerai par une brève note historique. Avant sRVB, les anciens CRT avaient une non-linéarité intégrée. Si vous doubliez la tension pour un pixel, vous doubleriez plus que l'intensité. Combien plus était différent pour chaque moniteur, et ce paramètre a été appelé le gamma . Ce comportement était utile car cela signifiait que vous pouviez obtenir plus d'ombres que de lumières, mais cela signifiait également que vous ne pouviez pas dire à quel point vos couleurs seraient lumineuses sur le CRT de l'utilisateur, à moins que vous ne l'aviez calibré au préalable. Correction gammasignifie transformer les couleurs avec lesquelles vous commencez (probablement linéaire) et les transformer pour le gamma du CRT de l'utilisateur. OpenGL vient de cette époque, c'est pourquoi son comportement sRGB est parfois un peu déroutant. Mais les fournisseurs de GPU ont maintenant tendance à travailler avec la convention que j'ai décrite ci-dessus: lorsque vous stockez une intensité 8 bits dans une texture ou un framebuffer, c'est sRGB, et lorsque vous traitez des couleurs, c'est linéaire. Par exemple, un OpenGL ES 3.0, chaque framebuffer et texture a un "indicateur sRGB" que vous pouvez activer pour activer la conversion automatique lors de la lecture et de l'écriture. Vous n'avez pas du tout besoin de faire explicitement la conversion sRGB ou la correction gamma.


6
réponse incroyable, merci, c'est toujours incroyable de voir les choses expliquées, je ne demanderais qu'un livre ou une ressource qui à votre avis sera assez bon pour ce sujet, les espaces colorimétriques, et quelles sont les formules utilisées pour faire la conversion sRGB <-> linéaire ou quelle est la fonction qui peut approcher ce comportement.
Ken

J'ai bien peur de ne pas connaître de bons livres ou ressources. La page Wikipédia est complète et comprend tout ce qui concerne le point blanc et la taille de la gamme (ce que je n'ai pas mentionné, car la plupart des gens n'ont pas besoin de le savoir), mais cela la rend un peu impénétrable .
Dan Hulme



1

Je ne suis pas un "expert en détection de couleur humaine", mais j'ai rencontré des choses similaires sur la conversion YUV-> RVB. Il existe différents poids pour les canaux R / V / B, donc si vous changez la couleur source par x, les valeurs RVB changent de quantité différente.

Comme dit, je ne suis pas un expert, de toute façon, je pense que si vous voulez faire une transformation de couleur correcte, vous devriez le faire dans l'espace YUV, puis le convertir en RVB (ou faire l'opération mathématiquement équivalente sur RVB, méfiez-vous de perte de données). De plus, je ne suis pas sûr que YUV soit la meilleure représentation native des couleurs, mais les caméras vidéo fournissent ce format, c'est là que j'ai rencontré le problème.

Voici la formule magique YUV-> RVB avec des nombres secrets inclus: http://www.fourcc.org/fccyvrgb.php


1
Faites attention aux conversions RVB <-> YUV et inversement. Je ne sais pas si c'est dans tous les cas, mais l'espace colorimétrique YUV se convertit parfois en une plage de 16 à 235 au lieu de 0 à 255 en RVB 24 bits. Ainsi, vous pouvez perdre des données à chaque fois que vous effectuez une conversion d'espace colorimétrique. La plupart des gens ont tendance à dire de rester dans le même espace colorimétrique si vous pouvez l'aider.
Joe Plante
En utilisant notre site, vous reconnaissez avoir lu et compris notre politique liée aux cookies et notre politique de confidentialité.
Licensed under cc by-sa 3.0 with attribution required.