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.