MMI, Lyon
- I est l'intensité lumineuse (en Watt/m2 par exemple),
- x est la valeur du cannal (de 0 à 255 par exemple, ou de 0 à 1 si on normalise x en le divisant par 255)
- k est une constante qui dépend de beaucoup de choses (en particulier il n'est pas le même pour les trois canaux, et dépend du réglage brightness ou contrast du moniteur).
En général \(\gamma = 2.2\). Au départ c'est une approximation de la réponse d'un écran cathodique (CRT) à un voltage donné.* Autrement dit on envoyait au CRT un signal x proportionnel au canal, et la luminosité suivait directement la loi gamma ci-dessus pour un certain \(\gamma\).
(*) \(\gamma\) était en fait légèrement plus grand, dans les 2.5, mais on encodait comme si c'était du 2.2. On affichait donc une intensité qui était volontairement non-fidèle, il paraît que c'est dû aux conditions de visionnage des TV dans pièce sombres mais je ne comprends pas très bien les tenants physiologiques.
Les écrans sont maintenant LCD, mais on a gardé cette convention: l'intensité affichée est proportionnelle au canal mis à la puissance \(\gamma\).
Histoire de rendre les choses compliquées, on a longtemps eu plusieurs valeurs de gamma en compétition: on a vu le 2.2 et le 2.5 mais Mac utilisait du 1.8 (raison historique liée à leurs imprimantes laser couleur) et HDTV du 2.
D'abord une valeur colorimétrique précise pour les valeurs maximales de chaque canal, ainsi que leurs intensités relatives.
Ensuite une formule de conversion différente entre x et l'intensité \(I=C_\mathrm{lin} \cdot I_\mathrm{max}\) :
avec \(a=0.055\)
Cette formule est la même pour chaque canal. Malgré son exposant 2.4≠2.2 elle est une approximation de \(x^{2.2}\). Ainsi si l'on ne dispose pas ou n'a pas envie d'écrire un convertisseur de sRGB vers les intensités, on peut l'assimiler à une loi de puissance d'exposant \(\gamma=2.2\).
Il me semble avoir lu que la partie linéaire près de x=0 évite certains problèmes de traitement d'image dus à une dérivée trop faible conjuguée à une discrétisation somme toute assez grossière (256 niveaux possibles pour un canal).
Notons que chaque canal va émettre une couleur R,V ou B indépendamment on a donc une superposition linéaire des 3 canaux.
En particulier on peut préciser la valeur du gamma que les pixels sont censés représenter. Ou bien l'espace de couleur, comme le sRGB.
Petite subtilité: le gamma indiqué dans PNG est l'inverse du gamma dont je parle depuis le début. En effet on distingue le gamma de décodage, par exemple 2.2 dans \(I=k\cdot x^{2.2}\), de celui d'encodage, qui serait 1/2.2=0.4545 car pour obtenir x on a mis I à la puissance 1/2.2 puis divisé par une constante. De même si plusieurs transformations du signal ont lieu, le gamma total est le produit des gamma, en supposant qu'elles sont toutes proches d'une loi de puissance.
Pour accéder aux métadonnées d'un PNG, on a un excellent utilitaire sous Windows: tweakPNG.
Sous les OS principaux (Linux, Mac et Win) il y a la commande identify d'ImageMagick qui permet de lire les metadonnées des images de divers formats. (Leur modification est plus limitée et elle est complexe.)
J'ai écrit en 2001 un utilitaire en ligne de commande PNGan qui sait analyser les métadonnées PNG (le lien vous dirige vers le code source, il faut que vous le compiliez).
Les OS eux-même permettent de consulter directement de plus en plus de metadonnées des images avec le temps (mais toujours pas le gamma du PNG il me semble).
D'autres logiciels sont disponibles... À vous de chercher dans ce cas.
On peut le faire indépendamment sur chaque canal.
Si on ne le fait pas on se retrouve avec des valeurs inappropriées. Le cas extrême, un pixel mi-blanc mi-noir, correspond en gamma=2.2 à [R,G,B]=[186,186,186] et non pas [128,128,128] ou [127,127,127] qui serait du gamma=1.
Une telle erreur n'est peut-être pas trop gênante pour des images où les changements brusques de couleurs ne sont pas trop proches mais quand on en arrive à des zones contrastées alternant rapidement (zones de 2 pixels ou moins) cela devient plus sensible. Surtout s'il on décide dans le code de remplacer ces zones par leur couleur moyenne ! pour comprendre le sens de cette dernière phrase, voir les exemples un petit peu plus bas.
Mais d'abord une première série d'exemples.
Rééch correct, γ=1 | Rééch commme du γ=1, affiché comme du γ=2.2 |
Rééch comme du γ=2.2, affichée comme du γ=1 |
Rééch correct, γ=2.2 |
Maintenant comparons des damiers et des plages censées être de la même couleur. On a choisi des damiers dont les cases font 1 pixel de large. On aurait pu prendre des lignes alternantes au lieu de damiers. En bleu, la valeur des canaux R,G,B du carré uniforme.
À nouveau cela devrait être correct en haut à gauche et en bas à droite.
Maintenant si vous avez un écran de portable en 2016, vous noterez certainement que les rendus des intensités et des couleurs varient fortement selon l'angle de vision: même en ne bougeant pas la tête ni l'ordi, je vois une différence entre le haut et le bas sur l'image ci-contre...
Ci-dessous, on est parti d'une image a grande résolution contenant du blanc [255,255,255], et du bleu variant de bleu clair=[128,128,255] à bleu=[0,0,255]. La transition entre les deux se fait le long de courbes (préimage itérée de Re(z)=seuil par f comme on l'a vu). C'est prévu pour du gamma=1 car juste avant la transition on a moitié de blanc et moitié de bleu, juste après bleu clair.
Réduction linéaire, gamma=1, image correcte.
Ici on a pris un logiciel qui considère l'image comme du gamma=2.2 et a réduit en conséquence. Elle est affichée comme du 2.2. L'interpolation est correcte mais la zone unie ne l'est plus. On voit nettement la transition.
Je vous laisse méditer là-dessus.
Quelqu'un a créé un petit gadget marrant sur le principe :
C'est une image en gamma=2.2. Si vous la réduisez avec Firefox, celui-ci échoue et vous lisez "sucks". Si vous la réduisez par exemple avec Preview sous Mac, vous aurez un "rules".Curieusement, Preview ignore le gamma déclaré dans les métadonnées du PNG et décrète du 2.2. Coup de bol l'image ci-dessus est en 2.2. Maintenant Preview effectue correctement un downscale en gamma 2.2, càd évite de le faire linéairement sur le canal RGB mais le convertit en intensité avant de rescaler.
Résumé de mes expériences (très partielles) en 2016:
- Firefox et Chrome: tient compte du gamma des PNG pour l'affichage, mais rescale ensuite comme si c'était du gamma=1.
- Preview sous Mac: ignore le gamma des PNG et les interprète en 2.2 (ou en sRGB?), par contre il fait un rescale correct pour les images en 2.2.
- Gimp et Safari ignorent le gamma du PNG. L'image est affichée avec gamma=2.2 mais le rescale est fait en linéaire sur les canaux c.à.d. comme pour du gamma=1.
J'ajoute qu'imageMagick permet de faire du resize correct à condition que vous lui demandiez explicitement de convertir vers et depuis le linear colorspace.
Conclusion: toujours une très mauvaise prise en charge du gamma ou sRGB (qui est pourtant le standard depuis longtemps). Aujourd'hui un downscale correct est faisable mais compliqué. Espérons que ça s'améliorera dans l'avenir. Espérons aussi que les navigateurs vont corriger leur downscale.