martedì 3 maggio 2011

Polifemo / monocular

Dopo un periodo di lunga assenza, oggi vorrei descrivere un progetto che ho realizzato nei ritagli di tempo (che sono veramente pochi ultimamente). Siccome il progetto è stato riadattato per un esame universitario, quella che segue è una relazione molto "accademica". 

Lo scopo del progetto è stato elaborare e costruire hardware e software per muovere automaticamente una webcam, in modo che essa segua lo spostamento di un oggetto. 














Il funzionamento è il seguente: il computer riceve un fotogramma dalla webcam ed elabora l'immagine per risalire all'eventuale posizione dell'oggetto da inseguire. Data la posizione nel fotogramma, elabora gli opportuni comandi di movimento e li invia ad una scheda di controllo, che ha il compito di controllare la posizione del motore su cui è montata la webcam.

I servomotori sono una tipologia di attuatori alimentati in corrente continua. In questo progetto si utilizza un servomotore per far ruotare la webcam che si trova montata su di esso.

Un servomotore presenta un connettore a tre fili: due per l'alimentazione e uno per il trasporto dei segnali di controllo. Questi ultimi sono segnali impulsivi periodici che trasmettono informazioni variando la durata dei propri impulsi. Prendono il nome di ''segnali PWM'', dove PWM è l'acronimo di Pulse-Width Modulation (Modulazione a Durata di Impulso).
Il servomotore associa alla durata degli impulsi la propria escursione motoria: l'elettronica di controllo riceve il segnale e, confrontando la posizione ad esso associata con quella attualmente assunta dal servo, pilota il movimento del motore.



La scheda di collegamento tra il computer e il servomotore che regola la posizione della webcam è basata su un microcontrollore programmabile della serie PIC 16F628-A.
La funzione principale di questa scheda è fornire, in modo continuativo, il segnale periodico necessario al servomotore per mantenere la sua posizione. Infatti, per il corretto funzionamento del servomotore, è necessario inviare un treno di impulsi e non un singolo segnale, che provocherebbe, invece, solo uno spostamento parziale del motore.

Complicare l'hardware inserendo questa scheda è stata una scelta progettuale che ha portato ad una semplificazione in fase di scrittura del codice di elaborazione delle immagini: in questo modo, il computer deve occuparsi solo di elaborare un fotogramma e inviare i comandi di movimento al servomotore, senza preoccuparsi di inviare anche il segnale periodico per mantenere la posizione raggiunta.






Il firmware, ossia il software memorizzato all'interno del microcontrollore, offre essenzialmente un'interfaccia con il servomotore.
Per la stesura del codice è stato utilizzato MikroC, un IDE prodotto dalla mikroElektronika che fornisce un compilatore in linguaggio C.
Il firmware può essere suddiviso in tre blocchi: ''inizializzazione'', ''generazione degli impulsi e del ritardo'' e ''interrupt''. Di seguito si trova il codice e la spiegazione delle singole fasi.

char buffer[3];
int posizione;
int cursore_buffer;
char car_letto;

void interrupt(){
        if(Uart1_data_ready()){
                car_letto=Uart1_Read();

                if(car_letto!=0x0D && car_letto!=0x0A){
                        buffer[cursore_buffer]=car_letto;
                        cursore_buffer++;
                }
                if(cursore_buffer==2){
                        buffer[2]='\0';
                        cursore_buffer=0;
                        posizione=atoi(buffer);
               }
        }
}


void main(){   
                int i;
                TRISA=0;
                TRISB=0x00001000;
                PORTB=0;

                CMCON=0x07;

                INTCON.GIE=1;
                PIE1.RCIE=1;
                INTCON.PEIE=1;

                UART1_Init(9600);

                cursore_buffer=0;
                posizione=22;
                  
                while(1){
                    RB3_bit=1;
                    for (i=0;i<posizione;i++) Delay_us(10);
                    RB3_bit=0;
                    Delay_ms(20);
                }
}

La fase di inizializzazione si occupa di configurare l'hardware del PIC e le variabili di sistema.
La fase di generazione degli impulsi e del ritardo è la fase principale del programma e consiste in un ciclo infinito. Ogni iterazione genera un impulso seguito da una pausa di circa 20 ms, in modo da produrre una frequenza di invio degli impulsi di circa 50Hz.
La fase di elaborazione dei comandi seriali è associata all'arrivo di un interrupt generato dal modulo USART del PIC a seguito della ricezione di dati dalla porta seriale. I comandi supportati dalla scheda sono tutti costituiti da un numero prefissato di caratteri. Nello specifico, la scheda si aspetta di ricevere due interi seguiti dal carattere  \t .

Il computer richiede alla webcam un singolo fotogramma, e in base alle elaborazioni su tale immagine ricava la nuova posizione che dovrà assumere il servomotore. Questo processo è totalmente indipendente dalla scheda di controllo, che serve solamente per inviare comandi al servomotore.
Nelle seguenti sezioni sarà analizzato il codice che permette alla webcam di ruotare, inseguendo un fissato pattern di pixel. Il codice utilizzato si basa sulle librerie OpenCV, che forniscono numerose funzioni già implementate.

Inseguire un punto luminoso blu
In questo caso, l'obiettivo è inseguire un LED blu: l'algoritmo cercherà di muovere la webcam in modo da posizionare il punto luminoso al centro del fotogramma, e quindi davanti alla webcam.

Dato che si deve riconoscere un semplice LED blu, per rendere più efficiente l'elaborazione si estrarrà dai fotogrammi solo il canale blu. Il pattern da inseguire sarà, quindi, il punto a intensità maggiore all'interno dell'immagine.
Ovviamente, non ci si può aspettare che l'unico oggetto ad avere dei pixel sul terzo canale sia proprio il LED da seguire, ma sicuramente tale oggetto avrà una forte componente cromatica blu.
Questo introduce uno dei principali problemi riscontrati: se il LED si trova su uno sfondo molto luminoso verrà "confuso" con lo sfondo. La soluzione implementata prevede quindi la sottrazione del background, attraverso un metodo della libreria OpenCV: la funzione cvAbsDiff , che viene utilizzata nel codice per calcolare la differenza, in termini di pixel, tra il fotogramma appena ricevuto dalla webcam e il background.
Viene poi estratto il punto di massima intensità, che corrisponde al punto più blu all'interno del fotogramma. Se questa intensità è sufficientemente elevata, viene richiamata la routine che si occupa della rotazione della webcam.

Inseguire un fissato pattern di pixel
L'obiettivo rimane sempre inseguire un oggetto, ma in questo caso l'approccio è diverso: per stabilire la posizione dell'oggetto, bisogna prima procedere al campionamento dello stesso in un template che verrà poi utilizzato in fase di ricerca.
Si fa quindi ricorso al template matching, che consiste nel far scorrere un template sull'immagine da analizzare, per poi stimare la similarità tra template e sotto-immagine corrente.
Rispetto al metodo illustrato in precedenza, quindi, cambia il metodo utilizzato per stimare la posizione dell'oggetto da inseguire, ma l'algoritmo è praticamente uguale, anche se in questo caso non c'è bisogno di ricorrere alla sottrazione del background.
La funzione della libreria OpenCV, usata per effettuare il template matching, è la \verb cvMatchTemplate . 

Nell'immagine è riportato il risultato dell'applicazione della funzione ad un'immagine di esempio. La presenza dell'oggetto in un'area è più probabile quanto più l'intensità della zona si avvicina allo zero, ossia dove l'immagine risultato presenta punti scuri. E' poi possibile, utilizzando la funzione \verb cvMaxMinLoc , trovare la zona che presenta l'intensità minima all'interno del fotogramma, così da avere una buona approssimazione della posizione dell'oggetto che si sta cercando.



Gli oggetti di cui sono stati campionati i template sono due: un quadrato fatto in cartoncino rosso e lo stesso LED usato in precedenza.
La prima soluzione funziona molto bene in ambienti con poca luce, mentre il cartoncino viene rilevato all'interno delle immagini solo se la luce ambientale è sufficiente.


Dal link qui sotto potete scaricare il codice "lato computer" che è scritto velocemente ma rende l'idea di cosa deve fare. Ah si dovrebbe anche vedere un video.

https://rapidshare.com/files/460463115/ledblu.zip




Nessun commento:

Posta un commento