4.17. Comandi del sensore

Oltre a pixformat() e framesize(), la classe CSI espone una manciata di controlli specifici per sensore a cui quasi ogni applicazione ricorre prima o poi: orientamento di montaggio, esposizione, guadagno, bilanciamento del bianco e qualche ausilio per il debugging. Ognuno corrisponde direttamente a un concetto del sensore trattato in precedenza; l’API fornisce semplicemente un riferimento Python per la scrittura nel registro che il driver effettua internamente.

Tutti i metodi seguenti agiscono sul sensore sottostante. Tutti inviano scritture nei registri attraverso il bus di controllo I2C del sensore, quindi il costo è dell’ordine dei microsecondi e la nuova impostazione ha effetto sulla prossima esposizione, tipicamente la prossima snapshot().

4.17.1. Orientamento

La camera non sa in che verso è stata montata. Due flag di ribaltamento applicati al sensore raddrizzano l’immagine prima che qualsiasi pixel lasci il chip:

csi0.hmirror(True)
csi0.vflip(True)

hmirror() ribalta da sinistra a destra e vflip() ribalta dall’alto verso il basso. Insieme coprono i casi che si presentano nella pratica: una scheda montata capovolta (entrambi i flag True), una scheda dietro uno specchio a superficie anteriore (solo hmirror) o una che guarda una scena riflessa dal basso (solo vflip).

Poiché il ribaltamento avviene nella logica di lettura del sensore, non c’è alcun costo per la CPU né overhead di memoria: il frame arriva nel framebuffer già orientato.

4.17.2. Esposizione

L’esposizione è il tempo di integrazione, ovvero per quanto tempo il fotodiodo di ogni pixel accumula carica prima che la riga venga letta, espresso in microsecondi. Il driver parte con il ciclo di esposizione automatica del sensore attivo, quindi la camera cerca di mantenere il valore medio dei pixel vicino a un valore obiettivo. Disabilitando il ciclo si fissa l’esposizione a un valore scelto dall’applicazione:

csi0.auto_exposure(False, exposure_us=8000)

Un’esposizione fissa è la scelta giusta quando la luminosità della scena è stabile e l’applicazione ha bisogno di una sfocatura da movimento prevedibile o di un’intensità coerente da frame a frame per la sogliatura. Rileggere l’esposizione corrente, sia che l’abbia impostata il ciclo o l’applicazione, è una chiamata separata:

us = csi0.exposure_us()

Chiamare auto_exposure() con True e senza un valore di esposizione restituisce il controllo al ciclo.

4.17.3. Guadagno

Il guadagno è l’amplificatore applicato alla tensione del pixel prima che raggiunga l’ADC, espresso in decibel. Come per l’esposizione, il driver parte con il ciclo di guadagno automatico attivo. Si presentano spesso due schemi. Limitare il valore massimo consente al ciclo di adattarsi all’illuminazione ma gli impedisce di amplificare indefinitamente il rumore nelle scene poco illuminate:

csi0.auto_gain(True, gain_db_ceiling=16)

Fissare un guadagno costante è la mossa giusta quando l’applicazione fissa anche l’esposizione: la stabilità del guadagno è importante per le applicazioni che confrontano i valori dei pixel da frame a frame, come il tracciamento del colore:

csi0.auto_gain(False, gain_db=0)

Il guadagno corrente si rilegge tramite gain_db(). Ogni volta che l’applicazione disabilita il guadagno automatico dovrebbe disabilitare anche il bilanciamento del bianco automatico e l’esposizione automatica, altrimenti i cicli di controllo ancora attivi sposteranno l’immagine in modi che vanificano il guadagno fisso.

4.17.4. Bilanciamento del bianco

Il bilanciamento del bianco è il guadagno per canale che l’ISP applica ai canali rosso, verde e blu in uscita dallo stadio di debayering affinché un oggetto bianco appaia bianco sotto qualsiasi colore di luce. Il ciclo di bilanciamento del bianco automatico calcola questi tre guadagni a partire dalle statistiche per regione che l’ISP raccoglie a ogni frame e li applica al frame successivo.

La maggior parte delle applicazioni lascia il ciclo attivo. Il tracciamento del colore è l’eccezione comune: i guadagni sono anche ciò che il ciclo modificherà per inseguire un oggetto colorato, quindi se l’applicazione sta cercando di trovare un blob rosso, il ciclo attenuerà silenziosamente il canale rosso e il blob smetterà di corrispondere. Bloccare il ciclo risolve il problema:

csi0.auto_whitebal(False)

Passa una tupla esplicita (r, g, b) in decibel per una calibrazione del colore ripetibile, con gli stessi guadagni tra schede e sessioni diverse:

csi0.auto_whitebal(False, rgb_gain_db=(0.0, 0.0, 0.0))

I guadagni correnti si rileggono come tupla tramite rgb_gain_db().

4.17.5. Limite del frame rate

Per impostazione predefinita i sensori funzionano al loro frame rate nativo: da 30 a 60 frame al secondo sulla maggior parte dei componenti, molto più alto sui sensori ad alta velocità quando il framesize è sufficientemente piccolo. Limitare la frequenza consente all’applicazione di rallentare la camera fino a ciò che l’elaborazione a valle riesce a sostenere:

csi0.framerate(15)

Sui sensori che supportano un controllo hardware della frequenza la chiamata allunga anche il budget di esposizione per frame, il che può aiutare in condizioni di scarsa illuminazione; sugli altri il driver salta semplicemente i frame in eccesso a livello di framebuffer.

4.17.6. Pattern di test

Il pattern di test a barre di colore è integrato nella maggior parte dei sensori ed è utile per separare un problema di imaging da un problema di output. Attivandolo si bypassa l’array di fotodiodi e si invia un pattern fisso lungo lo stesso percorso dei dati dei pixel:

csi0.colorbar(True)

Se il pattern di test appare corretto ma l’immagine dal vivo no, il guasto è nell’ottica o nel front-end analogico del sensore; se anche il pattern di test è corrotto, il problema è da qualche parte sul bus dei dati dei pixel o nella configurazione di pixformat() / framesize(). Passa False per tornare all’immagine dal vivo.

Vedi csi.CSI per l’API completa, inclusi i comandi ioctl() specifici per sensore che espongono controlli unici di particolari famiglie di sensori.