Mini-cours au groupe de travail "Images"
MMI, Lyon
Arnaud Chéritat

Retour


18 mars 2016
1e partie
Nous avons abordé la notion de correction gamma, puis regardé à nouveau la méthode du downsampling et les problèmes qu'elle implique quand on tient compte du gamma, rendus ardus par un support aléatoire de la part des navigateurs, OS et logiciels de retouche d'image.


Correction Gamma
On l'a vu, les couleurs sont codées par des canaux R, G et B, pouvant prendre des valeurs de 0 à 255 (classiquement). Cependant l'intensité lumineuse des pixels (R,V ou B) l'écran et la valeur R,G ou B du canal correspondant ne sont en général pas reliés de façon linéaire. On considère pour simplifier que

\(I = k\cdot x^\gamma\)

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.


sRGB
Le standard sRGB définit plusieurs choses.

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}\) :

\(C_\mathrm{lin}= \begin{cases}\frac{x}{12.92}, & \text{si }x\le0.04045\\ \left(\frac{x+a}{1+a}\right)^{2.4}, & \text{si }x>0.04045 \end{cases}\)
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.


Métadonnées
Les images PNG et JPEG incluent des données annexes, appelées metadonnées, en plus de celles de base que sont le nombre de pixels et leurs valeurs RGB.

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.


Conséquences pour le downsampling
Faire un ré-échantillonnage correctement nécessite de travailler avec des valeurs proportionnelles aux intensités à la place des valeurs RGB, sauf dans les rares cas où l'image est encodée en linéaire (\(\gamma=1\)).

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
Les images en haut à gauche et en bas à droite devraient apparaître identiques et correctes. L'image en bas à droite est trop claire et celle en haut à gauche trop sombre. Le défaut est plus flagrand sur l'image trop claire. Tout ceci en supposant que votre ordinateur et votre navigateur et votre écran font bien leur boulot, ce qui n'est pas garanti (voir plus bas).

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.


Prise en charge du gamma
Maintenant, une petite expérience: reprenez l'image des damiers et dézoomez avec votre navigateur. Si vous êtes en 2016 avec Firefox vous verrez un gros problème. En zoom factor=1 vous aviez une prise en charge correcte du gamma. En dézoom, vous avez un décodage correct du gamma suivi d'un ré-échantillonnage incorrect: ils font comme si c'était du gamma=1. On se retrouve ainsi avec un drôle de résultat, illustré ci-dessous.

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:

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.


Suite de la séance