UNIVERSITÀ DEGLI STUDI DI SIENA FACOLTÀ DI INGEGNERIA CORSO DI LAUREA SPECIALISTICA IN INGEGNERIA INFORMATICA Progettazione di un sistema di videosorveglianza basato sull'interpretazione automatica di scene: Sviluppi ed estensione del progetto “HuMoR” Relatore: Prof. MARCO GORI Correlatore: Ing. VINCENZO DI MASSA Tesi di Laurea di: STEFANO VOLPINI ANNO ACCADEMICO 2005-2006 SOMMARIO 1. INTRODUZIONE 4 2. HUMOR 7 PANORAMICA DI HUMOR 7 STIMA DEL BACKGROUND 9 ACQUISIZIONE E PREPROCESSING DELLE IMMAGINI SEGMENTAZIONE ESTRAZIONE DI FEATURES TRACKING TRACKING BASATO SU VOTAZIONI TRACKING BASATO SU RETI NEURALI – KOHONEN NETWORKS TRACKING BASATO SULLA DISTANZA TRA VETTORI DI FEATURES 8 13 15 19 21 23 26 CLASSIFICAZIONE 28 ANALISI 34 INTERPRETAZIONE 3. GSTREAMER 31 35 PANORAMICA DI GSTREAMER 35 PROPRIETÀ DEGLI ELEMENTI 39 GLI ELEMENTI 36 I PADS 40 LA PIPELINE 41 GST-EDITOR 43 ALCUNI STRUMENTI DI GSTREAMER GST-LAUNCH 43 45 4. INTEGRAZIONE DI HUMOR IN AMBIENTE GSTREAMER 47 HUMOR COME ELEMENTO DI GSTREAMER 48 DEFINIZIONE DEI PAD DI INGRESSO DELL'ELEMENTO HUMOR 49 PARAMETRI DELL’ELEMENTO HUMOR 53 UTILIZZO DEL PLUGIN HUMOR 60 FUNZIONAMENTO DELL’ELEMENTO HUMOR DI GSTREAMER DEFINIZIONE DEI PAD DI USCITA DELL'ELEMENTO HUMOR 5. L’ELEMENTO GSTDATADEMUXER DEFINIZIONE DEL PAD DI INGRESSO DELL'ELEMENTO GSTDATADEMUXER 50 57 61 64 PARAMETRI DELL’ELEMENTO GSTDATADEMUXER 64 UTILIZZO DEL PLUGIN GSTDATADEMUXER 68 I PAD DI USCITA DEL PLUGIN GSTDATADEMUXER 6. HUMOR ALL’OPERA IN AMBIENTE GSTREAMER DEFINIZIONE ED ESECUZIONE DI PIPELINES ESTRAZIONE DELLE FEATURES: LO SCRIPT avi2hum ADDESTRAMENTO E RICONOSCIMENTO DI SCENE 7. STATO DELL’ARTE E SVILUPPI FUTURI 67 69 69 71 77 78 IL PROGETTO HUMOR2 78 CONTESTI APPLICATIVI 79 SCALABILITÀ AD ARCHITETTURE 78 APPENDICE - SCRIPTS USATI FOCUS 81 82 CAM2AVI 83 SET2HUM 87 AVI2HUM AVI2HUMTRAIN 85 88 BIBLIOGRAFIA 89 WEBOGRAFIA 90 1. INTRODUZIONE Il presente lavoro si inserisce in un progetto più ampio relativo allo sviluppo di modelli e, conseguentemente, di macchine in grado di “vedere” e di “interpretare” una scena in movimento ripresa tramite una telecamera. Alcune delle possibili applicazioni di questo sistema sono: Videosorveglianza Interfacce uomo macchina Sistemi di visione per la robotica Punto cardine del progetto è il software HuMoR (Human Motion Recognizer), la cui idea di fondo è quella di implementare un sistema che sia in grado di capire cosa sta osservando basandosi su ciò che è cambiato nella scena, sulle traiettorie seguite dagli oggetti in movimento e sulle loro variazioni di forma durante tale spostamento. La forza di questa idea risiede nell'interpretazione dell'intera sequenza, tenendo conto della successione delle immagini, e non solo delle singole immagini scorrelate le une dalle altre. L’impiego di un sistema di interpretazione automatica delle scene potrebbe rivelarsi particolarmente utile in gran parte dei compiti di controllo e sorveglianza: controllo di posteggi, aree a traffico limitato, accesso ad edifici, aeroporti, porti navali, sorveglianza di musei, banche, appartamenti privati, esercizi commerciali, ecc. Il sistema potrebbe, ad esempio, essere in grado di decidere se e quando intraprendere o meno azioni a difesa o dell'edificio (sistema d'allarme) o delle persone che lo occupano (sistemi di sicurezza, antincendio, antipanico). HuMoR analizza una scena e la interpreta tramite modelli markoviani [11] definiti sulla base di informazioni estratte da sequenze filmate [10], con particolare riferimento alla classificazione e al riconoscimento di comportamenti umani, secondo il seguente schema: 4 1. Rilevare un movimento ed individuare chi lo ha generato 2. Tracciare il movimento compiuto dall'oggetto 3. Interpretare (classificare) il comportamento Con questa tesi si vuole estendere il software HuMoR con l’intento di integrarlo in un ambiente versatile e facilmente scalabile, come GStreamer. GStreamer è un framework open source per la gestione di flussi multimediali di dati che permette, tramite l'uso di elementi collegati opportunamente tra loro, il controllo e l'elaborazione di tali informazioni in maniera versatile ed ampiamente adattabile ad ogni casistica. Lo scopo di GStreamer è di permettere la gestione di flussi informativi di vario tipo (audio, video, binari, testo, metadati...) definendo insiemi strutturati di elementi, ciascuno specializzato in un particolare tipo di elaborazione sui dati che riceve in ingresso. La piattaforma di sviluppo che GStreamer mette a disposizione consente di creare applicativi multimediali di elevata complessità con estrema facilità e velocità, pur mantenendo intatti i gradi di libertà ed estendibilità propri di un linguaggio di programmazione. Il nostro contributo al progetto generale è stato quello di impacchettare HuMoR trasformandolo in un componente di GStreamer, unendo così le funzionalità del primo alle potenzialità, in termini di estensibilità e scalabilità, del secondo. L’approccio adottato è stato, in prima istanza, quello di analizzare HuMoR per comprenderne a fondo il funzionamento, le strutture dati utilizzate, le caratteristiche e gli eventuali limiti. Parallelamente a questo abbiamo studiato GStreamer, approfondendo i vari aspetti di questo progetto. Dopo aver compreso la filosofia che lo anima e la terminologia utilizzata, siamo passati alla realizzazione di alcuni applicativi multimediali che avrebbero potuto risultare utili nel nostro progetto (come semplici player video) utilizzando componenti e plugins esistenti, ed infine ci siamo concentrati sul codice sorgente e sulle modalità con cui è possibile estendere le sue funzionalità giungendo alla progettazione e alla realizzazione di veri e propri plugins. 5 A questo punto abbiamo iniziato a mettere insieme le varie competenze acquisite e abbiamo sviluppato un plugin di Gstreamer che mette a disposizione tutte le funzionalità di HuMoR [12]. Il risultato è quindi quello di rendere disponibile HuMoR come componente di Gstreamer e quindi perfettamente integrabile nel suo framework, garantendo al progetto scalabiltà e notevoli possibilità di sviluppo. 6 2. HUMOR PANORAMICA DI HUMOR HuMoR (Human Motion Recognizer) è un software in grado di interpretare ad alto livello una scena filmata classificandola e, successivamente, decidendo a quale tipologia appartiene scegliendo tra un insieme di scene note, secondo quanto appreso durante una fase di addestramento effettuata a priori. Attenzione particolare è stata posta nella classificazione di comportamenti umani. Nella versione originale di HuMoR si possono individuare diverse fasi successive che caratterizzano i seguenti stadi di elaborazione: 1. Acquisizione di immagini (trasferisce le immagini dalla telecamera all'elaboratore) 2. Preprocessing delle immagini (adatta le immagini alle esigenze dei componenti successivi; luminosità, contrasto...) 3. Stima del background (separa parti che sono considerate come sfondo immobile da altre che si muovono); 4. Segmentazione (estrae delle sotto-immagini contenenti ognuna solo un corpo in movimento) 5. Estrazione di features visuali (trasforma i dati relativi ai corpi in una forma “sintetica” adatta a successive elaborazioni) 6. Tracking (individua il moto di ogni corpo analizzandolo in fotogrammi differenti) 7. Classificazione (il movimento rilevato viene sintetizzato in una sequenza di simboli che si presterà ad essere confrontata con altre sequenze note) 8. Interpretazione (dato un corpo e la sua traiettoria decide, utilizzando modelli markoviani, se il corpo appartiene ad una particolare classe, per esempio un corpo umano) 9. Analisi (decide se la scena osservata deve dare luogo ad allarme) Analizziamo nel dettaglio le varie fasi individuate. 7 ACQUISIZIONE E PREPROCESSING DELLE IMMAGINI Nella fase iniziale HuMoR acquisisce il video da analizzare, proveniente da telecamere di rete, come una sequenza di immagini fornite da un server web. L’impiego di Internet Camera, ovvero di telecamere provviste di connessione ethernet 802.3 o wireless 802.11, consente di sfruttare la grande diffusione di questi protocolli rendendo il sistema utilizzabile su qualunque pc dotato di scheda di rete e soprattutto indipendente dal sistema operativo. Un importante requisito per la valutazione delle telecamere da usare è il framerate, ossia il numero di immagini che sono in grado di fornire al secondo. Considerando l’impiego principalmente rivolto al riconoscimento di comportamenti umani e all’interpretazione di scene, un valore di 20 frames al secondo consente di ottenere buoni risultati anche in situazioni delicate come il movimento degli arti di una persona. Alcune telecamere hanno un web-server integrato e non presentano particolari problemi, mentre altre possono utilizzare applet java per visualizzare i video all’interno del browser; in questi casi occorre interfacciarsi opportunamente con tali telecamere per mettere le immagini acquisite a disposizione di HuMoR. Il passo successivo è quello di effettuare il preprocessing delle immagini ricevute in modo da eliminare potenziali fonti di disturbo dovute, ad esempio, a livelli di dettaglio eccessivi ai fini del riconoscimento di scene. A seconda del tipo di azione da interpretare, infatti, alcuni particolari possono essere tranquillamente trascurati. Ad esempio un livello di dettaglio che arrivasse ad apprezzare particolari di un volto umano potrebbe essere assolutamente superfluo se l’obiettivo prefissato è quello di capire se una persona sta entrando in una zona riservata. In questo caso si può tranquillamente applicare un filtro gaussiano per livellare l’immagine stessa e, di conseguenza, ridurne il rumore. 8 STIMA DEL BACKGROUND Il passo successivo consiste nella rilevazione del movimento rispetto a ciò che si ritiene sfondo o comunque ad una o più immagini di riferimento. La stima del background è uno dei punti critici del sistema che si scontra con problematiche decisamente complesse in ambiente esterno: basti pensare all’ombra che si muove nell’arco della giornata che può venire interpretata come un oggetto in movimento; ma anche in ambienti indoor cela non poche insidie quali ad esempio l’instabilità della luce artificiale, moltiplicazione degli oggetti in movimento dovuta a fenomeni di riflessione oppure oggetti che si muovono lentamente e che possono venire parzialmente inglobati nello sfondo. Quest’ultima osservazione introduce direttamente l’elemento centrale della stima del background, ovvero la mediazione necessaria fra due fondamentali requisiti: lo sfondo deve essere aggiornato a ritmi sufficientemente rapidi da rilevare tempestivamente il movimento di un oggetto, ma non tali da tenere in considerazione soltanto la parte più recente dell’evoluzione della scena. In altre parole il sistema dovrebbe idealmente avere memoria di ciò che è avvenuto in precedenza nella scena ed allo stesso tempo essere pronto a reagire rapidamente alle sue variazioni. Da questa analisi risulta evidente che una banale implementazione del tipo 1. Memorizza un’immagine di sfondo 2. Acquisisci una nuova immagine 3. Considera in movimento tutti i pixel che sono diversi nelle due immagini 4. Torna al punto 2 soffrirà di problemi di efficacia dovuti a due implicite assunzioni non corrette: la prima immagine acquisita è lo sfondo tale sfondo non cambierà mai 9 Ovviamente entrambe sono infondate: la prima è inapplicabile nel caso in cui si voglia videosorvegliare un ambiente sul quale non si ha il pieno controllo (per esempio, se si dovesse riprendere l'interno di un aeroporto, risulterebbe difficile sfollarlo per poter catturare un’immagine in cui sia visibile solo lo sfondo). La seconda assunzione, ben più restrittiva, impone addirittura che lo sfondo non muti mai e questo, come abbiamo avuto modo di appurare, non è plausibile se non in un numero limitatissimo di situazioni. La naturale conclusione è che è indispensabile aggiornare lo sfondo. La soluzione più semplice sarebbe quella di aggiornarlo ad intervalli prefissati di tempo, ma si capisce immediatamente che non può essere una strada praticabile: se infatti lo sfondo cambia ad un istante intermedio rispetto a due aggiornamenti successivi, tutti i fotogrammi successivi alla variazione verranno male interpretati. Una soluzione alternativa potrebbe essere quella di aggiornare lo sfondo ad ogni fotogramma. Questo modo di procedere, sebbene valido in linea di principio, pone un nuovo problema: supponiamo che ad un dato istante di tempo t1 un oggetto si trovi in posizione P1 (Figura 1) , ad un istante t2 si trovi in posizione P2 (Figura 2), e che P1 abbia intersezione non nulla con P2 (Figura 3) Figura 1 Oggetto all’istante t1 Figura 2 Lo stesso oggetto all’istante t2 10 Figura 3 Movimento dell’oggetto in questo caso, aggiornando lo sfondo ad ogni fotogramma solo i pixel appartenenti all'area complementare all'intersezione vengono rilevati come in movimento dalla differenza rispetto allo sfondo (Figura 4) Figura 4 Movimento Rilevato non correttamente Risulta quindi necessario stabilire un criterio maggiormente efficace per la stima del background. In letteratura si utilizzano tipicamente due approcci differenti: nel primo si tengono in considerazione le differenze riscontrate negli ultimi due fotogrammi, nel secondo si crea un modello statistico dello sfondo [4]. Il difetto del primo approccio è quello di tenere conto solo della parte più recente dell'evoluzione della scena; l'altro metodo, invece, non consente di accorgersi 11 rapidamente di un cambiamento: è necessario un lasso di tempo consistente affinché il modello statistico dello sfondo cambi sostanzialmente. Nell’algoritmo utilizzato in HuMoR si cerca di sfruttare i vantaggi di entrambi: anziché creare un unico modello complesso per lo sfondo se ne creano molti. In questo modo, sebbene i singoli modelli vengano aggiornati lentamente, una volta creati si passa da uno all'altro con grande rapidità. In particolare, ogni pixel viene considerato come sfondo solo quando rimane stabile per un numero sufficiente di frames. Inoltre, per aumentare l’efficienza della stima si possono memorizzare più “versioni” di sfondo, in modo da rispondere efficacemente a brusche differenze generali della scena. Un caso tipico è quello dell’improvvisa variazione della luminosità dovuta all’accensione o allo spegnimento della luce in un ambiente chiuso, magari senza alcun oggetto in movimento. Situazioni di questo genere partono da uno sfondo stabile seguito da una brusca variazione della scena in cui, in prima analisi, si verifica un generale “movimento” di tutti i pixels fra due immagini consecutive. La seconda di esse acquisisce però ben presto una sua nuova stabilità e quindi diventa un nuovo candidato a background. Se si evita di sovrascrivere il primo sfondo con il nuovo, ma semplicemente si tiene in memoria un set di sfondi validi, la successiva variazione inversa (luce che viene riportata nella condizione iniziale) verrà immediatamente considerata come uno sfondo valido senza dover aspettare la ri-stabilizzazione dei pixels. Per migliorare ulteriormente l’efficacia della stima le varie immagini di riferimento vengono progressivamente invecchiate in modo da eliminare gradualmente quelle che non risultano essere più riutilizzate con il passare del tempo. 12 SEGMENTAZIONE Al termine del processo di stima del background siamo in grado di stabilire, per ognuno dei pixel dell’immagine di acquisita, se appartiene allo sfondo o meno, possiamo quindi definire l’insieme dei pixel che si sono “mossi” rispetto alla collezione di sfondi. Un sistema di rilevamento di movimento potrebbe fermarsi qua, ma per essere in grado di distinguere comportamenti diversi occorre andare oltre e stabilire l’entità e la tipologia del movimento appena rilevato, osservandone l’evoluzione e attribuendogli, in definitiva, un senso compiuto. Il primo passo in questa direzione è cercare di raggruppare i pixel che appartengono ad uno stesso oggetto, ovvero effettuare la segmentazione dell’immagine. Lavorare a livello di pixel significa imbattersi ben presto in un numero ragguardevole di confronti: in un’immagine di 160x120 = 19200 pixels è necessario effettuare 8*n confronti con i pixels adiacenti (con n numero di pixels), quindi 153600 confronti ad ogni frame. Da questa semplice analisi si conclude immediatamente che, per limitare la complessità computazionale di qualunque algoritmo che tratti confronti tra immagini, è necessario superare il concetto di pixel, ad esempio estendendolo a quello di box, ovvero una regione quadrangolare di pixel contigui, ad esempio 10x10. Ai boxes verranno associati direttamente il numero dei rispettivi pixel cambiati rispetto all’immagine di riferimento, pertanto si potranno raggruppare i boxes contigui aventi un numero di pixel cambiati superiore ad una certa soglia. In questo modo si ottengono due immediati vantaggi. Il primo è che il numero dei confronti da effettuare per determinare se 2 boxes adiacenti vanno considerati parte dello stesso oggetto decresce sensibilmente, essendo il numero dei box molto inferiore al numero dei pixel totali; nell’immagine di 160x120 con boxes di 10x10 i confronti da effettuare ad ogni frame passano a 1536, ovvero 2 ordini di grandezza in meno. Il secondo è che, ragionando in termini di boxes, si riduce il rischio di incorrere in suddivisione di uno stesso oggetto in movimento in più frammenti che verrebbero considerati, a tutti gli effetti, oggetti diversi: se un 13 oggetto venisse spezzato con un tratto di pixel di larghezza inferiore al lato del box verrebbe infatti automaticamente ricollegato grazie al fatto che l’ampiezza del box ricoprirebbe le porzione di separazione. Tale considerazione indurrebbe inoltre, se non ricorressimo ai boxes, ad effettuare confronti fra pixels non immediatamente contigui, ma anche più distanti con un conseguente ulteriore incremento di complessità. Come diretta conseguenza di quanto detto, è facile rilevare che il difetto maggiore di questo approccio risieda nel fatto che, per distinguere due oggetti, è necessario che essi siano ad almeno un box di distanza. 14 ESTRAZIONE DI FEATURES Una volta individuati e raggruppati opportunamente gli oggetti che si stanno muovendo l’obiettivo diventa quello di seguirli in modo da determinarne il comportamento. Le tecniche con cui è possibile tracciare con efficacia il movimento di un oggetto sulla scena, si basano sull’analisi di determinate features estratte dalle immagini con particolare riferimento all’area e al baricentro dei blob, oltre a determinate informazioni circa la distribuzione spaziale dei colori. Sebbene tali informazioni consentano di individuare e seguire un oggetto, per cercare di apprendere e riconoscere comportamenti e, in ultima analisi, interpretare la scena in esame, sono necessarie altre tipologie di dati. In particolare dovremmo estrarre informazioni poco sensibili a variazioni di posizione o di area ma, al tempo stesso, dovremo prestare particolare attenzione alla forma del blob, in modo da poter fare considerazioni sulla “postura” del soggetto piuttosto che sulla posizione. Inoltre è fondamentale riuscire a garantire l’invarianza rispetto ai colori, evitando così che la stessa azione compiuta da persone vestite in maniera differente o con diverso colore di capelli generi features differenti. Ciò di cui abbiamo bisogno è dunque una serie di misure geometriche dei vari blob in esame le quali, analogamente ad approcci riscontrabili in altre applicazioni, come la compressione video, hanno alla base il calcolo dei momenti di vario ordine. Di conseguenza abbiamo a che fare con una duplice tipologia di features: la prima, basata su caratteristiche prevalentemente geometriche, verrà usata per identificare la postura e quindi fornire informazioni sull’azione svolta; la seconda essendo più sensibile alle variazioni cromatiche, sarà necessaria a distinguere l’oggetto in movimento dal background ed il successivo tracking. In particolare per la classificazione degli oggetti ltiGeometricFeatures calcolate dalla libreria LTILib [19]. 15 vengono usate le Feature Group 0 (COG means "center of gravity"). feat[0] = "areasize" = (T,F) number of enclosed pixels (area). feat[1] = "bordersize" = (T,F) number of border pixels. feat[2] = "xcog" = x-component of COG. feat[3] = "ycog" = y-component of COG. feat[4] = "xmin" = smallest x coordinate. feat[5] = "xmax" = largest x coordinate. feat[6] = "ymin" = smallest y coordinate. feat[7] = "ymax" = largest y coordinate. feat[26]= "compactness" = (T,R,S,F) compactness = (4PI*area /(bordersize)^2), ranges from 0 to 1. Feature Group 1 [16]. feat[8] = "m02" = (T) central moment m02. feat[9] = "m03" = (T) central moment m03. feat[10]= "m11" = (T) central moment m11. feat[11]= "m12" = (T) central moment m12. feat[12]= "m20" = (T) central moment m20. feat[13]= "m21" = (T) central moment m21. feat[14]= "m30" = (T) central moment m30. feat[22]= "j1" = (T,R,F) inertia parallel to main axis. feat[23]= "j2" = (T,R,F) inertia orthogonal to main axis. feat[24]= "orientation" = (T,S) orientation of main axis. range: -90 to 90 degrees. feat[25]= "eccentricity"= (T,R,S,F) eccentricity, ranges from 0 (=circle) to 1 (=line). 16 Feature Group 2. These are the first 7 moment invariants as described in [27] feat[15]= "hu1" = (T,R,S,F) moment invariant 1. feat[16]= "hu2" = (T,R,S,F) moment invariant 2. feat[17]= "hu3" = (T,R,S,F) moment invariant 3. feat[18]= "hu4" = (T,R,S,F) moment invariant 4. feat[19]= "hu5" = (T,R,S,F) moment invariant 5. feat[20]= "hu6" = (T,R,S,F) moment invariant 6. feat[21]= "hu7" = (T,R,S) moment invariant 7. Feature Group 4. All the following distances are relative to the COG. feat[27]= "rmin" = (T,R,F) minimum distance to border. feat[28]= "rmax" = (T,R,F) maximum distance to border. feat[29]= "rmean" = (T,R,F) mean distance to border. feat[30]= "dleft" = (T,R -90°to+90°) leftmost distance to main axis. feat[31]= "dright" = (T,R -90°to+90°) rightmost distance to main axis. feat[32]= "dfront" = (T,R -90°to+90°) frontmost distance to COG, along main axis. feat[33]= "drear" = (T,R -90°to+90°) rearmost distance to COG, along main axis. Queste features vengono utilizzate tutte tranne la 2 (x-component of COG) e la 3 (y-component of COG) per rendere gli oggetti indipendenti dalla posizione che occupano nella scena. Le features necessarie al tracker si calcolano nel seguente modo: 17 /* I valori RGB sono normalizzati tra 0 e 1 */ xdist_r = xdist_r + ( i - x ) * red; xdist_g = xdist_g + ( i - x ) * green; xdist_b = xdist_b + ( i - x ) * blue; ydist_r = ydist_r + ( j - y ) * red; ydist_g = ydist_g + ( j - y ) * green; ydist_b = ydist_b + ( j - y ) * blue; xrel_q = ( i - x ) * ( i - x ); yrel_q = ( j - y ) * ( j - y ); tr = ( xrel_q + yrel_q ) * red; tg = ( xrel_q + yrel_q ) * green; tb = ( xrel_q + yrel_q ) * blue; moment_r = moment_r + tr; moment_g = moment_g + tg; moment_b = moment_b + tb; Come si vede dal codice vengono calcolati le distribuzioni lungo l'asse X, lungo l'asse Y e il momento del secondo ordine. Ad ogni pixels viene dato un peso che è pari al suo valore di rosso, di verde e di blu, infatti abbiamo tre valori per ogni features calcolata, uno per ogni colore. 18 TRACKING Il tracking è il processo che ha il compito di seguire lo spostamento di un oggetto in movimento nella scena (blob) tracciando l’evolversi della sua posizione nel tempo. Per stabilire che un determinato oggetto si sta muovendo, è necessario analizzare i blob rilevati in due fotogrammi consecutivi e determinare se sono stati effettivamente prodotti dallo stesso oggetto nonostante le diversa posizione. L’elemento centrale diventa quindi definire quanto due blob siano somiglianti al punto da rappresentare uno stesso oggetto reale. Già da una prima analisi si evince la necessità di scartare il confronto a livello di pixel, sia per la diversa angolazione da cui una telecamera fissa riprende un oggetto che si muove, sia per la naturale deformazione di determinati oggetti in movimento come persone o animali. Altre complicazioni possono sopraggiungere nei casi in cui un oggetto cromaticamente simile allo sfondo può venire suddiviso in più parti oppure più oggetti si sovrappongano e vengano quindi riuniti in un unico blob. A questo livello risulta ragionevole non occuparsi del secondo aspetto per il quale sono spesso necessarie nozioni di un certo valore cognitivo per comprendere ad esempio che due persone che camminano molto vicine debbano essere considerate come oggetti diversi, specialmente se entrano nell’inquadratura già in maniera sovrapposta. Possiamo anzi supporre che proprio lo scopo di questo lavoro – il riconoscimento dei comportamenti umani – possa essere un buon punto di partenza per poter successivamente discernere quei casi in cui un’azione appresa possa essere riconosciuta anche se i soggetti sono più di uno, magari sovrapposti. Il tracker integrato in HuMoR si occupa invece del primo aspetto, ovvero evitare che un oggetto in movimento venga spezzato, riunendo i vari blob che la segmentazione può aver prodotto a partire da un unico oggetto. In particolare si rende necessario tenere traccia di ciascuno degli oggetti presenti nella scena al variare del tempo. 19 L'informazione su un singolo oggetto già individuato in passato ed estratta frame per frame, viene memorizzata all'interno di una lista di vettori che risultano dunque composti dalle sequenze di features estratte dai blob individuati dal segmentatore (tale lista è chiamata track). Le tracks di tutti questi oggetti vengono memorizzate in una lista di tracks (tracklist). Per decidere se gli oggetti presenti in un nuovo fotogramma sono già stati osservati, le features di ogni suo blob vengono confrontate con quelle presenti nelle varie tracks della tracklist. Se il confronto ha esito positivo per una particolare coppia di blob e track, quindi se l'oggetto corrispondente è già stato tracciato nei fotogrammi precedenti, si aggiungono le features del blob in esame in coda a quelle della sua track. Se invece nessuna track genera corrispondenza con il blob in esame e quindi se l'oggetto compare nella scena per la prima volta, è necessario aggiungere una nuova track alla tracklist. Risulta dunque evidente che il funzionamento del tracker sarà fortemente caratterizzato dalle modalità con cui si effettuano i confronti tra le features dei nuovi blob e quelle presenti nella tracklist e, in ultima analisi, da quando un oggetto osservato deve essere considerato l’evoluzione temporale di un altro oggetto già considerato in precedenza e dunque collegato logicamente ad esso. Ognuna di queste tipologie di comparazione ha dei vantaggi particolari che la rendono utile in determinate condizioni o per evidenziare specifiche condizioni, ma nessuna può essere considerata migliore delle altre in termini assoluti. Entrando più nel dettaglio sono state implementate tre diverse modalità di tracking, basate su uno dei seguenti approcci: 1. votazioni 2. reti neurali – Kohonen Networks [5] 3. distanza tra vettori di features 20 TRACKING BASATO SU VOTAZIONI Questo è stato il primo (in ordine di tempo) ad essere stato implementato e si basa su un sistema di votazioni. Vengono calcolate le features per ogni oggetto nell'immagine attuale e ognuna viene confrontata con le features degli oggetti tracciati fino a quel momento. Ad ogni feature confrontata viene assegnato un voto di “somiglianza”, al termine questi voti vengono sommati e ogni oggetto viene associato l'oggetto che ha ricevuto la votazione più alta, se questa è maggiore della soglia minima. Con questo sistema è possibile dare pesi differenti alle singole features, quindi più o meno importanza a seconda delle condizioni. Inoltre le features più importanti, ossia le coordinate del baricentro e l'area, vengono usate come discriminanti, nel senso che se due oggetti non hanno queste tre features “compatibili” verrà automaticamente assegnato un voto pari a 0. In particolare, dati due vettori di features, F’ e F’’ si calcola il vettore D del valore assoluto delle differenze D = |F’ - F’’| D viene poi moltiplicato scalarmente per il vettore W dei pesi assegnati alle singole features, ottenendo R R=DxW Supponendo un numero di features discriminanti pari a k, confronteremo il vettore S delle soglie (di dimensione k) con i k elementi corrispondenti di R. Se tutti i k elementi superano la rispettiva soglia allora la somma degli elementi di R è il voto ottenuto, altrimenti il voto è 0. I parametri usati per i confronti sono frutto di un lungo lavoro di settaggio pressoché manuale, inoltre tali valori sono decisamente dipendenti dalla scena osservata. 21 Lo spostamento della telecamera da un ambiente all'altro comporta la necessità di calcolare nuovamente tali parametri. Tali variazioni sono dovute alle differenze di segmentazione degli oggetti causate da diverse condizioni ambientali. Per esempio può capitare che, sebbene in un determinato ambiente un oggetto venga individuato correttamente in tutte le sue parti e che anche durante i suoi spostamenti la sua forma rimanga sempre ben definita, passando in un altro ambiente con uno sfondo differente, nello spostamento dell’oggetto alcune sue parti vengano confuse con lo sfondo, determinando quindi una pesante variazione della sua forma originaria. In questo caso bisognerebbe consentire delle variazioni maggiori ad esempio dell'area. Questo problema si presenta non solo per sfondi simili all'oggetto, ma anche per cambiamenti di illuminazione. Le prestazioni di questo algoritmo sono risultate soddisfacenti solo dopo aver accuratamente tarato tutti i parametri, ma questo è un difetto che, di fatto, lo rende inutilizzabile. 22 TRACKING BASATO SU RETI NEURALI – KOHONEN NETWORKS Questo sistema di tracking prende spunto dal lavoro realizzato da Gilles Labonté [8] per lo studio della dinamica dei fluidi basato sull’osservazione del movimento nel tempo di determinate particelle. Le maggiori difficoltà incontrate sono dovute al numero elevato di particelle da tracciare e al fatto che molte di esse entrano ed escono continuamente dalla scena osservata. La soluzione proposta da Labonté è stata quella di utilizzare delle Self-Organizing Map (SOM). Le SOM sono reti neurali in grado di apprendere in modo non supervisionato e nel caso specifico, sono state opportunamente modificate per mappare le particelle di un'immagine con le particelle della successiva. Consideriamo due reti neurali, una per l'immagine all'istante t e l'altra per l'immagine all'istante t+1, con un numero di neuroni pari al numero di oggetti rilevati nell’immagine stessa. Nelle figure che seguono vengono rappresentati i neuroni corrispondenti agli oggetti rilevati a 2 istanti di tempo successivi che, come evidenziato, possono non essere in numero uguale. Figura 5 Figura 6 23 Supponendo di sovrapporre le due immagini otterremmo la seguente situazione, dalla quale non è ben chiaro quali neuroni rappresentano lo stesso oggetto ad istanti successivi e quale, invece è subentrato in scena solo nella seconda immagine. Figura 7 Ora, per entrambe le reti, inizializziamo i neuroni con il vettore delle features di un oggetto dell'immagine a cui è associata ed associamo come input i vettori delle features degli oggetti dell'immagine che fa riferimento all'altra rete Figura 8 24 A questo punto può iniziare l'addestramento delle SOM in modo alternato, ovvero con un passo di addestramento ciascuna. Ad ogni passo i neuroni sono attratti dai vettori di input in modo inversamente proporzionale alla loro distanza. Figura 9 Al termine troveremo che gli oggetti che possono essere associati hanno i rispettivi neuroni “vicini” e quindi avremo determinato una corrispondenza diretta tra gli oggetti della prima immagine e quelli della seconda. Figura 10 25 Queste reti sono ispirate alle Khonen Networks, dalle quali si differenziano principalmente per il diverso modo in cui vengono aggiornati i pesi dei neuroni. Il vantaggio di questo algoritmo è quello di essere molto efficace in presenza di molti oggetti, purtroppo funziona peggio degli altri quando nella scena non c'è troppo movimento rilevato. Altre situazioni critiche sono rappresentate da oggetti che variano repentinamente la propria postura, ad esempio una persona che ruota bruscamente su se stessa: il tracker non è in grado di tracciare la scena con continuità. TRACKING BASATO SULLA DISTANZA TRA VETTORI DI FEATURES Il sistema basato su distanza tra i vettori è un caso particolare del sistema basato su votazione: si tratta semplicemente di utilizzare una qualche forma di distanza in sostituzione del voto per decidere quanto un vettore sia simile ad un altro. Il vantaggio è che questo sistema non necessita di impostazioni manuali, lo svantaggio è che non funziona bene se i vettori hanno numerosi elementi, principalmente a causa del fatto che dalla distanza non si capisce che tipo di variazione si sia verificata: non si ricostruisce infatti se sono cambiate leggermente molte componenti oppure se ne è cambiata una sola ma in modo molto evidente. Per limitare tale effetto indesiderato si è pensato di determinare un ristretto sottoinsieme di features con cui descrivere l’oggetto. Sperimentalmente è stato riscontrato che un modo in cui questo tracker funziona particolarmente bene è usando un vettore di features composto unicamente da area e coordinate del baricentro del blob in esame: (Xc, Yc, sqrt(Area)) Il motivo è che, nonostante queste features non siano altamente descrittive delle caratteristiche grafiche del blob, sono difficilmente confondibili con quelle di un altro oggetto in quanto: 26 1. l'area impedisce che si confrontino oggetti troppo grandi con altri troppo piccoli: si assume che un oggetto non cambi troppo repentinamente le proprie dimensioni; si suppone quindi indirettamente che la qualità della segmentazione si sufficientemente elevata in modo da evitare di confondere un oggetto con lo sfondo, cosa che ridurrebbe di colpo la sua area. 2. la posizione del baricentro impedisce di confondere oggetti troppo distanti: si assume che un oggetto non si muova a velocità troppo elevate tali da percorrere uno spazio eccessivo da un fotogramma all'altro. La descrizione a grandi linee dell’algoritmo impiegato può essere la seguente: ad ogni oggetto presente all'istante t viene assegnato l'oggetto a lui più vicino all’istante t+1, secondo la distanza tra i rispettivi vettori di features. Successivamente viene controllato se ci sono state delle “collisioni”, ossia se a più oggetti del primo frame è stato assegnato lo stesso oggetto del secondo frame, in questo caso viene scelto l'oggetto del primo frame più vicino. Questo tipo di tracker riesce a tracciare la brusca variazione di forma di un oggetto, situazione invece critica per il tracker basto su SOM. Se la segmentazione non ha un buon livello di qualità, presenta però problemi di varia natura; specialmente in casi di cattiva illuminazione e conseguente bassa qualità delle immagini acquisite. 27 CLASSIFICAZIONE Dopo avere tracciato gli oggetti in movimento sulla scena ed avere generato una sequenza di features che rappresentano l'oggetto nei vari frames, bisogna passare ad un livello di astrazione ancora più elevato, creando una sequenza di simboli che rappresenti una particolare azione, a partire dalle features estratte. I simboli di tale sequenza vengono creati tramite K_Means: un algoritmo di clustering non supervisionato che raggruppa un insieme di dati, sotto forma di vettori, in sottoinsiemi di elementi “simili” rappresentati da un unico vettore leader detto centroide [2][3]. Nel nostro caso ad ogni oggetto tracciato viene assegnato il simbolo, ovvero un semplice numero intero identificativo del cluster a cui appartiene il vettore delle features che lo rappresenta. Il funzionamento di k-means è il seguente: 1. Vengono inizializzati in modo random i centri di k clusters. 2. Ogni vettore da raggruppare viene assegnato al cluster a lui più vicino. 3. Si calcola la media di ogni cluster e si sposta il centroide nel suo punto medio. 4. Vengono riassegnati i vettori da raggruppare ai clusters così modificati. I punti 3 e 4 vengono ripetuti fino a che non ci sono vettori che al punto 4 migrano da un cluster all'altro. In realtà, all’algoritmo originale sono state apportate alcune lievi modifiche per adattarlo alle esigenze specifiche. La prima ottimizzazione è stata quella di calcolare il minimo e il massimo valore che assumono i vettori per ogni coordinata al momento della lettura dei dati in input e di limitare l'inizializzazione dei centroidi all'interno di questo range di valori. La seconda consiste invece nel calcolare il raggio medio per ogni clusters in modo da avere, durante la classificazione successiva, un parametro che consenta di evitare il raggruppamento di oggetti con features significativamente diverse, ad 28 esempio con distanza dal centroide due o tre volte maggiore del raggio medio del cluster. K-means funziona ottimamente se il numero di clusters è corretto, ma non è in grado di decidere autonomamente quanti dovrebbero essere i clusters in cui suddividere l'insieme iniziale dei dati, si pone dunque il problema di stabilire il parametro k. Una sovrastima di k può portare alla creazione, soprattutto in uno spazio a 32 dimensioni, di clusters vuoti. Figura 11 centroidi inizializzati casualmente Figura 12 disposizione finale dei centroidi con 2 cluster vuoti Per ovviare a questo problema è stata sviluppata una variante denominata “Adattiva” che permette di eliminare i cluster ai quali non viene assegnato nessun elemento. Questa soluzione può rendere difficoltosa la distinzione tra posizioni differenti di un oggetto durante il suo movimento a causa della significativa diminuzione dei cluster. E’ stata quindi introdotto la modalità “Forced”, in cui tutti i clusters devono essere necessariamente assegnati. Per raggiungere questo obiettivo viene ripetuto più volte l'algoritmo, modificando però di volta in volta l'inizializzazione dei centroidi tenendo conto dell'informazione data dal raggruppamento effettuato dagli step precedenti e posizionando i centroidi forzatamente in aree già individuate come significative. 29 Figura 13 individuazione aree significative Figura 14 re-inizializzazione forzata dei centroidi Figura 15 classificazione finale corretta La classificazione analizza dunque la sequenza delle immagini, più in particolare la sequenza delle “forme” o posture assunte dall'oggetto che si muove sulla scena in ogni frame, associando ad ognuna di esse un simbolo. Di conseguenza il classificatore usato “osservando” un gran numero di vettori di features, è in grado di raggruppare quelli simili caratterizzandoli con un unico simbolo; al termine avremo quindi una sequenza di tali simboli. 30 INTERPRETAZIONE L'ultimo step è quello di interpretare la scena ripresa dalla telecamera. Per raggiungere questo obiettivo, l’idea di fondo dell’intero progetto HuMoR è quella di determinare un modello di Markov della scena stessa e confrontarlo con altri modelli ottenuti in una precedente fase in cui sono state presentate al sistema altre scene a titolo di esempio. Tali azioni devono venire catalogate e classificate da un operatore, permettendo al sistema di generare sequenze di riferimento da confrontare in seguito con quelle originate da nuove scene. Vediamo dunque nel dettaglio cosa sono e come vengono generati tali sequenze a partire dalle scene osservate, sia quelle di esempio che quelle da interpretare, per poterle successivamente confrontare tra loro. Un modello di Markov – in particolare un HMM, o modello markoviano nascosto – è in grado di apprendere, tramite algoritmi supervisionati, sequenze di simboli. Tale modello, una volta addestrato su delle sequenze di esempio, è in grado di analizzare sequenze nuove (cioè sequenze non presenti nell'insieme di addestramento) e di giudicare in che misura tali nuove sequenze sono simili a quelle note. Per comprendere il funzionamento di un Hidden Markov Model si rende necessario un breve richiamo sulle catene di Markov, che sono alla base degli HMM. I processi Markoviani sono processi stocastici che modellano situazioni in cui la transizione tra stati non è deterministica, ma probabilistica, ed è caratterizzata dal fatto che la probabilità di transire in uno stato successivo dipende esclusivamente dallo stato attuale. Una catena di Markov a tempo discreto è completamente specificata da: 1. ∑: spazio degli stati (numerabile) 2. ρ0 (x): probabilità dello stato iniziale 3. ρ0 (xi,xj): probabilità di transizione dallo stato i allo stato j 31 Supponiamo, a titolo di esempio, di voler descrivere l’andamento delle vendite di un libro mediante i 2 semplici stati seguenti x1 vendite in aumento x2 vendite in calo e che l’andamento delle vendite possa ragionevolmente essere modellato come segue: se le vendite sono attualmente in aumento, continueranno ad esserlo con il 70% di probabilità se le vendite sono attualmente in calo, continueranno ad esserlo con il 50% di probabilità La matrice di transizione degli stati sarà: 0.7 0.3 P = 0.5 0.5 Che può essere rappresentata tramite il seguente diagramma: Nel caso degli Hidden Markov Models invece lo stato è nascosto (hidden), nel senso che, in teoria, non è immediata la sua corrispondenza con una situazione reale e soprattutto non siamo in grado di stabilire in che stato ci troviamo, quindi lo stato non è “misurabile”. 32 In molte applicazioni pratiche, tuttavia, può venire attribuito agli stati (o a insiemi di stati) del modello un significato fisico. Inoltre ad ogni stato è associata la probabilità di emettere un simbolo, oltre alla probabilità di transizione in un altro stato. Chiariamo questi concetti con un semplice esempio tratto dal tutorial di L.R. Rabiner [7]. Supponiamo di avere a disposizione N urne, in ognuna di esse ci sono delle biglie colorate, di M colori diversi. Per ogni urna, in base al numero di biglie contenute e al numero di biglie di ogni colore, possiamo calcolare la probabilità che venga presa una biglia di un determinato colore. Questa probabilità varia da urna a urna, poiché le urne non contengono lo stesso numero di biglie. Ogni urna nel nostro modello rappresenta uno stato, e il colore delle biglie rappresenta un simbolo. Noi non sappiamo da quale urna iniziamo, e non sappiamo nemmeno quale sarà l'urna successiva, tutto questo viene stabilito da un processo random. Al termine delle estrazioni otteniamo però una sequenza di osservazioni di questo tipo: O = {verde, verde, blu, rosso,giallo,rosso,...,blu} Sebbene non sia in generale ricostruibile con certezza l’esatta successione di estrazioni di una certa biglia, da una specifica urna, che ha portato all’osservazione che si è manifestata, è possibile tuttavia stabilire con quale probabilità le biglie siano state estratte dalle urne in un determinato ordine; associando dunque ad ogni sequenza di stati (rappresentati dalle urne) la rispettiva probabilità di aver generato l’osservazione O. Tra tutte le possibili sequenze di stati (urne) che possono aver dato luogo a quella di simboli (i colori delle biglie) osservata, potremo scegliere quella con la probabilità maggiore, stabilendo una corrispondenza tra l’osservazione O e la sequenza di stati che, più verosimilmente, la rappresenta. 33 Un HMM è dunque caratterizzato dai seguenti elementi: 1. N, numero degli stati del modello 2. M, numero dei distinti simboli di osservazione per stato 3. La matrice di probabilità di transizione di stato: A = [ ai,j ] 4. La probabilità di emettere un simbolo k nello stato j: B = { bj(k) } dove: b j (k ) = P [v k all' istante t | qt = S j ] , 5. La probabilità dello stato iniziale π = {π i } 1≤ j ≤ N , 1≤ k ≤ M con: π i = P [q1 = S i ] 1≤ j ≤ N HuMoR fa uso di una batteria di HMM: ogni HMM viene addestrato per riconoscere un particolare comportamento; ovvero ogni tipologia di azione che vogliamo identificare in seguito viene fatta “vedere” al sistema in diverse versioni in modo da poter costruire un modello tipo da associare ad essa. L'intera batteria di modelli analizza, una volta addestrata, le nuove sequenze e fra tutti i modelli sceglie quello che ha la probabilità più alta di aver generato la sequenza vista; scegliere un modello significa quindi scegliere tra i comportamenti appresi durante il training quello che è più simile alla scena appena osservata. ANALISI Una volta riconosciuta un’azione ed associata ad uno dei comportamenti noti, il passo successivo e finale è semplicemente quello di decidere se o quale contromisura intraprendere. Qui le possibilità sono molteplici e dipendono strettamente dal contesto in cui viene impiegato il sistema. Potrebbe essere necessario attivare un allarme, oppure registrare soltanto il fatto rilevato o magari attivare un altro dispositivo di sicurezza. Gli aspetti relativi alle conseguenze dell’azione identificata, oltre ad avere una valenza tecnica meno rilevante, esulano tuttavia dai nostri scopi. 34 3. GSTREAMER PANORAMICA DI GSTREAMER GStreamer è un framework open source per la gestione di flussi multimediali di dati che permette, tramite l'uso di elementi collegati opportunamente tra loro, il controllo e l'elaborazione di tali informazioni in maniera versatile ed ampiamente adattabile ad ogni casistica. Lo scopo di GStreamer è di permettere la gestione di flussi informativi di vario tipo (audio, video, binari, testo, metadati...) definendo insiemi strutturati di elementi definiti pipelines, ciascuno specializzato in un particolare tipo di elaborazione sui dati che riceve in ingresso. In un primo approccio, l'interfaccia per la definizione delle pipelines utilizza una sintassi mirata alla progettazione di uno schema di elementi connessi tra loro, con la struttura tipica di un diagramma a blocchi, permettendo di definire rapidamente una pipeline complessa e adattabile ad ogni tipologia di elaborazione con estrema efficacia e senza particolari nozioni di programmazione di basso livello. Se da un lato la piattaforma di sviluppo che GStreamer mette a disposizione consente, quindi, di creare applicativi multimediali di elevata complessità con estrema facilità e velocità, dall’altro vengono mantenuti intatti i gradi di libertà ed estendibilità propri di un linguaggio di programmazione. Sono infatti disponibili librerie che permettono l'inclusione e l'uso, in ambiente C/C++, di primitive per il completo utilizzo delle varie funzionalità e per la creazione di pipelines in modo da poter sfruttare le potenzialità offerte da GStreamer anche nello sviluppo di applicativi propri, grazie anche alla disponibilità del codice sorgente stesso [14]. Proprio grazie alla piattaforma open source, è inoltre possibile sviluppare nuovi componenti o plugins con il prezioso supporto di una dettagliata documentazione liberamente disponibile [15]. 35 GLI ELEMENTI Le unità elaborative di base, utilizzabili all'interno delle strutture interconnessione e di gestione dei flussi di dati, sono gli elementi della pipeline. di Si tratta di blocchi caratterizzati da uno o più ingressi/uscite (rispettivamente sink e source pads) a cui, rispettivamente, inviare in input ed ottenere in output, il flusso di dati opportunamente elaborato secondo le peculiarità dell'elemento utilizzato. Gli elementi, vengono classificati e raggruppati in opportune categorie all'interno di una struttura ad albero, a seconda del tipo di lavoro svolto sui dati che ricevono in ingresso. Figura 16 36 Come si vede dalla Figura 16 un primo raggruppamento viene effettuato secondo una serie di categorie radice, come "codec", "sink", "source", "visualization", "generic", etc. Tali categorie si possono poi suddividere in altre sottocategorie, fino ad arrivare alle foglie della struttura, in cui troviamo gli elementi stessi. Per utilizzare ad esempio un encoder DV, utile per la compressione video di un filmato, sarà sufficiente scorrere, in maniera del tutto intuitiva, l’albero degli elementi partendo dalla categoria Codec, quindi entrare nelle sottocategorie Encoder e successivamente Video. Figura 17 Esistono inoltre dei particolari elementi, i sinks ed i sources, che sono rispettivamente consumatori e produttori di flussi di dati: i primi hanno solo uno o 37 più pads di ingresso ma non hanno uscite, mentre i sources non hanno ingressi sebbene possano disporre di una o più uscite. Questi particolari elementi vengono raggruppati distintamente in due apposite categorie nettamente separate dalle altre, le quali contengono invece tutte elementi in grado di elaborare i dati da cui vengono attraversati (disponendo cioè sia di input che di output), classificabili quindi in un unico tipo: i filters. In Figura 18 viene evidenziato un elemento terminale che si occupa di scrivere un flusso di dati su un generico file. Un elemento di questo tipo si chiama filesink, ed è disponibile all’interno della categoria sink e quindi file. Figura 18 38 PROPRIETÀ DEGLI ELEMENTI Gli elementi di GStreamer non sono solamente semplici "black box" che elaborano il flusso dati che ricevono in ingresso prima di inviarli all’uscita. Le modalità con cui l'elaborazione ha luogo e svariate altre caratteristiche sono configurabili direttamente dall'utente attraverso le cosiddette proprietà dell'elemento. Le proprietà sono, a tutti gli effetti, dei veri e propri parametri di configurazione da specificare: possono sia modificare l'elaborazione del flusso che attivare una qualsiasi caratteristica dell'elemento; la loro impostazione può inoltre essere facoltativa o prevedere valori di default. Ad esempio, un filesrc ha bisogno che venga specificato il nome del file da leggere con cui generare il flusso di dati da fornire in uscita; per fare questo è necessario specificare la sua proprietà location. Vedremo successivamente che il plugin che abbiamo sviluppato per implementare le funzionalità HuMoR, prevede la possibilità di attivare o disattivare una finestra di visualizzazione dei risultati dell'analisi tramite la proprietà view. Tale opzione è facoltativa, poiché nel caso in cui non venga specificata assumerà un valore di default impostato su OFF. 39 I PADS I Pads, come abbiamo avuto modo di vedere in precedenza, non sono altro che le unità che permettono di interconnettere i vari elementi di una pipeline. Un ulteriore importante compito svolto dai pads è quello di effettuare la negoziazione del flusso dei dati: dal momento che ognuno di essi è caratterizzato da un determinato tipo (o tipi) di dati che è in grado di gestire, è possibile testare, una volta richiesto il collegamento con il pad di un altro elemento, che i dati trattati dai due pads siano compatibili. Ogni elemento può avere uno o più source pads attraverso i quali produce dati in uscita e analogamente uno o più sink pads, con i quali accetta dati in ingresso; mentre i filter elements possono avere elementi di entrambi i tipi, solo source o sink pads sono presenti nei source o sink elements rispettivamente. Figura 19 filter element con ingressi e uscite Figura 20 source element Figura 21 sink element 40 LA PIPELINE L'interconnessione degli elementi permette di definire una struttura di elaborazione di un flusso di dati chiamata pipeline, altamente versatile ed adattabile ad ogni necessità o tipologia di problema. Figura 22 Figura 23 41 In Figura 23 è riportato un esempio di pipeline, creata utilizzando l'editor grafico gst-editor, il quale permette di effettuare questa operazione con estrema semplicità: è sufficiente selezionare gli elementi da inserire e unirli opportunamente tra loro, trascinando con il mouse i pads da collegare, fino a formare un diagramma a blocchi. Nell'esempio in questione il primo elemento è un source di un pattern video per scopi di test, collegato ad ximagesink, un sink di visualizzazione che si occupa di trasferire su una finestra di output video (visualizzata in figura in primo piano rispetto a quella dell'editor) i dati in arrivo al suo pad di ingresso. Il risultato, una volta premuto il tasto play, è proprio l’apertura della finestra di visualizzazione dell’immagine di test. 42 ALCUNI STRUMENTI DI GSTREAMER Analizziamo ora alcune delle funzionalità fornite da GStreamer mediante alcuni strumenti messi a disposizione per vari utilizzi, entrando nel dettaglio di quelli che sono stati indispensabili per lo sviluppo dei plugin e delle pipelines creati. GST-EDITOR Già dall’esempio precedente, in cui viene definita una banale pipeline dimostrativa, è stato introdotto gst-editor, uno strumento di semplice utilizzo che permette di costruire ed eseguire pipelines, mediante la semplice interfaccia grafica, in maniera del tutto intuitiva e veloce. Tale applicativo permette di scegliere gli elementi e sistemarli su una finestra (selezionandoli con il mouse e trascinandoli), in modo da poterli collegare opportunamente formando un diagramma a blocchi di immediata comprensione, che costituirà la pipeline da eseguire. L'interfaccia utente dell'editor si presenta alla sua apertura con tre finestre: quella principale è l'area vera e propria di lavoro specifica di una pipeline; al suo interno possono essere inseriti e collegati gli elementi e successivamente, a lavoro ultimato, si può lanciare l'elaborazione (premendo il tasto play), per verificare il funzionamento ed utilizzare direttamente la pipeline creata. Figura 24 43 E' possibile salvare in formato xml le pipelines create per poi ricaricarle successivamente ed eventualmente modificarle. Gli elementi, organizzati secondo la gerarchia di categorie e sottocategorie, sono selezionabili per l'inserimento sulla pipeline comodamente dalla finestra utility palette, dalla quale è possibile anche eseguire una rapida ricerca full text per individuare con facilità un elemento a partire da certe sue caratteristiche, oltre ad impostare il livello di debug da utilizzare in fase di esecuzione. Figura 25 L'ultima finestra, chiamata properties, serve infine per visualizzare ed editare le proprietà disponibili di un oggetto selezionato sull'area di lavoro E’ presente un secondo tab pads che permette di visualizzare tutti i source e sink pads dell'oggetto, visualizzando inoltre tutte le capabilities, ovvero i tipi di dati supportati da ognuno di essi; questa possibilità risulta molto utile per verificare immediatamente se l’elemento selezionato può essere utilizzato per gli scopi 44 prefissati e per prevedere se il collegamento con un altro elemento sarà possibile o meno. Figura 26 GST-LAUNCH Il comando principale per l'esecuzione di una pipeline da shell è gst-launch, con il quale è possibile contestualmente definire una pipeline utilizzando una sintassi di facile ed immediata comprensione, ma di grande versatilità. E' sufficiente elencare per nome gli elementi da utilizzare nella stessa sequenza in cui il flusso dei dati deve essere elaborato, semplicemente separandoli con un “ ! ” (punto esclamativo) ed uno spazio prima e dopo ogni nome. Eventuali proprietà possono essere impostate specificandone il nome ed immettendo il valore da assegnare di seguito dopo un “=”. La sintassi è dunque la seguente: Element1 [Property1=Value1][ [Property2=Value2]]... _ [ ! ElementN [PropertyN=ValueN]] 45 ! Element2 La semplice pipeline di esempio già vista in Figura 23, che implementa l'output del video di test, è il seguente: videotestsrc ! ximagesink Se si prova a lanciare tale pipeline tramite il comando gst-launch videotestsrc ! ximagesink si potrà visualizzare ovviamente lo stesso output ottenuto lanciandola tramite l'editor. La possibilità di creare ed eseguire pipelines direttamente da riga di comando ci è stata particolarmente utile per creare scripts parametrizzati, in grado di eseguire una serie di operazioni che fanno utilizzo di HuMoR tramite GStreamer. 46 4. INTEGRAZIONE DI HUMOR IN AMBIENTE GSTREAMER Dall’analisi effettuata si può chiaramente capire come la possibilità di rendere disponibili le funzionalità offerte da HuMoR in un framework così versatile come GStreamer sia di grande interesse ed utilità. Il primo passo è stato quello di convertire HuMoR da un applicativo stand-alone in un vero e proprio elemento da utilizzare all'interno di GStreamer. In questo modo diventa possibile utilizzare HuMoR in qualunque contesto (ad esempio utilizzarlo in un qualsiasi riproduttore video basato su GStreamer), oltre ad estenderne facilmente le funzionalità. A questo proposito si è rivelato particolarmente utile costruire un sistema finalizzato a raccogliere rapidamente in modo efficiente e un set di esempi e le corrispondenti features estratte. Inoltre è stato possibile superare alcuni limiti della versione originaria di HuMoR, una su tutte la possibilità di lavorare su video memorizzati su file anziché provenienti direttamente da telecamere in tempo reale. 47 HUMOR COME ELEMENTO DI GSTREAMER Gli elementi disponibili di serie nell’ambiente GStreamer già preconfezionati e pronti per essere inseriti in una pipeline sono molteplici ed assolvono ad una miriade di compiti i più diversi tra loro. All’interno di un framework progettato per garantire l'estendibilità e l’ elaborazione di un qualsiasi tipo di flusso dati ciò potrebbe, tuttavia, apparire abbastanza limitante e, in alcuni casi, riduttivo. Risulta invece lecito aspettarsi la possibilità di introdurre nuovi elementi progettati appositamente per uno specifico tipo di elaborazione non necessariamente previsto e fornito direttamente dal team di sviluppo del progetto generale. Naturalmente questa problematica viene risolta in GStreamer introducendo la possibilità di estendere la gamma di elementi disponibili tramite l'inclusione di plugins, ovvero blocchi di codice caricabili all'interno del framework stesso, solitamente sotto forma di oggetto condiviso o libreria collegata dinamicamente. Di conseguenza la creazione di un nuovo elemento implica il suo incapsulamento all'interno di una struttura predefinita, imposta dallo standard stabilito per la definizione di un generico plugin. Dallo studio della documentazione che accompagna il progetto, ed in particolare dal documento How to write a GStreamer plugin abbiamo appreso le fondamenta per la stesura del codice necessario alla riscrittura di HuMoR come elemento di GStreamer. Abbiamo per prima cosa analizzato quali dovevano essere i necessari pads di input, quindi come garantire il corretto arrivo dei dati in ingresso, previste alcune opzioni di controllo ed infine definito i pads di uscita. 48 DEFINIZIONE DEI PAD DI INGRESSO DELL'ELEMENTO HUMOR Il requisito fondamentale per quanto riguarda l’input del nuovo elemento è quello di accettare un flusso di dati video conformi allo standard utilizzato da HuMoR in modo da elaborarli successivamente esattamente come se venissero passati all'applicazione stand-alone. L’elemento "humor" è stato quindi dotato di un pad di ingresso, il quale è stato configurato in modo da accettare come tipo di dati solamente un flusso generico raw video in rgb ("x-raw-rgb"). Figura 27 Figura 28 In questo modo è stato possibile rendere disponibile all'elemento i dati in ingresso nel corretto formato. 49 FUNZIONAMENTO DELL’ELEMENTO HUMOR DI GSTREAMER Siamo dunque arrivati al nodo centrale, ovvero riuscire a far elaborare i dati in modo del tutto analogo a quanto fa la versione originaria di HuMoR, questa volta però utilizzando l’elemento HuMoR di GStreamer. Il risultato dovrà essere del tutto equivalente: dovremo poter ottenere tutte le informazioni relative agli oggetti rilevati ed in particolare le loro features ed i dati sul tracking. E' a questo punto che si va a realizzare effettivamente il collegamento tra GStreamer e HuMoR: le funzioni di quest’ultimo infatti vengono rese disponibili al plugin attraverso l'integrazione al suo interno di una apposita libreria (libgsthumor.la), che si occuperà di fornire le funzioni offerte da humor direttamente dal codice del plugin. Resta da definire come passare i dati da analizzare risolvendo il problema senza specificare l’input a livello di interfaccia utente, come accade nell’applicazione stand-alone. I dati in ingresso, a prescindere dal tipo di sorgente (videocamere o sorgente diretta di dati su host locale trasferiti tramite appositi plugin), vengono trattati come un flusso video standard ed elaborati all'interno del modulo netcam di HuMoR. Abbiamo quindi definito una nuova funzione che prende come argomento un puntatore alla locazione di memoria contenente i dati video in ingresso e li fornisce al suddetto modulo netcam per l'elaborazione. E' con questa funzione che è possibile, richiamandola dal codice dell'elemento, scambiare dati tra l'elemento stesso e il motore di elaborazione di HuMoR, bypassando i dati forniti dall'interfaccia utente. Questa modifica al modo con cui HuMoR acquisisce le immagini in ingresso richiede però un ulteriore intervento per garantire la correttezza dei dati trasferiti. Bisogna infatti tenere in considerazione che la funzione che recupera e fornisce a HuMoR le immagini da analizzare non viene più richiamata dall'interno di uno 50 stesso applicativo come in precedenza, ma da un plugin, ovvero un’applicazione separata, che utilizza le funzioni di HuMoR rese disponibili da una libreria esterna. Trattandosi a tutti gli effetti di due processi separati, l'esecuzione di uno rimane indipendente dall'altro e questo può portare a problemi di sincronismo nell’accesso alle risorse condivise. E’ quindi possibile che HuMoR importi dati per l'analisi quando ancora questi non siano stati preparati dal plugin o, peggio ancora, quando questi siano in fase di aggiornamento. Analogamente è possibile che il plugin richiami la funzione per aggiornare i dati su HuMoR mentre questi stanno per essere elaborati o addirittura prima che l'elaborazione stessa abbia luogo, causando la perdita di frames nell'analisi. Ci si immagina immediatamente come, in assenza di un sistema di sincronizzazione, sia totalmente non garantita la coerenza di ciò che viene elaborato e di conseguenza l'affidabilità del sistema. Si rende dunque necessaria l'introduzione di un controllo sul flusso di esecuzione dei due processi in modo da rendere mutuamente esclusivo l'accesso alle variabili interessate per lo scambio delle immagini tra il plugin e HuMoR. Tale obiettivo viene raggiunto introducendo due nuove variabili: una variabile di tipo Conditional, per controllare l'esecuzione dei processi ("cond") ed una boolean per impostare e verificare lo stato delle variabili buffer di scambio dati ("imageBufferReady"). Tali variabili vengono utilizzate nel codice in corrispondenza dei punti in cui ha luogo la scrittura o la lettura del buffer delle immagini. Innanzitutto, quando viene richiamata la funzione dal plugin per trasferire i dati su HuMoR, si effettua un lock per consentire la scrittura del buffer senza collisioni; terminato il trasferimento si sblocca l'esecuzione e si imposta a true la imageBufferReady, in modo da segnalare che il buffer è pronto e contiene i dati aggiornati. Nella parte del codice in cui si leggono i dati dal buffer, un ciclo while fa in modo di attendere che la variabile imageBufferReady sia true, bloccando l’esecuzione fino a quando il buffer è aggiornato e contiene i nuovi dati in ingresso. 51 Viene quindi effettuato un lock per consentire la lettura del buffer e viene aggiornata la imageBufferReady a false per indicare che i dati nel buffer sono adesso obsoleti e necessitano di un aggiornamento prima di essere riletti. Si ottiene quindi l'effetto di mettere in pausa opportunamente il plugin o l'applicazione, facendo in modo che l'uno attenda che l'elaborazione dei frame dell'altro sia terminata e che sia possibile scrivere o leggere sul buffer di scambio in maniera controllata, tale da garantire di non leggere più volte uno stesso frame o di non processarne affatto qualcuno. 52 PARAMETRI DELL’ELEMENTO HUMOR L'interfaccia grafica di HuMoR come applicazione permette di impostare una serie vastissima di proprietà adibite a vari tipi di configurazione quali l'impostazione della videocamera da utilizzare, il modello di tracker, l'attivazione di vari tipi di filtro, la visualizzazione del video in ingresso con la segnalazione degli oggetti in movimento e l'evidenziazione delle linee di tracking, per citare solo alcuni tra i più importanti parametri utilizzati. Ovviamente, dato che l'interfaccia grafica di controllo non sarà più disponibile, una volta integrata l'applicazione all'interno di un elemento del framework, si pone il problema di della configurazione dell'elemento humor all’interno di una pipeline. La soluzione ci viene offerta dalla possibilità di definire le proprietà degli elementi di GStreamer, utilizzate per configurare gli elementi direttamente sulla pipeline, semplicemente richiamando il nome della proprietà seguito dal valore che deve essere assegnato ad essa. Supponiamo, ad esempio, di aver previsto una proprietà booleana (chiamiamola view) per attivare la visualizzazione del video in ingresso con le linee del tracking e la segnalazione degli oggetti rilevati mediante la loro circoscrizione con un rettangolo. Per inserire all'interno di una pipeline l'elemento humor con tale proprietà attivata sarà sufficiente utilizzare la seguente sintassi: ... ! humor view=TRUE ! ... L'attivazione di una nuova proprietà di un elemento avviene attraverso direttive richieste dallo standard stabilito per la creazione di un plugin: innanzitutto è necessario specificare in testa al codice le proprietà che faranno parte dell'argomento, definendole nella funzione _class_init(). Nel nostro caso, per attivare la proprietà view, e stato necessario aggiungerla tra gli argomenti utilizzabili, all'inizio del codice: enum { ARG_0, ARG_VIEW, }; 53 In fase di inizializzazione della classe del plugin (gst_humor_class_init ), si è dovuto installare la proprietà, definendone alcune caratteristiche, quali il nome, la descrizione etc. g_object_class_install_property ( gobject_class, ARG_VIEW, g_param_spec_boolean ( "view", "View", "Show output video", FALSE, G_PARAM_READWRITE) ); Infine sono state definite le due funzioni _get_property() e _set_property(), il cui compito consiste rispettivamente nel fornire il valore della proprietà oppure impostarlo. In entrambe le funzioni, le operazioni sulla proprietà vengono gestite dal costrutto switch...case, in corrispondenza in cui l'argomento prop_id assume valore ARG_VIEW. 54 static void gst_humor_set_property ( GObject *object, guint prop_id, const GValue *value, GParamSpec *pspec ) { GstHumor * filter; g_return_if_fail ( GST_IS_HUMOR ( object ) ); filter = GST_HUMOR ( object ); switch ( prop_id ) { case ARG_VIEW: { filter->h_props.view = g_value_get_boolean ( value ); break; } default: { G_OBJECT_WARN_INVALID_PROPERTY_ID ( object, prop_id, pspec ); break; } } if ( filter->netcam ) netcamSetProperties( filter->netcam, &filter->h_props ); } 55 static void gst_humor_get_property ( GObject *object, guint prop_id, GValue *value, GParamSpec *pspec ) { GstHumor * filter; g_return_if_fail ( GST_IS_HUMOR ( object ) ); filter = GST_HUMOR ( object ); switch ( prop_id ) { case ARG_VIEW: { g_value_set_boolean ( value, filter->h_props.view ); break; } default: { G_OBJECT_WARN_INVALID_PROPERTY_ID ( object, prop_id, pspec ); break; } } } La proprietà definita sulla pipeline può essere utilizzata da HuMoR facendo riferimento alla stessa variabile dall'interfaccia dell'applicazione. che veniva in precedenza controllata Questa variabile fa parte del codice di HuMoR ed è accessibile dal plugin in virtù dell'inclusione della libreria libgsthumor.la. 56 DEFINIZIONE DEI PAD DI USCITA DELL'ELEMENTO HUMOR L'ultimo passo da compiere per completare la definizione dell'elemento HuMoR consiste nel definire le uscite che esso deve fornire. I dati di maggiore interesse prodotti dall'elaborazione di HuMoR sono le features geometriche estratte dagli oggetti individuati e quelle cromatiche utili per il tracking. Tali dati sono particolarmente rilevanti essendo le informazioni principali su cui si baseranno le successive fasi di learning e di classificazione. Risulta altresì utile fornire in uscita il flusso video che è stato processato al fine di conservarne una copia nel caso in cui si abbia necessità di riprocessarlo a posteriori su HuMoR, o semplicemente si voglia verificare di persona l'evento. L'elemento humor è stato perciò dotato di due source pads, sul primo dei quali viene semplicemente riversato il flusso video in ingresso; su tale pad il tipo di dati ammesso, analogamente al pad di ingresso, è un generico flusso "x-raw-rgb". Per quanto riguarda l'altro pad, la situazione risulta più complessa: le informazioni riguardanti le features sono presenti in HuMoR sotto forma di array multidimensionali; il problema che si presenta consiste quindi nel trovare un modo per restituire questi dati ad un flusso di uscita su un source pad in maniera efficiente e tenendo ben presente il loro utilizzo finale. In accordo con gli sviluppatori di HuMoR è stato deciso che il formato più adeguato per l'esportazione delle features è un file di testo, formattato in modo da definire un raggruppamento dei dati che rispetti il seguente ordinamento: frame video analizzato, tipo di features ed oggetto analizzato. In corrispondenza di ogni oggetto riportato segue la lista di features che lo riguardano separate da punti e virgola. Con questo formato si rende possibile il parsing a posteriori del file per recuperare le features ed utilizzarle nelle fasi successive di learning e classificazione. Il trasferimento dei dati dagli array al file finale richiede particolare attenzione a due aspetti. In primo luogo bisogna considerare che queste informazioni non dovranno essere inviate direttamente sul file di testo in questione, ma dovranno prima passare 57 attraverso il pad di uscita dell'elemento humor e dovranno essere trattate pertanto come un normale flusso di dati. La ragione di ciò risiede nel fatto che, essendo humor un elemento di GStreamer, è necessario che qualsiasi suo input o output venga gestito in maniera standard, conforme ad un qualsiasi altro elemento, di conseguenza essendo humor un elemento filtro (non un source o un sink), non può che accettare o fornire in uscita dati provenienti o diretti verso un altro pad di un altro elemento della pipeline. La fase finale in cui i dati saranno scritti su un file di testo sarà effettuata da un elemento filesink che scriverà su un file specificato le informazioni che riceve in input. La scelta di imporre questo standard proviene essenzialmente dalla necessità di garantire la scalabilità e la standardizzazione proprie di GStreamer, requisiti essenziali e punti di forza del framework stesso. Il secondo aspetto è in parte collegato al primo, in quanto permette di mantenere ed ampliare le caratteristiche di scalabilità e generalizzazione dell'output dell'elemento. Si consideri infatti il caso in cui, in una successiva versione di HuMoR (si tenga conto che tuttora il progetto è in fase di ampliamento e sviluppo) vengano introdotte nuove features o ulteriori dati di interesse per le analisi successive: se l'elemento si occupasse semplicemente di recuperare i dati dagli array e fornirli in uscita staticamente in un formato predefinito, sarebbe necessario modificare anche la parte del plugin che si occupa della formattazione per includere anche la nuova informazione introdotta. Queste considerazioni hanno indotto a progettare un sistema per impacchettare i dati, ottenuti dagli array delle features, in blocchi di dati strutturati in maniera tale da essere indipendenti dalle features che ne fanno parte. Di conseguenza si è ritenuto opportuno implementare un altro elemento di GStreamer, appositamente adibito alla gestione del flusso dei dati delle features in uscita da HuMoR, in modo da svincolare quest’ultimo dalle features richieste in uscita. 58 Tale elemento, chiamato GSTDataDemuxer, è stato progettato in modo da prendere in ingresso tutto il flusso dei dati informativi in uscita da humor, in un formato stabilito, e restituire su un file di testo solo i dati di interesse, mediante una selezione effettuabile tramite una proprietà dell'elemento. Sul secondo pad di uscita vengono dunque inviati i dati restituiti da una funzione definita su HuMoR che si occupa di recuperare i dati ed impacchettarli opportunamente. 59 UTILIZZO DEL PLUGIN HUMOR Ultimata la progettazione del plugin non rimane che compilarlo ed includerlo nella libreria libgsthumor.la in modo da renderlo visibile ed utilizzabile dall’ambiente GStreamer come un qualunque altro elemento. Esistono due possibilità: la prima è quella di registrare definitivamente il plugin tramite il comando gst-register in modo che venga incluso tra quelli caricati all'avvio da GStreamer. L’alternativa consiste, invece nel caricare il plugin dinamicamente ad ogni avvio di GStreamer attraverso la direttiva --gst-plugin-load="<path_del_plugin>” da includere come argomento del comando gst-launch se vogliamo eseguire la pipeline direttamente da linea di comando o gst-editor se intendiamo utilizzare l’editor visuale. Considerando che il plugin è tuttora in continua fase di sviluppo e messa a punto è stato scelto di utilizzare il secondo metodo, in quanto rende possibile l'utilizzo dell'ultima versione disponibile del plugin ad ogni utilizzo del framework, evitando di rieseguirne la registrazione esplicita ad ogni modifica e ricompilazione. Adesso possiamo quindi includere l'elemento humor all’interno di una qualsiasi pipeline, ma per poterlo davvero utilizzare in pratica è necessario collegare il source pad che fornisce in uscita le features ad un elemento in grado di riconoscere tale flusso e formattarlo in un file di testo, in modo da rendere disponibili tutti i risultati dell'elaborazione. 60 5. L’ELEMENTO GSTDATADEMUXER Lo scopo di questo elemento consiste, come detto in precedenza, nella conversione di un generico flusso di dati in uscita dall'elemento humor, contenente i risultati dell'elaborazione (features di vario tipo ed eventualmente altre informazioni) in dati formattati destinati all'output su file di testo. GSTDatademuxer si occupa inoltre di selezionare quali informazioni andare a trasferire all'uscita. Questa caratteristica permette non solo di scegliere quali features o proprietà previste nel progetto attuale inviare nell'output finale, ma anche di poter includere e gestire eventuali nuove caratteristiche di HuMoR in modo del tutto trasparente. Analogamente al caso dell’elemento HuMoR, è necessario definire un sink pad opportunamente configurato per accettare correttamente i dati in ingresso da processare. Per comprendere a fondo come elaborare correttamente tali informazioni, è opportuno analizzare come i dati vengano prodotti da HuMoR. Il formato con cui i dai vengono forniti in uscita da HuMoR è strutturato in modo da consentire che le informazioni, indipendentemente dalla loro natura o da quante e quali esse siano, vengano impacchettate e inserite in un flusso generico. Ciò implica che la modalità con cui si vanno ad impacchettare le informazioni e la struttura stessa dei dati impacchettati rimangano svincolate dalla loro natura e quantità, bensí consentano di aggiungere o rimuovere al flusso un qualunque dato a prescindere dal suo tipo e dalle sue dimensioni in qualsiasi momento. Tale requisito può essere soddisfatto progettando una struttura dati autoesplicativa, ovvero contenente al suo interno non solo le informazioni da scambiare tra gli elementi, ma anche un overhead di intestazione che permetta di ricostruire a posteriori la struttura stessa del flusso trasferito. In questo modo si rende possibile l'inserimento o l’eliminazione di qualsiasi informazione, essendo la struttura dinamicamente riadattabile alla variazione in virtù delle intestazioni, che vengono scritte sul flusso nel momento stesso in cui i dati vengono impacchettati e sono variabili in dipendenza dei dati stessi. 61 I dati provenienti da humor non sono necessariamente omogenei tra loro e quindi l'elemento GSTDataDemuxer dovrà essere in grado non solo di gestire correttamente una molteplicità di tipi di dati, ma anche di prevedere un meccanismo semplice ed al tempo stesso efficace che consenta di selezionare quali informazioni dovranno essere inviate in output. Nel rispetto di tali prerequisiti, la struttura dati è stata definita innanzitutto stabilendo la presenza di una intestazione contenente informazioni generiche sul pacchetto dati inviato: Figura 29 La prima informazione è la versione dello standard del formato dei dati utilizzato, seguita dal numero di elementi informativi che sono contenuti nel pacchetto. Tali elementi possono pertanto essere presenti in un numero variabile nel pacchetto; essi sono i veri e propri contenitori delle informazioni prodotte da humor. La loro struttura può essere schematizzata come segue: 62 Figura 30 Ogni elemento è costituito da 4 campi, i primi 3 a dimensione fissa, e l'ultimo, invece, a dimensione variabile. Il primo ed il secondo campo contengono due stringhe che rappresentano il nome ed il tipo (intero, stringa, array, etc.) dell'elemento esportato rispettivamente, il terzo un intero che rappresenta la dimensione in bit dei dati contenuti nell'elemento; infine il quarto campo contiene i dati veri e propri dell'elemento: la sua dimensione varia in funzione della quantità dei dati esportati con quell'elemento (tale dimensione è quella indicata nel terzo campo). Si noti la versatilità di tale struttura: il campo elements number ci dice quanti elementi sono contenuti nel pacchetto, di conseguenza risulta facile, scorrendo un elemento per volta, estrarli ad uno ad uno fino ad arrivare alla fine del pacchetto conoscendo esattamente quando fermarsi. Inoltre, avendo a disposizione per ciascun elemento un campo dimension (il terzo, preceduto da due campi a dimensione fissa, quindi inequivocabilmente localizzabile), risulta possibile conoscere immediatamente quanta memoria è stata 63 allocata per il quarto campo variabile dell'elemento, quindi delimitare con esattezza il termine dei dati relativi ad ogni singolo elemento (ed eventualmente accedere direttamente a quello successivo). Le informazioni provenienti da humor vengono impacchettate ciascuna in un elemento, seguendo sempre la stessa sequenza; pertanto su due pacchetti differenti saranno sempre contenute due occorrenze della stessa informazione in due elementi posti alla stessa posizione in ogni pacchetto. In virtù di questa proprietà risulta banale progettare un selettore su GSTDataDemuxer in grado di estrarre le informazioni desiderate, semplicemente facendo in modo che la scelta avvenga in base alla posizione dell'elemento da estrarre. Nel caso in cui venisse aggiunta una nuova struttura di dati da elaborare, sarebbe possibile estrarre l’informazione agendo sulla proprietà select in modo che prelevi i dati di un diverso elemento; ciò può essere fatto anche in fase di esecuzione della pipeline su GStreamer, senza modificare una riga di codice del plugin, rispettando i requisiti di adattabilità e scalabilità visti in precedenza. DEFINIZIONE DEL PAD DI INGRESSO DELL'ELEMENTO GSTDATADEMUXER Il sink pad dell'elemento GSTDataDemuxer è in grado quindi di accettare dati nel formato appena definito e di collegarsi con il source pad dell’elemento humor relativo alle informazioni ottenute dall'elaborazione. I dati così ottenuti vengono copiati in una locazione di memoria in attesa di essere elaborati ed opportunamente estratti dalla struttura pacchettizzata. PARAMETRI DELL’ELEMENTO GSTDATADEMUXER Grazie al tipo di struttura definito è possibile progettare un selettore che permetta di scegliere quali elementi recuperare basandosi sulla loro posizione all'interno del pacchetto, dal momento che possiamo fare affidamento al fatto che la posizione relativa fra gli elementi non varierà nel tempo. 64 Figura 31 Se supponiamo, ad esempio, che le features geometriche degli oggetti sono recuperabili estraendo il quarto elemento del pacchetto e le features cromatiche per il tracking estraendo il quinto, è sufficiente impostare il selettore in modo che recuperi sempre il quarto ed il quinto elemento da ogni pacchetto ricevuto per ottenere le informazioni desiderate. Requisito primario da considerare in fase di progettazione del selettore è che consenta, in caso di variazione dello standard dei pacchetti ricevuti (aggiunta, rimozione o variazione di uno o più elementi), di adattare la selezione al nuovo standard senza necessità di modificare la struttura del selettore stesso o di ricompilare il plugin. Nella soluzione adottata, la scelta degli elementi di interesse, le cui informazioni devono essere trasferite nel file di testo finale, avviene specificando un’unica proprietà intera (select) di GSTDataDemuxer: tale numero viene convertito in binario ed il valore dell’i-esimo bit, partendo dal meno significativo, indicherà se l’iesimo elemento va considerato o meno. Ad esempio un valore di select pari a 6 (1102) selezionerà il secondo ed il terzo elemento ma non il primo quindi per selezionare il quarto ed il quinto soltanto dobbiamo specificare 24 che corrisponde a 11000 in binario. Si noti come il funzionamento di tale sistema, codificando semplicemente la posizione degli elementi da attivare, sia completamente trasparente al variare dello standard dei pacchetti o della modalità con cui le informazioni in esso 65 contenute vengono organizzate: sarà sufficiente prestare attenzione alla nuova posizione degli elementi riadattando conseguentemente l’attivazione delle cifre e estendere o ridurre eventualmente l'ordine di grandezza del numero in questione. Analogamente a quanto fatto per l'elemento humor, è necessario inserire nel codice le opportune direttive e primitive per l'attivazione della proprietà select; inoltre sono state definite funzioni per la conversione in binario del numero immesso e l'estrazione delle informazioni in dipendenza di tale valore. In particolare, la seconda funzione introdotta estrae dal flusso dati in ingresso gli elementi selezionati nel Demuxer, leggendoli dalla struttura dati e passando in output solo quelli selezionati dalla proprietà select. Viene innanzitutto estratto l'header del pacchetto contenente le informazioni sulla versione dello standard del pacchetto ed il numero degli elementi presenti; successivamente ha inizio il parsing del pacchetto elemento per elemento. Vengono estratte le informazioni sul nome, il tipo e la dimensione dei dati presenti nell'elemento, dopodichè, se in base al valore di select, questo elemento deve essere selezionato per l'esportazione, vengono estratti ed inviati in output i dati relativi. Il processo di estrazione si interrompe in corrispondenza della fine del blocco dati dell'elemento (posizione conosciuta dal campo estratto dall'header dell'elemento, contenente la dimensione dei dati). Nel caso in cui l'elemento non risulti invece contrassegnato per l'esportazione i dati vengono ignorati ed il parsing prosegue prendendo in esame il successivo elemento. 66 I PAD DI USCITA DEL PLUGIN GSTDATADEMUXER I dati estratti vanno opportunamente formattati e convertiti in un formato che possa essere trascritto su un fle di testo di uscita da un normale filesink. Ogni blocco informativo contenuto in ciascun elemento viene dunque accodato in una stringa che sarà a sua volta successivamente copiata sul pad di uscita dell'elemento. In virtù della continuità dello streaming dei dati, gli elementi sarebbero esportati in successione uno dopo l'altro, senza alcuna delimitazione che permetta di differenziarli e distinguerne l'appartenenza all'uno od all'altro frame elaborato da humor. Per questo motivo abbiamo aggiunto, in fase di esportazione, un delimitatore che rappresenta l'inizio dei dati relativi ad un particolare frame. Il delimitatore scelto è un semplice timestamp che indica l'ora in cui l'accodamento dell'informazione ha luogo. Un esempio di una stringa così costruita è il seguente: ---Frame 1626211271839548--dove il timestamp rappresenta il tempo in secondi trascorso da una data di riferimento (00:00:00 UTC, January 1, 1970) alla data di sistema corrente. Stabilito questo riferimento, la stringa così creata viene accodata alla stringa di esportazione e seguita dalle stringhe contenenti i dati degli elementi selezionati, tutti appartenenti allo stesso frame cui l'intestazione fa riferimento. Una volta esaurite le informazioni contenute nel pacchetto (che corrispondono all'elaborazione di un frame), la stringa risultante viene inviata al pad di uscita dell'elemento di GStreamer. Tale pad è ovviamente configurato per accettare dati di tipo testuale, in modo da consentire, tramite il collegamento con un elemento filesink, il redirect su un file di testo dell'uscita ottenuta. 67 UTILIZZO DEL PLUGIN GSTDATADEMUXER Per poter utilizzare il plugin GSTDataDemuxer, analogamente a quanto fatto per il plugin humor, è necessario compilarlo ed includerlo nella libreria libgsthumor.la. Per le stesse motivazioni del caso precedente abbiamo scelto di caricare il plugin dinamicamente ad ogni avvio di GStreamer attraverso la direttiva --gst-plugin-load="<path_del_plugin>” da passare ai comandi gst-launch o gst-editor a seconda di voler eseguire la pipeline direttamente da linea di comando o tramite l’editor visuale. 68 6. HUMOR ALL’OPERA IN AMBIENTE GSTREAMER Lo sviluppo dei nuovi plugins humor e gstdatademuxer rendono finalmente possibile la creazione di pipelines in ambinete GStreamer in grado di sfruttare le potenzialità di HuMoR in maniera versatile e soprattutto scalabile. Abbiamo già avuto modo di vedere come, definendo una pipeline, sia possibile controllare, modificare ed analizzare un qualsiasi flusso di dati; di conseguenza abbiamo a disposizione un ambiente del tutto general-purpose che è potenzialmente in grado di fornire soluzioni ad un’ampia gamma di problematiche in diversi ambiti. Nel nostro caso specifico, ciò che serve è uno strumento con il quale elaborare una sequenza video proveniente da una videocamera e passarla al nostro plugin humor che si occuperà di analizzarla ed infine, tramite il plugin gstdatademuxer, estrarre le features geometriche, utili per discriminare il comportamento degli oggetti in movimento rilevati e quelle cromatiche indispensabili per il loro tracking. DEFINIZIONE ED ESECUZIONE DI PIPELINES Esistono diverse modalità tramite le quali è possibile creare ed eseguire una pipeline di GStreamer: la prima avviene direttamente da riga di comando, tramite il comando gst-launch, con cui è possibile specificare la sequenza di elementi da includere ed al tempo stesso lanciarla in esecuzione. Una seconda opzione è quella di utilizzare il comando gst-xmlparse con il quale è possibile leggere ed eseguire un opportuno file xml contenente l'intera struttura della pipeline. Esiste infine il tool gst-editor che, come abbiamo già accennato, permette la creazione di pipelines da interfaccia grafica. L’interfaccia di gst-editor si presenta con una finestra principale che riproduce l’intera area di lavoro in cui andare a costruire “pezzo per pezzo” la nostra pipeline inserendovi gli elementi che servono, i quali possono essere selezionati all’interno di un pannello, l’utility palette, che funge da browser per tutti gli elementi 69 disponibili. L’utility palette permette, oltre alla selezione diretta degli elementi dall’albero organizzato in categorie e sottocategorie di vario livello, di effettuare ricerche full-text per facilitare l’individuazione di un elemento partendo, ad esempio, da una sua determinata caratteristica o da un formato supportato. Sempre all’interno dell’area di lavoro principale è possibile creare le varie interconnessioni fra gli elementi inseriti facendo banalmente drag n’ drop fra gli opportuni pad degli oggetti che intendiamo collegare. Un’altra caratteristica di gst-editor è quella di permettere di salvare o caricare una pipeline in formato xml, svolgendo quindi in modalità grafica il lavoro di gstxmlparse. Una volta creata la pipeline definitiva è infine possibile mandarla in esecuzione cliccando sul pulsante play. Nel nostro lavoro è stato necessario utilizzare sia l'editor grafico che il launcher da riga di comando, date le loro peculiarità entrambi utili e talvolta complementari per la definizione, la prova, la modifica, il salvataggio e l'utilizzo finale della pipeline. Da un lato infatti gst-editor risulta comodissimo per il facile reperimento degli elementi desiderati, il linking dei pad (si è immediatamente in grado di verificare se ci sono, ad esempio, problemi di compatibilità tra i dati supportati tra due pad grazie al controllo immediato sulla negoziazione), il salvataggio ed un primo testing; dall’altro gst-launch risulta indispensabile in quanto permette di creare scripts parametrizzabili che richiamano determinate pipelines, oltre ad a fornire un’avanzata modalità di testing. Come abbiamo anticipato, la sintassi per definire ed eseguire una pipeline tramite il comando gst-launch è estremamente semplice ed immediata: è sufficiente elencare la sequenza degli oggetti desiderati, separandoli con un punto esclamativo, nell'ordine in cui si vuole che il flusso dei dati abbia luogo. Per modificare il valore di una proprietà di un elemento è sufficiente aggiungere il nome della proprietà e assegnargli il valore desiderato; ad esempio 70 filesrc location=start.avi assegna alla proprietà location dell'elemento permettendo, di fatto di leggere il file specificato. filesrc il valore start.avi, Alla luce di quanto detto abbiamo definito diverse pipelines che si occupano di compiti specifici come semplificare la messa a punto dell’impianto di sorveglianza, acquisire i filmati video in modo da preparare il set di esempi su cui effettuare l’addestramento (learning set) e finalmente utilizzare i plugins plugins humor e gstdatademuxer per estrarre le features ed effettuare il vero e proprio riconoscimento di scene. ESTRAZIONE DELLE FEATURES: LO SCRIPT avi2hum Focalizziamo l’attenzione sulla pipeline che è il cuore di tutto il sistema, ovvero quella che estrae le features dai filmati, basata interamente sui plugin che abbiamo sviluppato. Per fare questo abbiamo realizzato uno script (avi2hum) che prende in ingresso un filmato del learning set e ne estrae le features che lo caratterizzano, generando un file di testo opportunamente formattato. Vediamone il codice: #!/bin/sh if [ $# -ne 3 ] ; then echo "avi2hum: Errore negli argomenti" echo "Sintassi: avi2hum ESEMPIO FILE_ISTANZA SUFFISSO" exit 0 fi VIDEOFILE=$2 SRC_PATH="/home/gas/Tesi/svn/humor/trunk/humor/debug/src" GSTLIBS_PATH=$SRC_PATH"/gst-plugin" LEARNINGSET_PATH="/home/gas/Tesi/esempi" 71 PIPELINE= "filesrc location=$LEARNINGSET_PATH/$1/video/$2 ! avidemux ! ffcolorspace ! _ humor name=hum view=TRUE hum.src1 ! DataDemuxer select=7 ! _ _ _ Filesink location = $LEARNINGSET_PATH/$1/features/ _ ${VIDEOFILE%.avi}-$3.txt" export LD_LIBRARY_PATH=$SRC_PATH/LibHumor/.libs/:$SRC_PATH/Thread/.libs/ gst-launch-0.8 --gst-debug-level=1 _ --gst-plugin-load=$GSTLIBS_PATH/libgsthumor.la --gst-plugin-load=$GSTLIBS_PATH/libgsturlsrc.la _ _ --gst-plugin-load=$GSTLIBS_PATH/libgstDataDemuxer.la _ $PIPELINE Come primo argomento viene passato il nome della classe di esempi (tipicamente il nome descrittivo dell’azione da riconoscere) dalla quale recuperare il file video della specifica istanza da elaborare, specificata come secondo argomento, dal momento che per ogni azione saranno stati realizzati più filmati di esempio (istanze della stessa azione appunto), sui cui fare apprendimento. Il terzo parametro, invece, verrà utilizzato per aggiungere un suffisso al nome del file delle features ottenuto dall'elaborazione della pipeline, in modo da poter distinguere la sessione di analisi effettuata da HuMoR. Questa funzionalità è stata introdotta per consentire di effettuare una pluralità di analisi, ottenendo features diverse a partire stesso filmato, a seconda delle opzioni impostate di volta in volta. Sarà così possibile effettuare il tuning dei parametri utilizzati, oppure il confronto tra diversi algoritmi di tracking e di segmentazione, nonché ogni altra modifica alla configurazione di HuMoR che vada ad influire sul risultato dell'analisi, producendo un risultato differente nell'estrazione delle features. 72 Grazie a questa possibilità potremo addirittura testare una qualunque futura estensione di HuMoR, misurandone l'efficacia rispetto alle precedenti versioni o consentendo la comparazione con sistemi già in uso tramite il semplice confronto degli effetti del riconoscimento di una stessa scena esatta, ma con differenti features estratte distinguibili dal suffisso impostato di volta in volta. Tornando all’analisi del codice e sorvolando i dettagli relativi al controllo sulla sintassi e al settaggio di alcuni variabili relative ai path in cui reperire i dati utili, arriviamo alla definizione della pipeline vera e propria. Per fissare le idee vediamone prima la rappresentazione grafica realizzata con gst-editor: Figura 32 Un primo aspetto degno di nota è costituito dal fatto che, proprio grazie all’approccio basato su GStreamer, è stato possibile superare il limite della versione originaria di HuMoR, secondo cui era possibile ricevere in ingresso esclusivamente filmati provenienti da telecamere, il che imponeva un impiego unicamente “live” del sistema. Nella nuova versione, invece, il video da processare (sia in fase di training che di test o riconoscimento) può essere anche un file. Questa modifica strutturale del progetto iniziale, ci è stata utile in principio in fase di debug in quanto ci ha permesso di poter lavorare più volte con esattamente gli stessi dati e quindi di controllare la coerenza dei risultati ottenuti. 73 Al tempo stesso, però, si è rivelata molto interessante per il lavoro finito dal momento che permette di effettuare la registrazione delle scene su cui fare apprendimento una volta per tutte, svincolando questa fase da quella di tuning dei parametri da usare, la quale può dunque venire eseguita separatamente dal training e soprattutto non necessariamente nella sede da sorvegliare. Nella pipeline questo aspetto è evidenziato dall’impiego di un filesrc come elemento iniziale, il quale permette di aprire un file in lettura e trasferire il suo contenuto in un flusso di elaborazione di GStreamer. La proprietà location indica il percorso del filesystem da cui recuperare il file. Nel nostro caso, volendo processare il file che rappresenta una certa istanza dell’azione in esame, dovremo accedere all'interno del learning set, più precisamente nella sottodirectory video dell’ azione specificata come primo argomento dello script, quindi aprire il file il cui nome corrisponde al valore passato come secondo parametro. L’oggetto successivo nella pipeline è il demuxer avidemux che permette di processare un video avi non compresso (il formato con cui i filmati vengono salvati nel learning set). A questo punto è necessario convertire adeguatamente lo spazio di colori del flusso video tramite ffcolorspace, in modo da ottenere dei dati video standard compatibili con il pad di ingresso del prossimo elemento: humor. Il plugin humor effettua la vera e propria analisi del filmato e ne estrae le features, le quali vengono indirizzate al source pad relativo e quindi fornite al plugin DataDemuxer. La proprietà view permette, se impostata a TRUE, di visualizzare il video processato evidenziando gli oggetti in movimento e la corrispondente traccia di tracking, oltre alla finestra che evidenzia i pixel differenti rilevati tra il frame corrente e lo sfondo di riferimento. 74 Il plugin DataDemuxer si occupa invece del filtraggio e della formattazione delle features estratte secondo il valore della proprietà select. Nel nostro caso abbiamo specificato 7, ovvero 1112 e quindi tutte e 3 le informazioni che arrivano in ingresso da humor (features geometriche, cromatiche ed il numero dei pixel cambiati che ci è servito per stabilire la soglia da superare) verranno inviate in output per essere infine salvate su file tramite l’elemento filesink. Analogamente a filesrc, la proprietà location di un filesink specifica il percorso su cui il file sarà scritto. In questo caso la destinazione sarà ubicata sempre all'interno del learning set nella sottodirectory relativa alla stessa azione specificata come primo parametro ma, a differenza del video in origine, il file di testo finale verrà salvato nella sottocartella features. Il nome del file sarà completato con il suffisso specificato come terzo argomento. Completata la definizione della pipeline lo script avi2hum prosegue con l’esportazione della variabile di sistema LD_LIBRARY_PATH, che permette di poter caricare dinamicamente i plugin aggiunti a GStreamer. Infine viene invocato il comando gst-launch che manda in esecuzione la pipeline appena creata dopo aver impostato il livello di debug e caricato i moduli necessari a per riconoscere i plugin aggiunti. Nelle figure che seguono (Figura 33 - Figura 36) vengono riportati, a titolo di esempio, alcuni fotogrammi significativi dell’elaborazione di un filmato in cui una persona prende un ombrello inizialmente appoggiato alla parete. Precisiamo subito che la qualità delle immagini risulta bassa a causa dei filtri applicati nel preprocessing che mirano a ridurne il rumore. Possiamo notare inoltre il box blu che identifica la persona in movimento e la corrispondente linea verde del tracking. Si osservi come la posizione iniziale dell’ombrello venga successivamente identificata come una zona in movimento e segnalata con il relativo box. L’oggetto che scompare determina, infatti, una differenza rispetto al background che viene immediatamente rilevata finché, trascorso un necessario intervallo di 75 tempo, il sistema aggiornerà nuovamente lo sfondo aggiungendo al set di sfondi possibili la nuova versione senza l’oggetto in questione. Si veda a questo proposito il paragrafo “Stima del Background” pag. 9. Figura 33 Figura 34 Figura 35 Figura 36 Una variante di avi2hum, set2hum, permette di analizzare direttamente, con un solo comando, tutte le istanze di esempi video relative ad una stessa azione, automatizzando l’estrazione delle features da un intero learning set. 76 ADDESTRAMENTO E RICONOSCIMENTO DI SCENE Dal momento che sia le attività di addestramento del sistema che quella di riconoscimento delle azioni erano implementate nella versione originale di HuMoR, è stato del tutto naturale integrare queste stesse prerogative nel plugin humor. La soluzione adottata è stata quella di definire opportune proprietà dell’elemento humor, in base alle quali decidere se attivare o sia il training su di un learning set che il test vero e proprio e quindi il riconoscimento. In definitiva i parametri che nella versione originale venivano attivati mediante i controlli disponibili attraverso l’interfaccia grafica, vengono ora modificati in base al valore delle nuove proprietà (train, hmm e act) di cui abbiamo dotato il plugin. La prima serve ad attivare l’addestramento sull’esempio passato, la seconda attiva la modalità riconoscimento tramite gli HMM ed infine l’ultima assegna un nome all’azione in esame e pertanto viene settata con il nome descrittivo dell’azione assegnato durante lo costruzione del learning-set. Sulla base dello script avi2hum abbiamo quindi creato la sua naturale evoluzione avi2humTrain, che non fa altro che impostare in maniera opportuna tali proprietà. Una volta effettuato il training su tutte le azioni che intendiamo riconoscere possiamo passare al riconoscimento impostando a 1 la proprietà HMM_ACTIVATION di avi2humTrain e passando al sistema un il filmato di una sequenza video mai vista prima. Verrà quindi lanciata una pipeline di GStreamer che processa il video in ingresso tramite HuMoR, attivando il modulo che si occupa di individuare un’ azione tra quelle apprese che, con maggiore probabilità, approssima quella osservata. Come output verrà restituito il modello che più si avvicina al video processato e con quale probabilità tale modello rappresenta davvero l'azione compiuta. 77 7. STATO DELL’ARTE E SVILUPPI FUTURI IL PROGETTO HUMOR2 Come abbiamo accennato, HuMoR è un progetto tuttora in continua evoluzione e la sua integrazione in GStreamer è senz’altro un aspetto fondamentale per lo sviluppo e il futuro dell’intero sistema. Al momento in cui scriviamo è già partito il progetto HuMoR2 che prevede di estendere la modularità del predecessore realizzando le varie componenti interne sotto forma di altrettanti plugins di GStreamer, in particolare vengono studiate le modalità di separazione del modulo relativo al tracking, ma anche la fase di preprocessing o la vera e propria estrazione di features potrebbero venire sganciate dal progetto principale, studiate nel dettaglio e quindi implementate a vari livelli di ottimizzazione con il supporto di competenze diverse. Già con l’introduzione del plugin GSTDataDemuxer l’intenzione manifestata era proprio quella di dirigere gli sforzi in direzione di un frazionamento delle varie funzioni. Senza dubbio questa ulteriore suddivisione dei compiti e la conseguente specializzazione che ne deriverà, non potrà che apportare benefici sia in termini di manutenibilità del progetto che di capacità di adattamento a contesti diversi, oltre a consentire di focalizzare gli sforzi sugli elementi che possono avere necessità di essere migliorati in termini di efficienza o di funzionalità. SCALABILITÀ AD ARCHITETTURE Può essere interessante analizzare la scalabilità dell’intero sistema, sia dal punto di vista dell’hardware che del software stesso, all’aumentare delle dimensioni del problema, ovvero estendendo il numero di locali da controllare, quindi di telecamere anche diverse tra loro e interconnesse tramite protocolli differenti (ethernet, USB, wireless…). A questo proposito è stato svolto uno studio preliminare [13] che dimostra come le applicazioni di sorveglianza e monitoraggio remoto siano sempre più efficaci, 78 considerando lo scopo dell'applicazione ed i requisiti minimi in termini di costi, scalabilità e flessibilità. Vengono esaminate dapprima le componenti hardware di base di un sistema video di rete, ovvero telecamere di rete, video server ed integrazione con eventuali sistemi analogici preesistenti, per arrivare gradualmente a delineare l'intera struttura di un sistema di videosorveglianza integrato, analizzando gli elementi fondamentali che devono essere tenuti in considerazione nello scegliere le telecamere da installare come risoluzione, tipo di sensore, sensibilità alla luce etc. Un altro punto toccato riguarda lo studio dei vari formati di compressione, tenendo conto di aspetti quali occupazione di banda durante le trasmissioni, consumo di risorse di calcolo per l'introduzione dell'algoritmo di compressione, spazio occupato sui dispositivi di storage. A proposito di sistemi automatici per l’interpretazione di scene, viene inoltre analizzato come l'introduzione di algoritmi intelligenti influenzi le prestazioni dell'intero sistema di videosorveglianza. In particolare viene valutata la criticità delle condizioni di carico in cui può trovarsi la rete al crescere delle dimensioni del sistema stesso, in relazione all’occupazione delle risorse di calcolo necessarie per la compressione, il trasferimento e l’indicizzazione dei dati. CONTESTI APPLICATIVI Per quanto riguarda i possibili campi di applicazione esistono già sperimentazioni di varianti di HuMoR specializzate nel conteggio di persone e più in generale del controllo di attraversamento di varchi, in cui è il tracking l’elemento cruciale. Tra le situazioni in cui il focus va invece a cadere sull’analisi e il riconoscimento di comportamenti umani e quindi della postura, possono rientrare i vari contesti di videosorveglianza: si pensi ad esempio ad un sistema centralizzato in grado di poter filtrare le immagini provenienti dall’interno di una banca, sulla base di un addestramento fatto per riconoscere situazioni critiche come una persona che punta una pistola oppure che scavalca un bancone o che entra in una zona riservata. 79 In questi casi l’idea è quella di attivare automaticamente un controllo supervisionato da parte di un umano al quale però vengono passate solamente situazioni rilevate come critiche dal sistema, evitando quindi di inondare di immagini inutili (perché non pericolose) la centrale operativa. Altre applicazioni più originali, ma proprio per questo forse maggiormente distanti dalle attuali possibilità, potrebbero essere quelle in cui si vuole valutare in maniera automatica il movimento umano, ad esempio di un atleta in una gara di tuffi. Si potrebbe pensare di fare apprendimento da una grande quantità di filmati registrati ed in particolare sulle sequenze che sono state rilevate dai giudici di gara come errate, fornendo anche spezzoni di esempi ben eseguiti, in modo da addestrare il sistema a riconoscere gli errori e, in ultima analisi, a proporre una sua valutazione. Ovviamente le applicazioni possibili potrebbero essere molte altre e questo studio vuole semplicemente essere un punto di partenza, ma soprattutto una presa di coscienza dei limiti e delle attuali possibilità di un sistema automatico di riconoscimento di scene. 80 APPENDICE - SCRIPTS USATI In questa appendice vengono descritti i vari scripts sviluppati per eseguire particolari pipelines di GStreamer, riportando per ognuno una breve descrizione, la sintassi, un esempio di utilizzo ed infine il codice sorgente. Molti di essi fanno riferimento allo script xplug, che serve per prelevare le immagini dalla telecamera e metterle a disposizione su localhost: tipicamente viene lanciato prima di aprite la pipeline e viene richiuso alla fine. 81 FOCUS Focus è un semplice visualizzatore dei video provenienti da una videocamera di rete ed è utile per verificare che l'inquadratura comprenda l'area desiderata e per la corretta messa a fuoco dell'obiettivo. Sintassi: focus Esempio: focus Non sono previsti parametri di esecuzione. Codice Sorgente #!/bin/sh SCRIPTS_PATH="/home/gas/Tesi/scripts" GSTLIBS_PATH="/home/gas/Tesi/svn/humor/trunk/humor/debug/src/gstplugin" PIPELINE="urlsrc url=http://localhost:8000/IMAGE.JPG ! jpegdec ! ffmpegcolorspace ! ximagesink" sh $SCRIPTS_PATH/xpluglaunch.sh & gst-launch-0.8 --gst-plugin-load=$GSTLIBS_PATH/libgsturlsrc.la $PIPELINE ps xww | grep "xplug" | cut -c1-5 | xargs -i kill {} 2>/dev/null 82 CAM2AVI Cam2avi viene usato in fase di creazione del learning-set, in particolare nella raccolta delle varie istanze di esempio delle azioni da riconoscere. In questa fase i filmati devono essere organizzati secondo una struttura ordinata e facilmente riutilizzabile da HuMoR per l'estrazione delle features, automatizzando il più possibile la successione delle riprese video. Sintassi: cam2avi SCENA ISTANZA Il primo argomento richiesto sarà utilizzato come nome da assegnare alla scena da riconoscere, mentre il secondo corrisponderà all'istanza ripresa dalla specifica esecuzione dello script e quindi sarà, tipicamente, il contatore delle istanze riprese di una stessa scena. Esempio: cam2avi intrusione 01 Codice Sorgente #!/bin/sh if [ $# -ne 2 ] ; then echo "cam2avi: Errore negli argomenti" echo "Sintassi: cam2avi ESEMPIO ISTANZA" exit 0 fi SCRIPTS_PATH="/home/gas/Tesi/scripts" GSTLIBS_PATH="/home/gas/Tesi/svn/humor/trunk/humor/debug/src/gstplugin" LEARNINGSET_PATH="/home/gas/Tesi/esempi" PIPELINE="urlsrc url=http://localhost:8000/IMAGE.JPG ! jpegdec ! videorate ! video/x-raw-yuv,framerate=25.0 ! avimux ! filesink location=$LEARNINGSET_PATH/$1/video/$2.avi" sh $SCRIPTS_PATH/xpluglaunch_silent.sh >/dev/null & mkdir $LEARNINGSET_PATH/$1 mkdir $LEARNINGSET_PATH/$1/features mkdir $LEARNINGSET_PATH/$1/video gst-launch-0.8 --gst-plugin-load=$GSTLIBS_PATH/libgsturlsrc.la $PIPELINE ps xww | grep "xplug" | cut -c1-5 | xargs -i kill {} 2>/dev/null 83 Per ogni scena viene creata una directory dedicata all’interno del learning-set in cui organizzare i dati. Le varie istanze della scena verranno salvate nella sottodirectory video mentre dentro a features verranno successivamente salvati i dati prodotti da humor. 84 AVI2HUM Come abbiamo avuto modo di vedere approfonditamente nel capitolo 6 - HuMoR all’opera in ambiente GStreamer, avi2hum permette di estrarre le features da un singolo video specificato in ingresso salvandole nella directory predisposta in precedenza da cam2avi. Sintassi: avi2hum SCENA FILE_ISTANZA SUFFISSO Il primo parametro è il nome descrittivo della scena, il secondo specifica la particolare istanza da analizzare (tipicamente il numero progressivo usato), mentre l’ultimo permette di distinguere i risultati ottenuti nel caso in cui venga ripetuto il processo di estrazione di features di uno stesso filmato, eventualmente con una diversa configurazione di humor. Esempio: avi2hum intrusione 01 00 Codice Sorgente #!/bin/sh if [ $# -ne 3 ] ; then echo "avi2hum: Errore negli argomenti" echo "Sintassi: avi2hum ESEMPIO FILE_ISTANZA SUFFISSO" exit 0 fi VIDEOFILE=$2 SRC_PATH="/home/gas/Tesi/svn/humor/trunk/humor/debug/src" GSTLIBS_PATH=$SRC_PATH"/gst-plugin" LEARNINGSET_PATH="/home/gas/Tesi/esempi" PIPELINE="filesrc location=$LEARNINGSET_PATH/$1/video/$2 ! avidemux ! ffcolorspace ! humor name=hum view=TRUE hum.src1 ! DataDemuxer select=7 ! filesink location=$LEARNINGSET_PATH/$1/features/${VIDEOFILE%.avi}-$3.txt" 85 export LD_LIBRARY_PATH=$SRC_PATH/LibHumor/.libs/:$SRC_PATH/Thread/.libs/ gst-launch-0.8 --gst-debug-level=1 --gst-pluginload=$GSTLIBS_PATH/libgsthumor.la --gst-pluginload=$GSTLIBS_PATH/libgsturlsrc.la --gst-pluginload=$GSTLIBS_PATH/libgstDataDemuxer.la $PIPELINE Si noti la presenza all’interno della pipeline, degli elementi humor e datademuxer, oltre al filesink che permette di salvare le features su file. 86 SET2HUM Set2hum è stato creato in modo da eseguire l'estrazione delle features su tutte le istanze relative ad una stessa scena con un unico comando. E’ inoltre prevista la possibilità di processare più di una scena. Va comunque specificato il suffisso assegnato in fase di estrazione in modo da processare video acquisiti nelle stesse condizioni. In sostanza si tratta di una ripetuta esecuzione automatica di avi2hum. Sintassi: set2hum SUFFISSO SCENA-1 [|SCENA-2 | ... | SCENA-N] Vengono specificati per primo il parametro suffisso, che è lo stesso per tutte le scene, e quindi i nomi descrittivi delle azioni che vogliamo processare. Tali nomi devono corrispondere a quelli specificati in cam2avi. Esempio: set2hum 00 intrusione passaggio Codice Sorgente #!/bin/sh LEARNINGSET_PATH="/home/gas/Tesi/esempi" SCRIPTS_PATH="/home/gas/Tesi/scripts" if [ $# -le 1 ] ; then echo "set2hum: Errore negli argomenti." echo "Sintassi: set2hum SUFFISSO ESEMPIO1 [| ESEMPIO2 ... | ESEMPION]" exit 0 fi SUFFEAT=$1; shift for ESEMPIO in $* do cd $LEARNINGSET_PATH/${ESEMPIO}/video for ISTANZA in *; do $SCRIPTS_PATH/avi2hum ${ESEMPIO} $ISTANZA $SUFFEAT done done Si notino i cicli per eseguire avi2hum su tutte le istanze con un certo suffisso di ogni azione specificata. 87 AVI2HUMTRAIN Partendo dallo script avi2hum, che si occupava di processare un filmato per estrarne le features, si è costruito avi2humTrain, naturale evoluzione del precedente, che consente di attivare le modalità di addestramento e di riconoscimento di humor. (v. cap. 6 - HuMoR all’opera in ambiente GStreamer ) Sintassi: avi2humTrain SCENA ISTANZA SUFFISSO TRAIN HMM I parametri specificano, nell’ordine, la scena da verificare, il numero dell’istanza, il suffisso e quindi i parametri relativi al training (attivando l’addestramento sull’esempio passato) o al testing (avviando la modalità di riconoscimento tramite HMM). Esempio di train: avi2humTrain intrusione 01.avi 00 1 0 Esempio di riconoscimento: avi2humTrain intrusione 01.avi 00 0 1 Codice Sorgente #!/bin/bash if [ $# -lt 5 ] ; then echo "avi2humtrain: Errore negli argomenti" echo "Sintassi: avi2humtrain ESEMPIO FILE_ISTANZA SUFFISSO TRAIN_ACTIVATION HMM_ACTIVATION" exit 0 fi VIDEOFILE=$2 SRC_PATH="/home/gas/Tesi/git/HuMoR/humor/debug/src" GSTLIBS_PATH=$SRC_PATH"/gst-plugin" LEARNINGSET_PATH="/home/gas/Tesi/esempi" PIPELINE="filesrc location=$LEARNINGSET_PATH/$1/video/$2 ! avidemux ! ffcolorspace ! humor name=hum view=TRUE train=$4 hmm=$5" if [ $4 -eq 1 ] ; then PIPELINE=$PIPELINE" act=$1$2" fi export LD_LIBRARY_PATH=$SRC_PATH/LibHumor/.libs/:$SRC_PATH/Thread/.libs/ gst-launch-0.8 --gst-debug-level=1 --gst-pluginload=$GSTLIBS_PATH/libgsthumor.la --gst-pluginload=$GSTLIBS_PATH/libgsturlsrc.la --gst-pluginload=$GSTLIBS_PATH/libgstDataDemuxer.la $PIPELINE 88 BIBLIOGRAFIA [1] Stuart J. Russell, Peter Norvig: Intelligenza Artificiale, Prentice-Hall, [2] D. Comaniciu, P. Meer: Mean Shift: A Robust Approach toward Feature [3] Vance Faber: Clustering and the Continuous k-Means Algorithm, Los Alamos [4] G. Gordon, T. Darrell, M. Harville, J. Woodfill: Background estimation and Englewood Cliffs 1995. Space Analysis, IEEE Trans. Pattern Analysis Machine Intell., 2002. Science , 1994 removal based on range and color, Proceedings of the IEEE Computer Society Conference on Computer Vision and Pattern Recognition, 1999. [5] Teuvo Kohonen: The [6] Ming-Kuei Hu: Visual Pattern Recognition by Moment Invariants, IRE [7] Lawrence R. Rabiner: A Tutorial on Markov Models and Selected [8] Gilles Council,1990. Self-Organizing Map, IEEE Neural Networks Transactions on Information Theory, 1962. Applications in Speech Recognition, Proceedings of the IEEE, 1989. Labonté: Displacement A SOM Neural Network That Reveals Continuos Fields, The 1998 IEEE International Joint Conference on Neural Networks Proceedings, 1998. [9] E. R. Davies: Machine Vision: Theory, Algorithms, Practicalities, Academic [10] Vincenzo di Massa: Vincenzo di Massa: Rilievo di Features da Sequenze di [11] [12] Press, London 1997. Immagini ai Fini dell'Interpretazione Automatica di Scene, Tesi di Laurea - Università di Siena. Innocenzo Russo: Modelli di Apprendimento Markoviani per l'Interpretazione Automatica di Scene, Tesi di Laurea - Università di Siena. Andrea Paolessi: Progettazione di un sistema di videosorveglianza basato sull'interpretazione automatica di scene: Integrazione del software HuMoR come elemento di GStreamer, Tesi di Laurea - Università di Siena. 89 [13] [14] [15] Gianluca Mazzei: Progettazione di un sistema di videosorveglianza basato sull'interpretazione automatica di scene: Struttura e dispositivi, Tesi di Laurea - Università di Siena. Wim Taymans, Steve Baker, Andy Wingo, Ronald S. Bultje, Stefan Kost: GStreamer Application Development http://gstreamer.freedesktop.org/ Manual Wim Richard John Boulton, Erik Walthinsen, Steve Baker, Leif Johnson, Ronald S. Bultje, Stefan Kost: GStreamer Plugin Writer's Guide (0.10.11.1), http://gstreamer.freedesktop.org/ WEBOGRAFIA [16] HuMoRweb: il wiki dedicato a HuMoR [17] Gstreamer Home Page: [18] [19] (0.10.11.1), http://www.dii.unisi.it/cgi-bin/twiki/view/HuMoRweb/WebHome http://gstreamer.freedesktop.org/ cplusplus.com - The C++ Resources Network http://www.cplusplus.com/ LTI-Lib Home Page: http://ltilib.sourceforge.net/ [20] Canonical Ltd Ubuntu, Linux for human beings [21] KDE.org, K Desktop Environment [22] KDevelop http://www.ubuntu.com/ http://www.kde.org http://www.kdevelop.org 90
© Copyright 2024 Paperzz