5.18. Istogrammi e statistiche¶
Oltre alle operazioni che modificano i pixel di un’immagine, la classe Image mette a disposizione una famiglia di metodi che li misurano: riassumono la distribuzione dei valori dei pixel, restituiscono la luminosità media e mediana, individuano il punto di taglio ottimale tra pixel scuri e chiari, riportano la dispersione dei canali di colore. Le misurazioni alimentano le applicazioni in due modi: come input per il codice che decide quale soglia usare, quale guadagno impostare, che aspetto ha il profilo tonale della scena; e come segnali diagnostici – «la scena è abbastanza luminosa?» – su cui un’applicazione può agire senza prendere decisioni su alcun pixel specifico.
Il punto di partenza di quasi ogni misurazione è l”istogramma.
5.18.1. L’istogramma¶
Un istogramma di un’immagine è un conteggio di quanti pixel hanno ciascun possibile valore di luminosità. Per un’immagine in scala di grigi, si tratta di un elenco di conteggi indicizzati dai valori da 0 a 255. Per un’immagine a colori, sono tre elenchi di questo tipo, uno per canale.
get_histogram() ne calcola uno:
h = img.get_histogram()
L’oggetto restituito è un risultato histogram che espone gli elenchi di bin per canale e alcune query di alto livello su di essi. I conteggi dei bin sono normalizzati in modo che la loro somma sia 1.0: l’istogramma descrive il profilo della distribuzione anziché il conteggio assoluto dei pixel, il che rende le misurazioni confrontabili tra immagini di dimensioni diverse.
Per le immagini in scala di grigi l’istogramma ha un solo canale di bin, disponibile come h.bins() (o, equivalentemente, h[0]). Per le immagini RGB565 l’istogramma viene calcolato nello spazio colore LAB introdotto nella pagina sul thresholding binario, con tre canali di bin disponibili come h.l_bins(), h.a_bins(), h.b_bins() (oppure h[0], h[1], h[2]). LAB è la stessa scelta usata dai metodi di soglia e di tracciamento; gli istogrammi concordano con le soglie sullo spazio in cui viene misurato il colore.
5.18.2. I bin e il loro numero¶
L’istogramma predefinito ha un bin per ogni possibile valore di pixel: 256 bin per un canale a 8 bit. A volte questa risoluzione è più fine di quanto l’applicazione richieda. Un classificatore che si interessa solo al profilo approssimativo della distribuzione potrebbe essere meglio servito da un numero di bin inferiore – 32 o anche 8 bin – che è al tempo stesso più veloce ed offre un risultato più pulito a fronte del rumore. La parola chiave bins (e le rispettive l_bins, a_bins, b_bins per canale nel caso del colore) imposta il numero:
h = img.get_histogram(bins=32)
La delimitazione tramite ROI e soglia funziona allo stesso modo di ogni altro metodo di misurazione. Passa un roi per limitare l’istogramma a un rettangolo di pixel; passa un elenco di thresholds per includere solo i pixel che corrispondono a quegli intervalli. La forma con soglia è ciò che rende «calcola l’istogramma dei soli pixel corrispondenti» un’operazione in una sola chiamata: un pattern comune quando un’applicazione vuole caratterizzare la texture di una regione già rilevata senza dover percorrere i pixel da sé.
Un istogramma in scala di grigi con tre misurazioni riassuntive sovrapposte: la soglia di Otsu (il punto di taglio che separa meglio i cluster scuri e chiari), la media e la mediana. Ciascuna misurazione dice qualcosa di diverso sulla stessa distribuzione.¶
5.18.3. Statistiche¶
Un istogramma è una descrizione della prevalenza di ogni valore; le statistiche sono i riassunti numerici da esso derivati. L’oggetto statistics restituito da get_statistics() riporta l’insieme standard:
mean– la media aritmetica dei valori dei pixel.median– il valore al di sotto del quale si trova metà dei pixel.mode– il singolo valore più comune.stdev– la deviazione standard, una misura della dispersione attorno alla media.minemax– i valori di pixel più scuri e più chiari presenti.lqeuq– i punti di taglio del quartile inferiore e superiore.
Per un’immagine RGB565 le forme per canale (l_mean, a_median, b_mode e così via) forniscono le stesse misurazioni canale per canale.
La maggior parte di questi numeri ricorre in contesti specifici. mean e stdev insieme forniscono una stima del rumore: una scena che dovrebbe essere uniforme ha una stdev piccola, mentre un sensore rumoroso conferisce alla stessa scena una stdev maggiore. min e max forniscono il contrasto dell’immagine: più sono vicini, più piatta è la scena; più sono distanti, più gamma dinamica ha a disposizione l’algoritmo. median è il centro robusto quando la distribuzione presenta valori anomali (pochi pixel molto luminosi non spostano la mediana come spostano la media). mode è il singolo valore più comune, utile per individuare il livello di sfondo di un’immagine il cui sfondo copre la maggior parte dei pixel.
get_statistics() esegue internamente la passata sull’istogramma e poi lo riassume; passando gli stessi argomenti thresholds e roi di un istogramma calcolato in precedenza si ottengono le statistiche per lo stesso insieme di pixel.
5.18.4. Percentili e ricerche sulla CDF¶
L’oggetto histogram espone un metodo get_percentile() che trasforma una frazione in un valore di pixel: il valore al di sotto del quale si trova la frazione richiesta di pixel. h.get_percentile(0.5) è la mediana; h.get_percentile(0.05) e h.get_percentile(0.95) insieme forniscono un min/max robusto che ignora il 5% inferiore e superiore come valori anomali.
Questa è la forma usata da un’applicazione quando vuole caratterizzare l”intervallo dei valori dei pixel senza lasciare che una manciata di pixel scuri o chiari isolati alteri il risultato. Il min/max robusto del 5° e 95° percentile è anche l’input naturale per una passata di estensione del contrasto – il rimappaggio per pixel trattato in Correzioni tonali.
5.18.5. Il metodo di Otsu¶
Gli istogrammi rispondono a un’altra domanda che vale la pena evidenziare a parte: data un’immagine i cui pixel si dividono in un cluster «scuro» e uno «chiaro», qual è il punto di taglio tra di essi? La pagina sul thresholding ha già nominato il meccanismo dal suo risultato – una singola soglia globale che l’applicazione può passare a binary() – ma ha rimandato il come. Il come è il metodo di Otsu, e risiede nell’istogramma.
L’intuizione: un’immagine con un primo piano e uno sfondo netti ha due cluster nel suo istogramma di luminosità, con una valle tra di essi. Il punto giusto in cui applicare la soglia è il fondo della valle, il valore in cui i due cluster sono separati al meglio. Il metodo di Otsu esamina ogni possibile punto di taglio e sceglie quello in cui le varianze interne ai cluster sono minime (il che equivale a dire che la varianza tra i cluster è massima), e il risultato è la separazione binaria ottimale per la distribuzione di quella particolare immagine.
L’oggetto histogram espone Otsu tramite get_threshold:
h = img.get_histogram()
t = h.get_threshold()
L’oggetto threshold restituito ha gli attributi value (per la scala di grigi) oppure l_value / a_value / b_value (per il colore) che contengono il punto di taglio scelto. Reintrodurre il risultato direttamente in binary() fornisce una soglia globale autoregolante il cui punto di taglio è scelto dall’immagine stessa:
img.binary([(t.value, 255)])
Quel pattern non risolve il problema dell’illuminazione non uniforme che risolve la soglia adattiva basata su filtri; ciò che risolve è la domanda «quale valore dovrei usare per il taglio?» quando il thresholding globale è già l’approccio corretto. Per una scena la cui distinzione tra primo piano e sfondo è ben definita, il valore scelto da Otsu è di solito entro poche unità da quello che un essere umano sceglierebbe a occhio.
5.18.6. Calcolo su un’immagine di differenza¶
Un dettaglio utile su get_histogram() e get_statistics(): entrambi accettano una parola chiave difference che prende un’altra Image e calcola l’istogramma (o le statistiche) della differenza per pixel tra l’immagine sorgente e quell’immagine, senza allocare un’immagine di differenza separata. È il modo economico per chiedere «quanto è cambiata la scena rispetto al frame di riferimento?» senza pagare per una chiamata esplicita a difference() che produrrebbe un’immagine il cui unico scopo è essere misurata. Per uno script di rilevamento del movimento in esecuzione continua, il risparmio si accumula.