Progetto per Laboratorio di Informatica 3 - Rimotti Daniele, Santinelli Gabriele Plate Locator Riconoscimento Automatico di Targhe Il programma plate_locator.m prende come input: l immagine della targa binarizzata un valore binario (1: stampe attivate; 0: stampe disattivate) un messaggio di errore. Dopo aver letto e convertito l immagine dalla scala RGB alla scala di livelli di grigi viene chiesto all utente di inserire la distanza dell auto e, a seconda della scelta, vengono impostate le variabili utilizzate successivamente dal programma. L algoritmo si divide essenzialmente in 5 passi. 1. trovare tutte le variazioni di colore Consiste nel trovare tutte le variazioni di colore da nero al bianco e dal bianco al nero. Queste vengono salvate nella matrice near_positions che contiene per ogni riga le posizioni di ogni variazione trovata, mentre l array near_counter contiene il numero di variazioni per ogni riga dell immagine. Per visualizzare il risultato sono stati colorati di rosso i pixel corrispondenti a ogni variazione, ecco un esempio del risultato ottenuto dopo il primo passo.
2. trovare variazioni vicine Il secondo passo ha il compito di tenere, tra tutte le variazioni trovate nel passo precedente, solo quelle la cui distanza dalla variazione successiva sia compresa tra min_var e max_var (rappresentano la larghezza minima e massima del tratto del carattere, il valore di queste 2 variabili cambia a seconda della distanza dell auto). Delle due variazioni vicine viene mantenuta solo la prima. Si iniziano così ad eliminare molte variazioni che sicuramente non hanno niente a che vedere con la targa. Anche in questo caso le variazioni vicine vengono salvate nella matrice near_var_positions, mentre l array near_var_counter contiene il numero di variazioni vicine per ogni riga. Come si può notare, questa seconda fase ha eliminato tutte quelle variazioni troppo distanti tra loro. Questo si può facilmente notare nello stemma rotondo al centro dell immagine: tutte le variazioni centrali sono state eliminate, perchè la loro distanza è eccessiva; sono invece rimaste le variazioni agli estremi superiore e inferiore, perchè lo spessore del tratto bianco è molto simile a quello di un carattere della targa.
3. conservare righe con almeno min_hotspots "variazioni vicine" Nel terzo passo per ogni riga dell immagine ottenuta al passo precedente, vengono conservate le righe contenenti almeno min_hotspots variazioni vicine e dove almeno due variazioni non sono più distanti di max_hotspots. Questo ha lo scopo di eliminare sia le variazioni isolate, sia quelle il cui numero nella riga esaminata è esiguo (si suppone che in una targa ci siano molte variazioni vicine). Come nel passo precedente le due variabili (min_hotspots e max_hotspots) vengono impostate a valori diversi a seconda della scelta iniziale dell utente sulla distanza dell auto. Le posizioni delle variazioni rimaste, chiamate hotspots, vengono salvate nella matrice hotspots_positions, mentre l array hotspots_counter contiene il numero di hotspots per ogni riga. Si può notare come, dopo il terzo passo, siano rimasti in evidenza quasi esclusivamente gli hotspots della targa. I restanti hotspots individuati sono facilmente distinguibili da quelli della targa (ce ne sono pochi per ogni riga e la loro estensione in verticale è molto piccola) e nella fase successiva non verranno presi in considerazione.
4. trovare corrispondenze tra le righe Il quarto passo consiste nel trovare le corrispondenze tra le righe. Per ogni riga i e per ogni variazione j si controlla se nelle rows righe successive e precedenti siano presenti altre variazioni (le variazioni non devono distare più di un pixel dalla riga i). In caso affermativo si salva nella nuova matrice hotspots_positions2 l hotspots di cui si è verificata una corrispondenza nelle righe adiacenti, altrimenti altrimenti non viene salvato. Come sempre viene anche creato un array hotspots_counter2 contenente il numero di hotspots per ogni riga. La seconda figura mostra solamente gli hotspots rimasti dopo la quarta fase. Come si può notare, sono rimasti solamente gli hotspots della targa e quelli del logo FIAT, facilmente distinguibili.
5. salvare su files le targhe individuate La funzione is_plate() analizzata in seguito effettua un controllo su una singola riga (quindi muovendosi orizzontalmente), per vedere se queste potrebbero far parte di una targa. Ma questa informazione non basta: è necessario effettuare un controllo anche in verticale, muovendosi sulle righe. Una targa infatti è caratterizzata da un elevato numero di hotspots nella stessa riga, ma anche le righe successive dovranno mantenere questa particolarità. Inizialmente viene quindi creato l array binario plate_rows che segnala quali righe sono state riconosciute come presunte targhe dalla funzione is_plate(). In seguito, per ogni riga riconosciuta come presunta targa, si controlla che questa non sia isolata, ovvero che nelle successive quasi_plate righe ci sia almeno un altra riga riconosciuta come presunta targa. Qualora questa condizione si sia verificata, e nelle successive quasi_plate righe non si siano trovate altre righe riconosciute come targhe, allora potremmo trovarci di fronte a una targa. Le informazioni interessanti vengono salvate nella lista di matrici plate_info. Ogni elemento della lista corrisponde a una targa individuata: per ogni targa viene memorizzata una matrice in cui ogni riga corrisponde alle righe delle targhe riconosciute come presunte targhe dalla funzione is_plate(), e per ognuna di queste la prima cella della matrice contiene il numero di riga, la seconda cella contiene la posizione del primo hotspot di quella riga, la terza cella contiene la distanza tra il primo e l ultimo hotspot (la larghezza della targa in quella particolare riga). A questo punto il programma si troverà ad avere diverse targhe memorizzate nella lista plate_info(). Quelle composte da troppe poche righe verranno eliminate (è improbabile che si tratti di una targa), per le restanti si stabilisce la lunghezza della targa (lunghezza massima tra le lunghezze delle righe che compongono la targa, la cui dimensione si trova nella terza cella delle matrici presenti in plate_info). Se la lunghezza della targa è compresa tra min_plate_width e max_plate_width (che cambiano a seconda della distanza dell auto), allora quella che stiamo considerando è veramente una targa. Viene quindi calcolata l altezza della targa (come distanza tra la prima e l ultima riga che la compongono), l estremo sinistro (come valore minimo tra i primi hotspots della targa) e l estremo superiore (il primo hotspot della prima riga della targa). A questo punto abbiamo le dimensioni del rettangolo della targa individuato mediante gli hotspots, ovviamente questo rettangolo con grande probabilità non è sufficiente a contenere tutta la targa senza tagliarla, è quindi necessario aumentarne le sue dimensioni aggiungendo una quantità pari a due volte offset_x in orizzontale e pari a due volte offset_y in verticale (questa quantità cambia nel caso in cui il rettangolo esca dalle dimensioni dell immagine). Le dimensioni della targa individuata e la matrice contenente la regione stessa della targa vengono quindi ritornate all utente.
Funzione is_plate() Questa funzione prende come argomento: la riga su cui agire la matrice degli hotspots hotspots_positions2 l array contatore hotspots_counter2 La funzione controlla se nella riga corrente c è un numero sufficiente di hotspots (la soglia è definita dalla variabile min_var). In caso affermativo per ogni hotspot della riga controlla se il successivo hotspot dista più di check_width dal precedente. check_width è intesa come la distanza massima tra due caratteri alfanumerici, quando si supera questo valore è probabile che si sia usciti da una targa. Nel caso in cui si siano trovati alcuni hotspots a una distanza minore di check_width, allora si controlla che la distanza tra il primo e l ultmo hotspots (la lunghezza della targa) sia maggiore di min_plate_width (variabile già vista al passo 5). A questo punto possiamo conludere che la riga presa in considerazione presenta delle caratteristiche simili a quelle di una targa. Questa risposta viene ritornata sotto forma di variabile binaria (is), assieme alla localizzazione del primo hotspot della riga (xmin) e alla distanza tra il primo hotspot e l ultimo (plate_dim).