5.6. Disegnare forme e testo¶
Un algoritmo che decide qualcosa riguardo a un’immagine ha spesso bisogno che tale decisione sia visibile. Un rilevatore di blob trova una regione a cui l’applicazione è interessata; l’applicazione vuole che la regione venga disegnata sul frame, così che un operatore - o lo sviluppatore che esegue lo script - possa vedere cosa è stato trovato. Una trasformazione di coordinate mappa una posizione di ingresso su una di uscita; eseguirne il debug di solito significa marcare le due posizioni sulla stessa immagine. L’anteprima dell’IDE legge qualunque cosa si trovi nel frame buffer nel momento in cui esegue il polling, quindi il modo più semplice per rendere visibile l’output di un algoritmo è scrivere le annotazioni direttamente nel frame buffer. La famiglia di metodi di disegno della classe Image è proprio il set di strumenti per questo tipo di lavoro.
5.6.1. Le primitive¶
Ogni metodo di disegno colloca un tipo specifico di segno sull’immagine. Il catalogo è ridotto e resta vicino alle primitive geometriche di cui un’annotazione ha effettivamente bisogno:
draw_line()- un segmento di linea retta tra due estremi.draw_rectangle()- un rettangolo allineato agli assi, vuoto o pieno.draw_circle()- un cerchio attorno a un centro, vuoto o pieno.draw_ellipse()- un’ellisse con rotazione arbitraria.draw_cross()- un segno di più in un punto, il segno consueto per un centroide o un bersaglio di clic.draw_arrow()- una freccia da un punto iniziale a un punto finale.draw_edges()- i quattro lati di un quadrilatero arbitrario, dati i quattro punti d’angolo; il modo naturale per delineare un tag rilevato o una regione deformata in prospettiva.draw_string()- testo con un font bitmap incorporato.
Ognuno di questi metodi modifica l’immagine sorgente sul posto e restituisce la stessa immagine per il concatenamento, seguendo la convenzione dei metodi operativi stabilita in precedenza.
Le otto primitive di disegno, una per pannello. Ogni metodo produce un tipo di segno.¶
5.6.2. Colore¶
Ogni metodo di disegno accetta un argomento color che decide quale valore scrivere in ciascun pixel dipinto. La forma che assume questo argomento dipende dal formato dell’immagine. Per un’immagine RGB565, la forma naturale è una tupla (r, g, b) con ogni canale nell’intervallo 0 – 255; il modulo la impacchetta nella parola RGB565 a 16 bit prima di scriverla. Per un’immagine in scala di grigi la forma naturale è un singolo valore intero di luminosità da 0 (nero) a 255 (bianco). I metodi accettano anche il valore grezzo memorizzato dal formato - una parola impacchettata a 16 bit per RGB565, un intero a 8 bit per la scala di grigi - che è la forma efficiente quando il colore è stato calcolato altrove ed è già nella forma memorizzata.
Omettere l’argomento color dipinge in bianco. Questo valore predefinito è comodo per il lavoro in scala di grigi, dove il bianco è il valore massimo e si legge chiaramente sulla maggior parte degli sfondi. Per gli overlay di debug RGB565 è quasi sempre sbagliato: il verde o il rosso di solito si leggono meglio sul tipo di scena che una camera effettivamente vede, e un colore esplicito comunica l’intenzione.
5.6.3. Spessore e riempimento¶
La maggior parte dei metodi geometrici accetta due flag che decidono come viene disegnato il segno:
thickness=Nimposta la larghezza della linea in pixel. Il valore predefinito è1, che va bene per la maggior parte degli overlay; un valore più grande è utile quando un’annotazione deve restare visibile su una scena affollata o dopo che una fase successiva della pipeline modifica ulteriormente l’immagine.fill=Truetrasforma il segno da contorno a forma piena, dipingendo ogni pixel interno con il colore scelto. Il valore predefinito èFalse.
Questi flag non si applicano alle primitive che non hanno un interno da riempire - la linea, la croce, la freccia, il quadrilatero - dove solo thickness è significativo.
5.6.4. Disegnare il testo¶
draw_string() scrive i caratteri utilizzando un font bitmap incorporato di 8 per 10 pixel. x e y sono l’angolo in alto a sinistra della cella del primo carattere, text è la stringa da disegnare e color segue la stessa convenzione dei metodi geometrici. Il font comprende l’intero intervallo ASCII stampabile e non ha kerning - ogni carattere occupa la stessa cella larga 8 pixel - il che rende l’output facile da posizionare.
img.draw_string(10, 10, "blobs: 3", color=(0, 255, 0))
La stringa può includere a capo (\n); ogni a capo sposta il carattere successivo all’inizio di una nuova riga, dieci pixel sotto la precedente. L’argomento scale disegna ogni carattere a una dimensione maggiore secondo un fattore in virgola mobile, mentre x_spacing e y_spacing aggiungono spaziatura attorno a ciascun carattere. Un piccolo insieme di flag di rotazione / specchiatura / capovolgimento si applica all’intera stringa oppure a ciascun carattere singolarmente - controllo sufficiente per disporre il testo lungo un angolo o contro un bordo non orizzontale quando il layout lo richiede.
5.6.5. Pulire il canvas¶
Un metodo della famiglia non disegna alcun segno specifico. Si limita ad azzerare ogni pixel dell’immagine:
clear()- azzera ogni pixel, opzionalmente limitato a una ROI o circoscritto tramite una maschera.
clear() è la risposta giusta quando un’applicazione compone un’annotazione da zero a ogni frame - si parte da un canvas nero, si disegnano le nuove annotazioni, si consegna il risultato al display - invece di sovrapporsi al frame acquisito. È anche il modo più economico per preparare un’immagine temporanea da usare come buffer di maschera.
Un’immagine appena allocata è già azzerata dal costruttore, quindi clear() è rilevante in particolare per i buffer riutilizzati tra un frame e l’altro.