Elaborazione delle immagini: convoluzione, Bayer, istogramma
Le basi dietro il tool Image Processing Lab: convoluzione 2D e kernel, il pattern Bayer dei sensori CMOS e il demosaicing, istogramma, luminanza ed esposizione.
Codice su GitHub ↗Cosa copre questa wiki
Le tre tecniche dietro lo strumento Image Processing Lab: la convoluzione con kernel, il demosaicing di un sensore Bayer e la lettura di istogramma ed esposizione. Sono i mattoni elementari di qualsiasi pipeline di immagine, dal software desktop alla camera embedded.
La convoluzione 2D
La convoluzione è l’operazione di base dei filtri spaziali. Una piccola matrice di pesi — il kernel — scorre su ogni pixel; il valore di uscita è la somma pesata del pixel e dei suoi vicini. Ma qui va fatta una distinzione che quasi tutta la letteratura applicativa salta, e che questo strumento ha il dovere di dichiarare, perché sui kernel antisimmetrici cambia il risultato. Con un kernel K di lato dispari (a = (lato − 1)/2) e un’immagine I esistono due operazioni:
Differiscono per il segno degli indici: la convoluzione ribalta il kernel, la correlazione no. Questo strumento — come la maggior parte delle librerie di image processing, OpenCV compresa nella sua filter2D — implementa la correlazione, e la chiama convoluzione per abitudine consolidata.
Sui kernel simmetrici (blur, gaussiana, Laplaciano 3×3) le due coincidono esattamente e la distinzione è accademica. Sui kernel antisimmetrici no. Su una rampa orizzontale, il Sobel X dà:
kernel Sobel X [[-1, 0, 1], [-2, 0, 2], [-1, 0, 1]]
correlazione (qui) 168 208 208 208 208 208 208 168
convoluzione vera 88 48 48 48 48 48 48 88
I due risultati sono speculari rispetto all’offset 128: 208 − 128 = +80, 128 − 48 = +80. Il modulo del gradiente è identico, il segno è invertito — cioè un bordo che sale viene letto come un bordo che scende. Per la magnitudo (√(Gx² + Gy²)) non cambia nulla; per la direzione del gradiente, per il flusso ottico, per qualunque uso in cui il segno conta, cambia tutto. Se serve la convoluzione vera basta ruotare il kernel di 180°.
I tre canali R, G, B si filtrano separatamente. Due dettagli pratici cambiano il risultato:
- Bordi. Dove il kernel sborda fuori dall’immagine, le coordinate vengono clampate (si estende il pixel di bordo). Esistono anche modalità a specchio o periodiche.
- Normalizzazione. Dividere per la somma dei coefficienti mantiene costante la luminanza media: indispensabile per i blur. I kernel a somma zero (bordi, gradienti) non si normalizzano; per renderli visibili si somma un offset (tipicamente 128), che porta lo zero al grigio medio.
Kernel notevoli
| Kernel | Somma | Effetto |
|---|---|---|
| Identità | 1 | nessun effetto (centro 1) |
| Box / Gaussian blur | >0 | media il vicinato → riduce rumore e dettaglio |
| Sharpen | 1 | centro alto, bordi negativi → esalta il contrasto locale |
| Laplaciano | 0 | derivata seconda → contorni in ogni direzione |
| Sobel X / Y | 0 | gradiente direzionale → bordi verticali / orizzontali |
| Emboss | 1 | rilievo illuminato di lato |
I due operatori di Sobel stimano le derivate orizzontale e verticale; combinati danno il modulo del gradiente, che è il cuore del rilevamento dei contorni:
Tre kernel 3×3 scritti per esteso
sharpen Sobel X box blur (×1/9)
0 -1 0 -1 0 1 1 1 1
-1 5 -1 -2 0 2 1 1 1
0 -1 0 -1 0 1 1 1 1
Lo sharpen ha somma 1 (conserva la luminanza) ma centro alto e bordi negativi: amplifica la differenza fra un pixel e i suoi vicini. Il Sobel X ha somma 0 e risponde solo dove l’intensità cambia in orizzontale (il Sobel Y è la sua trasposta). Il box blur, normalizzato a 1/9, è la media pura del vicinato.
Il sensore Bayer e il demosaicing
Un sensore CMOS a colori non misura RGB in ogni pixel. Davanti ai fotositi c’è una matrice di filtri colore (CFA, Color Filter Array) disposta secondo il pattern Bayer: una griglia 2×2 ripetuta con due verdi, un rosso e un blu. I verdi sono il doppio perché l’occhio umano è più sensibile al verde, che porta gran parte dell’informazione di luminanza. RGGB, BGGR, GRBG e GBRG sono le quattro fasi dello stesso schema.
Poiché ogni pixel registra un solo canale, gli altri due vanno ricostruiti: è il demosaicing.
- Nearest neighbor — copia il campione dello stesso colore più vicino. Velocissimo, ma con scalettature e blocchi 2×2 visibili.
- Bilineare — media i vicini dello stesso colore. Più morbido, ma sui bordi netti può generare due artefatti tipici: lo zipper (zig-zag lungo i contorni) e il color fringing (frange colorate).
Gli algoritmi che usano davvero le fotocamere sono più sofisticati: invece di mediare alla cieca, riconoscono la direzione dei contorni e interpolano lungo i bordi anziché attraverso, riducendo gli artefatti.
Quanta risoluzione costa il mosaico
Il conto è semplice e spiega gli artefatti del demosaicing meglio di qualunque descrizione qualitativa. Su un blocco 2×2 RGGB ogni canale è campionato a una frazione diversa:
| Canale | Campioni su un blocco 2×2 | Passo effettivo | Nyquist (cicli/pixel) |
|---|---|---|---|
| R e B | 1 / 4 = 25 % | 2,00 px | 0,250 |
| G | 2 / 4 = 50 % | 1,41 px | 0,354 |
| sensore monocromatico | 4 / 4 = 100 % | 1,00 px | 0,500 |
Il verde è campionato al doppio degli altri (è il canale su cui si appoggia la luminanza percepita) ma su un reticolo diagonale, quindi il suo passo effettivo è √2 pixel e la Nyquist è 0,354 cicli/pixel invece di 0,5. Rosso e blu stanno a 0,25, metà di un sensore monocromatico.
Da qui vengono gli artefatti tipici: un dettaglio fine e colorato oltre 0,25 cicli/pixel è sotto-campionato in R e B, e il demosaicing può solo interpolare — producendo zipper sui bordi e false colours sulle tessiture regolari. È anche il motivo per cui davanti a un sensore Bayer si mette un filtro anti-aliasing ottico: rinunciare a un po’ di nitidezza costa meno che avere moiré colorato. Un sensore monocromatico, non avendo mosaico, non ha né il problema né il filtro — ed è la ragione per cui in molte applicazioni di visione industriale si sceglie il bianco e nero.
Istogramma, luma ed esposizione
L’istogramma conta quanti pixel cadono in ciascun livello (0–255), separatamente per i tre canali e per una quarta grandezza che merita di essere chiamata col suo nome: la luma. Non è la luminanza, e la differenza non è terminologica.
La luma Y′ si calcola sui valori RGB così come stanno nel file, cioè gamma-encoded: è una scorciatoia nata nella televisione analogica, dove fare la somma pesata prima della correzione di gamma costava un circuito in meno. La luminanza Y è una grandezza fotometrica: richiede di linearizzare prima i tre canali (per sRGB, l’EOTF con l’esponente 2,4 e il tratto lineare vicino a zero) e usa i pesi del primario Rec.709.
Quanto sono diverse? Su un grigio, per niente. Su un colore saturo, molto:
| Colore | Luma Y′ (601) | Luminanza Y relativa | Y′ del grigio di pari luminanza | Scarto |
|---|---|---|---|---|
| rosso puro | 76,2 | 21,3 % | 127,1 | +50,9 |
| verde puro | 149,7 | 71,5 % | 219,9 | +70,2 |
| blu puro | 29,1 | 7,2 % | 76,0 | +46,9 |
| giallo | 225,9 | 92,8 % | 246,7 | +20,8 |
| ciano | 178,8 | 78,7 % | 229,5 | +50,7 |
| magenta | 105,3 | 28,5 % | 145,4 | +40,1 |
| grigio 128 | 128,0 | 21,6 % | 128,0 | 0 |
| bianco | 255,0 | 100,0 % | 255,0 | 0 |
La colonna «scarto» è la lettura più diretta: un rosso puro ha luma 76 ma la stessa luminanza di un grigio 127. Cinquantuno livelli su 255 di differenza, cioè il rosso saturo appare nell’istogramma della luma a un quinto della scala mentre in luminanza sta a metà. Sul verde puro lo scarto arriva a 70 livelli. Solo la diagonale dei grigi è esatta.
Nella stessa tabella si legge un’altra cosa che sorprende: il grigio 128, il «mezzo» della scala digitale, vale il 21,6 % della luminanza del bianco, non il 50 %. È la gamma, e è il motivo per cui «schiarire del 50 %» ha significati diversi a seconda dello spazio in cui si lavora.
C’è poi una terza ambiguità, indipendente dalla gamma: i pesi. Rec.601 (0,299 / 0,587 / 0,114) sono quelli della televisione a definizione standard; Rec.709, usato per l’HD, pesa diversamente (0,2126 / 0,7152 / 0,0722). Applicati agli stessi pixel gamma-encoded:
| Colore | Y′ con pesi 601 | Y′ con pesi 709 | Differenza |
|---|---|---|---|
| rosso puro | 76,2 | 54,2 | −22,0 |
| verde puro | 149,7 | 182,4 | +32,7 |
| blu puro | 29,1 | 18,4 | −10,7 |
| giallo | 225,9 | 236,6 | +10,7 |
| ciano | 178,8 | 200,8 | +22,0 |
| magenta | 105,3 | 72,6 | −32,7 |
| grigio 128 | 128,0 | 128,0 | 0 |
| bianco | 255,0 | 255,0 | 0 |
Fino a 33 livelli di differenza sul verde e sul magenta — e nessuna delle due è «sbagliata», sono due convenzioni per due sistemi diversi. Questo strumento usa Rec.601 su valori gamma-encoded, cioè luma Y′ in senso stretto: perfettamente adatto al suo scopo (valutare esposizione e clipping in fase di acquisizione), da non confondere con una misura fotometrica.
La forma dell’istogramma racconta l’immagine: addensamento a sinistra → scena scura; a destra → scena chiara; distribuzione ampia → buon contrasto. Quando i conteggi si schiacciano contro 0 o 255 c’è clipping: il dettaglio nelle ombre o nelle alte luci è perso e non si recupera in post. È il controllo che si fa in fase di acquisizione per impostare correttamente esposizione e guadagno del sensore — prima di elaborare l’immagine.
Dal sensore al codice
Queste non sono nozioni astratte: sono le operazioni quotidiane della messa a punto di una camera embedded. Nel bring-up di un sensore CMOS si legge l’istogramma per tarare l’esposizione, si valuta la qualità del demosaicing e si applica un filtro di nitidezza o di riduzione del rumore. Lo strumento da cui nasce questo tool, arducam-evk-gui, serve proprio a portare in vita un sensore a livello di registri e a ispezionarne l’immagine.
Limiti
Il tool è dimostrativo: gli algoritmi sono didattici, non quelli di un ISP reale; l’immagine viene ridimensionata per restare reattiva; il mosaico Bayer è simulato a partire da un’immagine RGB già compressa, non un RAW di sensore; la convoluzione lavora a precisione intera 8-bit con clamp.
Riferimenti
- B. E. Bayer, brevetto del Color Filter Array (1976) — l’origine del pattern Bayer.
- I. Sobel, operatore di gradiente per il rilevamento dei bordi.
- ITU-R BT.601 / BT.709 — coefficienti di luminanza.
- Provalo: Image Processing Lab.
Un progetto simile?
Acustica, embedded, strumenti di calcolo: se hai un caso d’uso vicino, parliamone.