Volpini Stefano - Università degli Studi di Siena

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