Provate a creare una sfumatura dal rosso puro al verde puro con un semplice calcolo di media tra i valori RGB. Al centro comparirà una banda marrone scuro, che nella realtà non esisterebbe mescolando due luci. Oppure ridimensionate una foto con sottili linee bianche su fondo nero: dopo la riduzione appare più scura dell'originale. Entrambi i problemi hanno la stessa causa, la gamma, ed è uno degli argomenti più fraintesi della grafica digitale.
La percezione non è lineare
L'occhio umano non percepisce la luminosità in proporzione alla quantità di luce. Siamo molto più sensibili alle differenze nelle zone scure che in quelle chiare: passare da una a due candele in una stanza buia è un cambiamento enorme, passare da cento a centouno è impercettibile.
Se si codificasse la luce in modo lineare con 8 bit, cioè con 256 livelli equidistanti in termini di energia, si sprecherebbero moltissimi livelli nelle alte luci, dove l'occhio non distingue le differenze, e se ne avrebbero troppo pochi nelle ombre, dove comparirebbero gradini visibili.
La soluzione: codifica con una curva
Per usare meglio i bit disponibili, i valori vengono memorizzati dopo aver applicato una curva che "espande" le ombre e "comprime" le luci. In modo semplificato:
valore_codificato = luce_lineare ^ (1 / 2,2)
luce_lineare = valore_codificato ^ 2,2
Lo standard sRGB usa in realtà una funzione a tratti, con un piccolo segmento lineare vicino al nero e una potenza di 2,4 per il resto, ma nel complesso si comporta in modo simile a una gamma di 2,2. Con valori normalizzati tra 0 e 1, il valore codificato 0,5 corrisponde a circa il 21% della luce del bianco.
| Valore sRGB (8 bit) | Luce lineare approssimativa |
|---|---|
| 0 | 0% |
| 64 | circa 5% |
| 128 | circa 22% |
| 188 | circa 50% |
| 255 | 100% |
Il grigio che appare "a metà" tra nero e bianco emette dunque circa un quinto della luce. E per ottenere metà della luce del bianco serve un valore intorno a 188.
Dove la gamma crea problemi
La codifica gamma è ottima per memorizzare e trasmettere immagini. Diventa un problema quando si eseguono calcoli fisici sui valori codificati come se fossero luce. I casi tipici sono:
- Sfumature: interpolare tra due colori sui valori sRGB produce zone centrali troppo scure e a volte desaturate.
- Fusione di livelli e trasparenze: un livello bianco al 50% su nero dovrebbe produrre un grigio che emette metà della luce, ma il calcolo diretto dà il valore 128, che ne emette un quinto.
- Ridimensionamento: fare la media di pixel chiari e scuri in spazio gamma scurisce i dettagli fini; testi chiari su fondo scuro e foto di stelle sono gli esempi più evidenti.
- Sfocatura: le luci puntiformi sfocate in spazio gamma diventano macchie spente invece di dischi luminosi, come accadrebbe in un vero obiettivo.
- Illuminazione 3D: sommare luci su valori gamma produce scene con contrasto innaturale.
Lavorare in spazio lineare
La procedura corretta per questi calcoli è sempre la stessa:
- Decodificare: convertire i valori sRGB in luce lineare, applicando la funzione inversa.
- Calcolare: eseguire media, fusione, sfocatura o illuminazione sui valori lineari.
- Ricodificare: riapplicare la curva sRGB prima di salvare o mostrare.
Lavorando in lineare servono più bit: con soli 8 bit per canale le ombre si riempirebbero di gradini. Per questo i programmi che operano in spazio lineare usano internamente 16 bit interi o numeri in virgola mobile.
Nella pratica:
- i software 3D e i motori di gioco moderni calcolano l'illuminazione in lineare e convertono solo all'uscita;
- molti programmi di fotoritocco offrono un'opzione per la fusione dei colori con gamma 1,0 o per lavorare in uno spazio lineare;
- le schede video supportano formati di texture "sRGB" che vengono decodificati automaticamente alla lettura e codificati alla scrittura, a costo zero.
Un esempio concreto
Nel mio lavoro ho visto spesso miniature generate da script automatici in cui i caratteri bianchi su fondo scuro diventavano grigi e quasi illeggibili. Il codice faceva la media dei pixel direttamente sui valori sRGB. Convertire in lineare prima del ridimensionamento e tornare in sRGB dopo ha risolto il problema senza altri cambiamenti. È un intervento di poche righe, ma va ricordato che ogni libreria ha il proprio comportamento predefinito: alcune lavorano già in lineare, altre no.
Gamma del monitor e gamma del file
Una precisazione per evitare confusione: si parla di "gamma" anche per la risposta del monitor. Per decenni gli schermi a tubo catodico avevano naturalmente una risposta simile a una potenza di circa 2,2–2,5, e la codifica dei segnali si è adattata a quella caratteristica. Gli schermi moderni non hanno questo comportamento fisico, ma lo emulano per restare compatibili. Il risultato è che, se tutto è configurato correttamente, la codifica del file e la risposta dello schermo si compensano e l'immagine appare come previsto.
In sintesi
- L'occhio è più sensibile alle differenze nelle ombre: per questo i valori sono codificati con una curva gamma.
- In sRGB il valore 128 corrisponde a circa un quinto della luce del bianco, non alla metà.
- Sfumature, fusioni, ridimensionamenti, sfocature e illuminazione vanno calcolati in luce lineare.
- Il metodo è sempre decodificare, calcolare, ricodificare, con più di 8 bit durante il calcolo.
- La gamma del file e quella dello schermo, se configurate bene, si compensano.