Un framework modulare per lo sviluppo di applicazioni di Computer

Transcript

Un framework modulare per lo sviluppo di applicazioni di Computer
Università degli Studi di Siena
Facoltà di Ingegneria
Corso di Laurea in
Ingegneria Informatica
Un framework modulare per lo
sviluppo di applicazioni di Computer
Vision: videosorveglianza e
interazione uomo-macchina
Tesi di Laurea di
Yusef Maali
21 Luglio 2008
Relatori:
Prof. Marco Gori
Ph.D Vincenzo Di Massa
Anno Accademico 2007/2008
Indice
Introduzione
ii
1 Rilevazione del movimento
1.1 Motion Detection . . . . . . . . . . . . . . . . . . . . . . . . .
1.2 Object Tracking . . . . . . . . . . . . . . . . . . . . . . . . . .
1
4
8
2 Costruire un framework di sperimentazione
2.1 Semplicità . . . . . . . . . . . . . . . . . . .
2.1.1 Interface Plugin . . . . . . . . . . . .
2.1.2 Component Plugin . . . . . . . . . .
2.1.3 HuMoR Plugin . . . . . . . . . . . .
2.2 Modularità . . . . . . . . . . . . . . . . . .
2.2.1 HuMoRCore Plugin . . . . . . . . . .
2.2.2 DataConsumer Plugin . . . . . . . .
2.3 Efficienza . . . . . . . . . . . . . . . . . . .
3 Esemplificazioni dell’utilizzo di HuMoR
3.1 Rimozione di oggetti da una scena . . . .
3.2 Tracciamento di oggetti in movimento . .
3.3 Rilevazione di percorsi . . . . . . . . . .
3.4 Interfaccia di controllo per giochi . . . .
3.5 Un Avatar: LIA . . . . . . . . . . . . . .
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
.
12
14
15
16
17
18
18
19
20
.
.
.
.
.
22
22
22
22
22
22
Conclusioni
23
Bibliografia
26
Introduzione
Un problema che da sempre sfida l’Intelligenza Artificiale è comprendere la semantica di una immagine. Se una macchina riuscisse a capire cosa
l’uomo vede, permetterebbe di aprire una serie di scenari impensabili. Basti
pensare all’interazione uomo-macchina: non si avrebbe più la necessità di
limitare le possibili azioni a contesti scelti in fase progettuale con meticolosa attenzione, ma si potrebbe rendere la macchina “libera” di interpretare
con grande precisione cosa accade nell’ambiente circostante e permetterle di
decidere autonomamente cosa è meglio fare. Molti film cinematografici ipotizzano ormai da tempo questa realtà e sfortunatamente (o fortunatamente? )
ne siamo ben lontani, a causa anche delle difficoltà riscontrate in altri settori
dell’Intelligenza Artificiale. L’interazione uomo-macchina è uno di quei task
che richiede il massimo sforzo in termini teorici e al momento attuale manca
parte della tecnologia necessaria per ottenere un tipo di interazione simile a
quello uomo-uomo.
Con HuMoR1 si è cercato di dare un piccolo contributo in questo senso, trovando il modo più efficiente per estrapolare la semantica da flussi di
immagini, generalmente provenienti da telecamere. Il target preferenziale di
HuMoR è inizialmente stato la videosorveglianza, in quanto estrarre concetti
quali “azione lecita”, “azione non lecita” o “evento anomalo” da una ripresa
video aggiunge una notevole quantità di informazioni semantiche fondamentali nel decidere se lanciare un allarme sonoro, se avvertire la sorveglianza o
semplicemente se memorizzare la parte di filmato interessata dall’evento.
Nella sua prima versione, HuMoR implementava interessanti concetti di
Intelligenza Artificiale applicata alla Computer Vision che lo rendevano capa1
Human Motion Recognizer, il software prodotto come progetto di questa tesi.
INDICE
iii
ce di riconoscere sequenze di azioni e catalogarle in un insieme di eventi noti.
Era quindi capace di discernere da azioni proibite, come rubare un oggetto,
da azioni lecite, come spostare un oggetto, raggiungendo un buon livello di
affidabilità grazie all’impiego di tecniche consolidate come K-Means e reti
di Kohonen. Su questa base si inserisce il mio contributo svoltosi durante
il progetto di tesi, che ha riguardato principalmente la ristrutturazione di
HuMoR e che lo ha portato alla sua seconda versione stabile. L’esigenza di
re-ingegnerizzazione interna è nata a causa della sua struttura monolitica 2 ,
che rendeva difficile, spesso impossibile, introdurre miglioramenti significativi. È stata quindi fatta un’attenta pianificazione rivolta alla ricerca di una
modalità che consentisse di organizzare i vari concetti in classi C++, rispettando fortemente il paradigma della programmazione ad oggetti (OOP) e
preservando concetti quali semplicità, modularità ed efficienza. Il risultato
è stato la nascita di un nuovo sistema, non più esclusivamente dedicato alla
videosorveglianza, ma utilizzabile in qualsiasi ambito della Computer Vision,
dalla sperimentazione ai sistemi di produzione. Grazie all’introduzione del
concetto di plugin3 è ora possibile cambiare le componenti per la rilevazione
del movimento, per il tracciamento dello stesso e per tutte le funzionalità
di alto livello che aggiungono informazioni di tipo semantico al flusso video.
Sono stati creati, ad esempio, dei plugin per la rilevazione di oggetti aggiunti
o rimossi dalla scena, per la rilevazione del movimento avvenuto entro un
certo percorso, per il conteggio di oggetti transitanti lungo la scena (con la
possibilità di vincolare anche la direzione del transito), ecc. . .
L’esperienza maturata durante il lavoro svolto per HuMoR ha permesso
di realizzare inoltre qualcosa di decisamente diverso, ma nello stesso tempo
molto simile: un interfaccia di controllo e un avatar. Inizialmente l’obiettivo primario era sfruttare le informazioni estrapolate dalle immagini per
far interagire con modalità estremamente semplici la macchina e il mondo
esterno.
Il primo passo è stato creare un’interfaccia di controllo per videogiochi
2
Un software è monolitico quando al suo interno non c’è separazione logica e concettuale
tra i vari moduli.
3
Un plugin è un modulo che può essere aggiunto ad un certo software per aggiungere
funzionalità o addirittura cambiare il comportamento di funzionalità già esistenti.
INDICE
iv
sfruttando il movimento del corpo, rilevato dalle tecnologie che HuMoR ha
premesso di elaborare. Videogiochi ovviamente semplici, dove il grado di
libertà del movimento consentito era solamente quello orizzontale, anche se
grazie a raffinamenti successivi è stato possibile ottenere il click, permettendo
cosı̀ di attivare azioni contestuali al gioco (sparare, lanciare palline, ecc. . . ). Il
lavoro si era direzionato anche sul creare un sistema di puntamento analogo
al mouse ma che funzionasse unicamente con il movimento della mano e
delle dita (anche qui molti film cinematografici ipotizzano queste tecnologie),
inglobando un altro settore dell’Intelligenza Artificiale in forte ascesa: la
Gesture Recognition 4 .
Il secondo passo è stato approfondire il concetto di interazione uomomacchina, studiando un avatar in grado di interagire con l’ambiente circostante. L’avatar è dotato di un volto renderizzato in real-time grazie ad
un modello 3D che consente di muovere indipendentemente gli occhi, dalle
sopracciglia, dalla bocca, dal volto. L’interazione, per il momento molto basilare, consiste nel seguire con gli occhi il soggetto che si muove nella scena,
compensando la distorsione prospettica che si genera durante la rotazione del
volto sull’asse verticale.
Per cercare di avere un tipo di reazione agli eventi quanto più simile a
quella umana, la macchina deve poter avere quante più informazioni possibili
sul contesto in cui agisce. Assolvere questo compito significa studiare tecniche che rientrano in altri settori dell’Intelligenza Artificiale come la Face
Detection e la Mood Detection, per il riconoscimento del volto e dell’umore
di chi interagisce, lo Speech Recognizing e il Text to Speech, per poter avere
interazioni di tipo vocale sia uomo-macchina, che macchina-uomo, l’Audio
Localization, per la localizzazione spaziale delle fonti sonore, ad esempio l’utilizzatore del sistema, utile in aiuto alla localizzazione video. Tutte le funzionalità sopra esposte sono attualmente in fase di studio e implementazione,
ma la loro descrizione dettagliata non rientra negli scopi di questa tesi e ne
verrà dato solamente un breve accenno.
4
Branca dell’Intelligenza Artificiale rivolta all’interpretazione dei gesti umani tramite
algoritmi matematici.
Capitolo 1
Rilevazione del movimento
L’uomo ha una naturale ed efficace propensione a rilevare il movimento
che si verifica nell’ambiente circostante. Per una macchina assolvere a questo
compito non è altrettanto semplice, anche se le tecniche adottate non sono
concettualmente complesse.
Le azioni principali eseguite per raggiungere lo scopo sono:
• Acquisizione dell’immagine da una sorgente video
• Adeguamento dell’immagine per le elaborazioni successive, fase nota
come pre-processing
• Stima dello sfondo per suddividere le parti dell’immagine che rappresentano le zone statiche e le zone in movimento
• Segmentazione dell’immagine per isolare ogni singolo oggetto in movimento e rappresentarlo come entità indipendente dalle altre
• Estrazione di features dall’immagine, necessarie per tutte le elaborazioni di più alto livello (semantiche), fatte in fasi successive
• Tracciamento del movimento
I passi sopra elencati non preoccuperebbero nessun ricercatore né alcun
elaboratore se vivessimo in un mondo ideale. Sfortunatamente non è questo
il caso e nel tentativo di concludere con successo questa lista di azioni, si
incontrano molte difficoltà:
2
• Acquisendo un’immagine da una sorgente video i primi problemi in
cui ci si imbatte sono la qualità e l’affidabilità della sorgente. Basti
considerare che le singole immagini, i fotogrammi, possono non essere
generati con cadenza regolare, ad esempio una sorgente in streaming via
internet, obbligando il sistema ad essere robusto a questo tipo di errore.
Ovviamente se i fotogrammi dovessero mancare per un periodo troppo
prolungato, l’elaboratore sarebbe comunque costretto a reinizializzarsi
sulle nuove immagini. Anche il problema della qualità non può essere
trascurato, perché una sorgente, ad esempio una webcam economica
o posizionata in modo scorretto, che non riesca a mantenere stabile il
livello del colore o della luminosità, causerebbe forti variazioni locali al
singolo pixel con il rischio che vengano interpretate erroneamente come
movimento.
• La stima dello sfondo risente molto dell’instabilità di luminosità e colore dell’immagine. L’occhio (e soprattutto la mente) umana riesce a
compensare egregiamente anche forti variazioni di colore e luminosità,
in virtù del fatto che viene fatta a priori un’analisi semantica. Un elaboratore non possiede questa dote e l’analisi parte dalle fondamenta
dell’immagine, il pixel. Se questo subisce forti variazioni in una delle sue componenti tra un fotogramma e il successivo, lo stimatore di
sfondo potrebbe essere indotto a segnalare tale pixel come movimento, anziché come sfondo. La qualità della sorgente è influenzata anche
dalla risoluzione con cui l’immagine viene prodotta. Maggiore è la risoluzione, maggiore è il numero di pixel creati per ogni singolo oggetto
dell’immagine, maggiore è la precisione con cui si riescono a fare analisi semantiche sull’immagine, ivi compresa la rilevazione dello sfondo.
Un’immagine descritta da 320x240 pixel (76.800 pixel) sarà molto meno
resistente al rumore di una descritta da 1024x768 pixel (786.432 pixel).
• Il processo di segmentazione risente, anch’esso, della mancanza di qualità della sorgente. Segmentare un’immagine consiste nell’identificare
zone i cui pixel sono correlati fra loro secondo un qualche criterio scelto
ad-hoc, spostando il dominio di analisi dal singolo pixel a regioni di
3
pixel e permettendo, quindi, di ridurre notevolmente la mole di dati da
analizzare. Partendo da un’immagine 1024x768 pixel (786.432 pixel),
dopo la segmentazione, si possono avere un numero di regioni molto
minore, generalmente di qualche ordine di grandezza (100-1000 regioni), arrivando ad una situazione in cui la complessità computazionale
diventa sostenibile per gli attuali elaboratori. Si potrebbe osservare che
si ha una notevole perdita di informazione, il che è senz’altro vero, ma
il tipo di analisi successive che viene effettuato non necessita di una
descrizione dettagliata dell’immagine, quanto di una descrizione più
verosimilmente semantica. Risulta ovvia la constatazione che se zone
ampie di pixel subiscono forti variazioni dovute al rumore, le regioni
ottenute dalla segmentazione saranno diverse e più difficili da analizzare, soprattutto nel caso le si vogliano correlare tra un fotogramma e il
successivo.
• La scelta di quali features estrarre risulta essere particolarmente delicata, in quanto devono discriminare in modo mirato alla risoluzione del
problema e devono essere il più resistenti possibile al rumore introdotto dalla sorgente. Si possono scegliere features discriminanti in base al
colore, alla forma, all’area, alla posizione del baricentro o al centro di
gravità dell’oggetto in movimento oppure in base a proprietà invarianti a rotazione e ridimensionamento dell’immagine. Le features che si
posso estrarre da un’immagine sono generalmente molte, ma anche in
questo caso si deve porre attenzione che la bontà delle features ottenute
non vada a discapito della complessità computazionale complessiva.
• Tracciare il movimento risulta essere un’analisi di livello più alto, in
quanto va a lavorare sui dati prodotti nelle fasi precedenti. È evidente
che se le features ottenute e la stima dello sfondo sono state alterate da
rumore o più in generale dalla scarsa qualità della sorgente, anche in
questo caso si possono ottenere risultati poco soddisfacenti. Se il dominio di applicazione risulta essere abbastanza limitato e ben strutturato
nulla vieta di porre dei vincoli restrittivi sul tipo di analisi da fare, cosı̀
da ridurre a posteriori la produzione di dati errati.
1.1 Motion Detection
4
Nel seguito del presente capitolo verranno prese in esame più in dettaglio
solamente le fasi di rilevazione del movimento e di tracking degli oggetti. Le
altre fasi per quanto interessanti esulano dallo scopo di questa tesi.
1.1
Motion Detection
Analizzare il movimento in una sequenza di immagini è un processo che
coinvolge principalmente due fasi:
• Rilevare lo sfondo (Background Detection)
• Determinare il movimento
La rilevazione dello sfondo è una fase fondamentale nell’analisi del movimento ed è anche la fase che più ha coinvolto lo sforzo dei ricercatori nell’ambito della Computer Vision. L’esperienza comune suggerisce di considerare
come sfondo la parte dell’immagine che rimane immobile nel susseguirsi dei
fotogrammi. Si potrebbe quindi decidere di impostare come sfondo il primo
fotogramma che arriva dalla sorgente video. All’arrivo del fotogramma successivo si effettua un’operazione di confronto pixel per pixel, del tutto simile
ad una sottrazione, per ottenere i pixel che sono diversi e che possono essere etichettati come movimento. Una soluzione cosı̀ strutturata per quanto
semplice e veloce computazionalmente presenta dei forti limiti, in quanto si
deve assumere che il primo fotogramma sarà sempre sfondo e che lo sfondo è
statico, ovvero non può subire cambiamenti di alcun tipo. Impostare il primo fotogramma come sfondo può portare ad una scelta errata, basti pensare
a luoghi particolarmente affollati, come una piazza, dove lo sfondo effettivo
è sempre coperto da movimento oppure basti pensare alla presenza di un
oggetto dentro la scena nel momento in cui viene impostato lo sfondo, ad
esempio una macchina parcheggiata; quando questo si rimuoverà dalla scena
la differenza con i nuovi fotogrammi, in assenza di quell’oggetto, mostrerà
costantemente movimento laddove in realtà non ce n’è. La seconda restrizione produce risultati ancor più negativi, tranne che in un numero molto
limitato di situazioni, in quanto è sufficiente far cambiare le condizioni di illuminazione della scena per ottenere un’immagine completamente diversa dallo
1.1 Motion Detection
5
sfondo impostato. Per chiarire meglio il concetto, si può supporre di avviare
l’elaboratore la mattina, cosı̀ da impostare lo sfondo che abbia proprietà di
illuminazione ben definite e di vedere cosa succede al calar della sera quando
l’illuminazione diventa artificiale o totalmente assente. Ovviamente i nuovi
fotogrammi risulteranno completamente diversi nella loro totalità dallo sfondo impostato. Un caso più pratico, riscontrato personalmente, è l’abilità di
molte webcam moderne di compensare automaticamente la luminosità delle
immagini prodotte. Per quanto questa funzionalità sia molto utile all’occhio
umano per migliorarne la percezione visiva, risulta essere veramente controproducente per le analisi da effettuare in quanto l’elaboratore per ogni cambio
di luminosità sarà “cieco”; tutti i pixel dell’immagine verranno etichettati come movimento, ottenendo quindi informazioni totalmente inutilizzabili. Una
situazione di questo tipo può essere parzialmente isolata introducendo delle soglie (threshold ) sulla velocità di variazione della luminosità dell’intero
fotogramma o dei singoli pixel, portando quindi l’elaboratore ad ignorare
la variazione qualora questa superi la soglia impostata. Ovviamente una
soluzione cosı̀ strutturata non può risolvere il problema dei cambi di luminosità lenti e graduali, come la transizione giorno-notte, con cui è difficoltoso
impostare delle soglie adeguate senza inficiare l’analisi complessiva.
Un compromesso per ovviare a queste problematiche senza incrementare
eccessivamente la complessità computazionale è considerare lo sfondo non
più statico ma aggiornabile secondo un qualche criterio specifico per l’applicazione. Introducendo un nuovo fattore di analisi, si introducono ovviamente
nuove problematiche a cui occorre fare attenzione per non cadere in errori
banali ma subdoli. Una approccio apparentemente plausibile nell’aggiornamento dello sfondo potrebbe essere di reinizializzarlo ad intervalli regolari
con i nuovi fotogrammi prodotti dalla sorgente. Portando questa idea al caso
limite si potrebbe pensare di restringere l’intervallo al singolo fotogramma, in
modo da avere uno sfondo che si aggiorna su ogni immagine. Una soluzione
di questo tipo per quanto semplice produce effetti non migliori di uno sfondo
statico, in quanto soffre in parte delle stesse problematiche di quest’ultimo
ma aggiunge un nuovo problema: un oggetto in movimento, rilevato in due
istanti consecutivi, verrà riconosciuto come mosso solo laddove l’intersezione
1.1 Motion Detection
6
dell’oggetto nei due fotogrammi sia nulla. Semplificando il concetto se si
confronta (sottrae) il primo fotogramma con il secondo, la parte dell’oggetto
che verrà etichettata come movimento sarà solamente quella zona in cui l’elaboratore vede nuovi pixel dell’oggetto. Tutti i pixel in comune tra il primo
e il secondo fotogramma, non rappresentando un cambiamento, verranno etichettati come zona non mossa, producendo l’indesiderato effetto di rendere
totalmente inaffidabili le conclusioni.
La necessità quindi di avere uno sfondo aggiornabile ha portato molti ricercatori alla produzione di soluzioni più o meno efficaci, ma con un punto
in comune: la considerazione che l’alterazione dello sfondo avviene gradualmente, a meno di applicazioni specifiche. In letteratura si riescono infatti
a trovare principalmente due filoni nell’approccio al problema: chi tiene in
considerazione le differenze riscontrate negli ultimi fotogrammi e chi crea un
modello statistico dello sfondo.
Il primo approccio presenta lo svantaggio di tenere traccia di una storia
troppo breve dei cambiamenti avvenuti nello sfondo e quindi essere poco accurato nel determinare eventi verificatisi a istanti di tempo più lontani. Il
secondo approccio, invece, non risente di questa limitazione, ma risulta essere
molto lento nel memorizzare le nuove variazioni. Il lasso di tempo necessario per l’aggiornamento del modello statistico può essere troppo ampio per
rendere questa tecnica utilizzabile in un ambiente in cui gli oggetti ripresi
si muovano troppo lentamente. Offre, comunque, l’indiscutibile vantaggio di
essere insensibile al verificarsi di variazioni repentine (spike) sull’immagine,
che non entrando a far parte dello sfondo non inficeranno le analisi successive.
Offre anche la capacità di assorbire nel modello statistico oggetti che rimangono fermi per un periodo di tempo sufficientemente lungo, ad esempio una
macchina che viene parcheggiata sul bordo di una strada, evento che il primo
approccio avrebbe inglobato in un tempo troppo breve per la produzione di
risultati attendibili (la macchina poteva essere ferma ad uno stop).
L’implementazione utilizzata in HuMoR è una versione ibrida dei due
metodi sopra descritti, in quanto si è cercato di sfruttarne maggiormente i
vantaggi, attenuandone i difetti. Come già detto il modello statistico è quello
che offre il maggior grado di accuratezza e precisione nel modellare lo sfondo,
1.1 Motion Detection
7
ma è inevitabilmente lento per aggiornarsi sui nuovi dati ricevuti. Si è proceduto quindi a creare, invece di un singolo modello, un insieme degli stessi,
implementando la possibilità di scegliere quale tra quelli attualmente disponibili approssimassero meglio lo sfondo corrente. L’idea, fondamentalmente,
consiste nel cominciare ad usare uno dei possibili modelli, finché questo risponda in modo adeguato alle immagini analizzate. Nel momento in cui sia
necessario l’aggiornamento del modello, in quanto non è più in grado di approssimare correttamente lo sfondo corrente, invece di far partire il processo
di aggiornamento, che ricordo essere lento e soprattutto irreversibile, viene
scelto il modello tra quelli disponibili che meglio si adatti alla situazione corrente. Se un modello con tali caratteristiche non esiste, quello attuale viene
memorizzato in uno slot vuoto e parallelamente si crea un nuovo modello da
modificare secondo le richieste correnti. Gli slot dei modelli da memorizzabili
sono in numero limitato ed è quindi necessaria una politica di eliminazione
dei modelli che non contribuiscono più efficacemente. Si è proceduto all’introduzione di una tecnica di invecchiamento con la quale ogni modello che
non viene utilizzato nel fotogramma corrente viene invecchiato; quando tutti
gli slot sono pieni e si deve memorizzare un nuovo modello, si procede con
l’eliminazione del modello che è più vecchio, ovvero che non è stato utilizzato
per un lasso di tempo maggiore rispetto agli altri. In questo modo si possono
liberare gli slot che non hanno più contribuito attivamente al funzionamento
dell’algoritmo e per permettere ai nuovi modelli, che potrebbero (ma non
necessariamente fanno) approssimare meglio lo sfondo, di essere allocati. Risulta chiaro che il numero di slot disponibili diventa un parametro cruciale,
in quanto un numero troppo piccolo rende vana l’idea basilare dell’algoritmo implementato, mentre un numero troppo ampio aumenta inutilmente la
complessità computazionale, dovendo effettuare un maggior numero di confronti tra il fotogramma attuale e tutti i modelli memorizzati, nel tentativo
di trovare quello che meglio approssimi lo sfondo corrente.
Si può evincere facilmente che il grosso vantaggio di un’implementazione
simile consiste nell’essere robusta a variazioni sistematiche dello sfondo, come
i cambi di illuminazione (una fonte luminosa che viene accesa e spenta, una
finestra che viene aperta e chiusa o più banalmente la presenza di masse
1.2 Object Tracking
8
nuvolose che rendono scostante l’illuminazione solare) o come una porta che
sia apre e si chiude con continuità (ad esempio un ufficio). Avendo come
riferimento un solo sfondo, tutte le circostanze citate produrrebbero una
lunga serie di eventi1 totalmente inutili. Con l’algoritmo implementato in
HuMoR, invece, non appena lo sfondo cambia, se tale cambiamento è già stato
osservato dal sistema, viene effettuato un semplice e rapido cambiamento di
sfondo, senza generare tutti gli eventi del precedente caso. Si è quindi riusciti
a rendere il sistema robusto a variazioni sistematiche dello sfondo.
1.2
Object Tracking
Una volta che si è riusciti ad identificare quali parti dell’immagine risultano essere mosse, si procede con la fase nota come Object Tracking. Sapere
che c’è movimento è di per se una informazione utile in molti contesti, ma
nell’ambito della videosorveglianza2 , come in molti altri settori, si ha l’esigenza di seguire l’oggetto e quindi di tracciarne l’evoluzione del movimento
avvenuto su tutti i fotogrammi in cui l’oggetto è presente, da quando entra a far parte della scena fino a quando ne esce. Si pone quindi un altro
problema non banale da risolvere: come si può essere certi che un oggetto
rilevato in movimento ad un certo fotogramma sia ancora lo stesso oggetto
rilevato al fotogramma successivo e non sia, ad esempio, un nuovo oggetto
completamente diverso? Per rispondere a questa domanda si deve fare una
breve accenno sul quinto punto della lista di fasi elencati all’inizio di questo
capitolo: l’estrazione di features.
Una feature è una particolare sequenza di dati che identificano una certa
proprietà legata all’intera immagine o ad una sua parte. Il target di interesse
in questa analisi sono gli oggetti in movimento, pertanto le features generate saranno sempre in relazione alla porzione di immagine che comprende
l’oggetto. Si potranno avere features selettive in base all’area (espressa in
1
Con evento si intende un’azione compiuta dal sistema in risposta alla rilevazione di
movimento nella scena
2
Si ricorda al lettore che inizialmente HuMoR è stato sviluppato come progetto di
videosorveglianza e come tale le tecniche usate ne rispecchiano il comportamento
1.2 Object Tracking
9
pixel) dell’oggetto, nonché in base alla forma, alla posizione del baricentro
o del centro di gravità dell’oggetto stesso. Le features possono essere molteplici e possono discriminare anche sulla base di informazioni diverse da
quelle puramente geometriche, ad esempio colore e luminosità, oppure sulla
base di complessi algoritmi matematici, come l’algoritmo di David G. Lowe
presentato in [10] estremamente potente nel localizzare alcuni punti dell’immagine invarianti a rotazione e ridimensionamento dell’immagine stessa.3
Ovviamente in un sistema che lavora in tempo reale su stream video risulta
fondamentale la velocità nel calcolo delle features; si deve quindi scegliere
quali possano essere utili per la risoluzione dello specifico problema e quali
no. Se ad esempio si lavora su flussi di immagini in scala di grigi (in assenza
quindi di colore) risulterà ovviamente inutile estrarre features sul colore. In
ogni caso vale spesso la regola che più features si hanno a disposizione, meglio
si riesce a stabilire la somiglianza di un certo oggetto con uno già visto ad
instanti precedenti.
Esistono celebri esempi di come vengano usate proficuamente features di
tipo esclusivamente geometrico, come applicazioni per la compressione video
Mpeg7 [1] oppure sistemi che si prefiggono obiettivi paragonabili a HuMoR
come [7]. Alla base dell’estrazione di features geometriche si può riscontrare
in quasi tutti gli approcci il calcolo di momenti di vario ordine come spiegato
in [5].
Nell’implementazione attuale del tracker di HuMoR vengono usate principalmente features di tipo geometrico, in particolare vengono calcolate la
posizione, il baricentro, il centro di gravità del blob4 e la distribuzione del
colore sugli assi x e y. Si è pensato di non usare altri tipi di features in
quanto il tracker non necessita di molte informazioni per riuscire a tracciare efficacemente gli oggetti presenti sulla scena; le informazioni geometriche
sono sufficienti per rintracciare l’oggetto nei fotogrammi successivi, mentre
3
La tecnica implementata da Lowe è particolarmente nota per la sua potenza nel riuscire
a descrivere in modo quasi univoco alcuni punti ben precisi dell’immagine, che possono
poi essere ritrovati anche se l’immagine viene ruotata, ridimensionata (con perdita di
informazione) e anche se l’oggetto analizzato viene parzialmente occluso da altri oggetti.
4
Un blob è una zona generalmente rettangolare che racchiude tutti i pixel identificati
come movimento.
1.2 Object Tracking
10
le informazioni sulla distribuzione del colore sono utili per distinguere tra
oggetti geometricamente simili.
La parte finale della fase di Object Tracking, ovvero dopo aver estratto
tutte le features necessarie, consiste nell’effettuare il tracking degli oggetti
presenti. Per assolvere a questo compito sono stati implementati tre metodi:
per votazione, con la distanza tra vettori di features e con le reti di Kohonen.
Tutti i metodi citati tengono traccia degli oggetti presenti e passati della
scena, utilizzando un vettore (tracklist) contenente vettori di features riferite
al singolo oggetto tracciato. Per ogni oggetto identificato dal motion detector,
vengono confrontate le features con quelle già presenti nella traklist; se si ha
corrispondenza, si aggiungono le nuove features al vettore relativo all’oggetto
nella tracklist, in quanto l’oggetto è già stato visto e se ne sta seguendo il
movimento. Nel caso in cui non si ha corrispondenza, viene aggiunto un
nuovo elemento nella tracklist, perché l’oggetto è appena entrato a far parte
della scena e da questo momento in poi ne viene tenuta traccia.
L’analisi della corrispondenza tra l’oggetto identificato nel frame corrente
e quelli memorizzati nella tracklist è compito dei tre metodi sopra citati: il
metodo per votazione consiste nel sottrarre due vettori di features, prenderne
il valore assoluto, moltiplicarlo per un vettore di pesi e confrontare il risultato con un vettore di soglie. Se le componenti del vettore ottenuto sono
inferiori delle componenti del vettore delle soglie, allora i singoli elementi del
vettore ottenuto vengono sommati fra loro per ottenere il voto. Il metodo per
votazione è stato poi sostituito con il metodo basato su distanza tra vettori,
in quanto non necessita dell’intervento manuale per la definizione del vettore
dei pesi e delle soglie. Il funzionamento di quest’ultimo metodo è del tutto simile a quello per votazione tranne che invece del voto viene usata la distanza
tra i vettori di features. Al vantaggio di non dover intervenire manualmente
per configurarlo, si aggiunge lo svantaggio della perdita di precisione dell’algoritmo, in quanto se il vettore delle features da confrontare contiene molti
elementi, la distanza tra vettori è un parametro che non può tenere conto del
tipo di variazione verificatasi: possono cambiare molte componenti oppure
una sola ma in modo consistente. Si è comunque potuto osservare che questo
algoritmo funziona bene nel caso di features puramente geometriche, come
1.2 Object Tracking
11
area e baricentro del blob, assumendo che gli oggetti non si muovano troppo
velocemente rispetto al framerate del flusso video. Il terzo metodo si basa su
approccio basato su reti neurali di tipo SOM e reti di Kohonen, dove a livello
concettuale, le features presenti nella traklist attraggono le features estratte
dall’immagine corrente: più forte è l’attrazione più c’è corrispondenza tra gli
oggetti rappresentati dalle features in esame. Per maggiori approfondimenti
si rimanda alla lettura del lavoro di Gilles Labonté [8].
Capitolo 2
Costruire un framework di
sperimentazione
La parte principale del contributo personale apportato a HuMoR è stata la sua ristrutturazione interna, che lo ha portato dall’essere una applicazione monolitica ad essere un framework1 estremamente flessibile per la
sperimentazione di algoritmi e idee per la Computer Vision. L’esigenza di
re-ingegnerizzazione interna ha dato la possibilità di pianificare attentamente quali dovessero essere le caratteristiche principali che il nuovo HuMoR
avrebbe dovuto offrire. Ci siamo posti un obiettivo ambizioso: trasformare
HuMoR in un’entità molto più generica che permettesse al ricercatore, non
esperto di programmazione, di implementare velocemente nuovi algoritmi su
una piattaforma performante. Software simili già esistono, ad esempio Matlab2 , che per quanto permetta di scrivere algoritmi molto rapidamente non
permette poi di eseguirli con altrettanta velocità. Abbiamo cominciato a
porre dei vincoli che la nuova piattaforma avrebbe dovuto soddisfare, cercando di prendere il meglio dalle soluzioni già esistenti e migliorare ciò che
già avevamo. Siamo quindi giunti alla conclusione che se HuMoR sarebbe
1
Un framework è una struttura di supporto su cui un software può essere organizzato e
progettato. HuMoR non è propriamente un framework ma un ambiente di sviluppo, poiché
per quanto possa essere utilizzato come una libreria, risulta più semplice implementare le
nuove funzionalità al suo interno ed eventualmente esportarne i risultati.
2
Software molto noto in ambito universitario e non solo, utilizzato principalmente per
la sperimentazione in ambito matematico e affine. Per maggiori informazioni vedere [11].
13
diventato un sistema flessibile e performante, avrebbe dovuto essere:
semplice HuMoR sarebbe dovuto essere utilizzabile ma soprattutto estensibile anche da utenti non propriamente esperti di programmazione.
Proponendosi come framework ovviamente avrebbe richiesto un livello
minimo di conoscenze tecniche, ma questo non sarebbe dovuto essere
un ostacolo per chi non fa della programmazione il proprio ambito di
studio o di lavoro. Abbiamo deciso di modellare i vari moduli come dei
plugin, con un’interfaccia pubblica estremamente chiara, ridotta e funzionale, per non lasciare possibili spazi ad incomprensioni o difficoltà.
Come verrà mostrato in seguito (paragrafo 2.1) è possibile creare un
nuovo plugin con tre file e meno di venti righe di codice sorgente.
modulare Tutte le funzionalità del framework avrebbero dovuto essere implementate all’interno di moduli intercambiabili fra loro, rispettando
ovviamente la compatibilità tra i moduli stessi. Sarebbe quindi stato possibile sviluppare un nuovo motion detector e sostituirlo a quello
in uso per misurare poi i miglioramenti (o i peggioramenti). Come il
motion detector sarebbe stato possibile sostituire velocemente anche il
tracker, la sorgente video o tutti i componenti che effettuano analisi
a posteriori (vedere in proposito il paragrafo 2.2.2). Nel progettare la
scomposizione in moduli è stata fatta la scelta di rendere anche il core 3
di HuMoR un modulo, rendendo cosı̀ possibile alterare l’ordine che lega
i vari moduli fra di essi e quindi anche il flusso logico di come i dati
vengono elaborati.
efficiente Progettare un framework estremamente flessibile senza offrire la
possibilità di sperimentare ed eseguire gli algoritmi con rapidità sarebbe stata una contraddizione. Ambienti di lavoro con questa tipologia
già esistono4 e non avrebbe avuto molto senso ripercorrere le scelte progettuali effettuate da altri software. Si è scelto di usare un linguaggio
3
Il core di un software è la sua parte principale. Generalmente senza di essa non si
potrebbero avere neanche le funzionalità basilari oltre che l’interconnessione tra tutti gli
altri moduli.
4
Ad esempio lo stesso Matlab che a fronte di una notevole flessibilità, offre una
scarsissima velocità nel processamento dei dati.
2.1 Semplicità
14
di programmazione che offrisse sufficiente potenzialità espressiva per
non privarsi della capacità di descrivere nel linguaggio stesso i concetti qui esposti (modularità, efficienza e semplicità) e che producesse
binari veloci ed ottimizzati. L’attenzione è ricaduta immediatamente
sul linguaggio C++, che grazie alla compatibilità quasi completa con
il paradigma della programmazione ad oggetti (OOP) ha permesso di
mantenere la complessità del codice sostenuta e con ottime performance globali. Oltre a tale aspetto sono state poi adottate delle tecniche
di ottimizzazione del codice sorgente per evitare la ridondanza dei dati
e lo spreco di risorse.
Prima di concludere questa breve parte introduttiva vorrei porre l’attenzione su alcune peculiarità aggiuntive proprie di HuMoR: la scelta del
linguaggio C++ ha permesso di creare un framework platfrom independent,
ovvero che possa essere con pochissimo sforzo essere riadattato per funzionare su tutti i principali sistemi operativi, come Linux, Windows, MacOsx,
Bsd, ecc. . . Inoltre il processo di sviluppo è avvenuto completamente su piattaforma Linux[9], utilizzando esclusivamente software libero5 come Vim[12]
e Kdevelop[6], tutti rilasciati con licenze libere, come la GNU GPL[4].
Lo stesso HuMoR è stato rilasciato come software libero, con licenza GNU
GPL versione 2.
2.1
Semplicità
Pensando al concetto di semplicità, ci siamo posti il vincolo che per creare un nuovo modulo (da ora in avanti plugin) sarebbe servita una struttura
estremamente compatta. Nell’ambito di questa struttura devono però essere
risolte tutte le possibili esigenze che un plugin può avere: l’implementazione
del codice operativo e la gestione di una configurazione di funzionamento.
Il primo passo effettuato, quindi, è stato suddividere la struttura del plugin
in due parti distinte (figura 2.1), in cui una, il Component Plugin, si occupa
5
Per una trattazione più approfondita di cosa sia il software libero l’autore della presente
tesi raccomanda la lettura di “Cos’è il Software Libero?”[2].
2.1 Semplicità
15
Figura 2.1: Struttura di un plugin
dell’implementazione del codice operativo a cui è affidato l’elaborazione e la
produzione di dati, mentre l’altra, l’Interface Plugin, si occupa della gestione dei parametri di funzionamento per configurare il Component Plugin nel
modo voluto. L’interazione fra le due componenti avviene in maniera del tutto trasparente per il Component Plugin, che quando richiamato dal core di
HuMoR effettuerà l’analisi dei dati avuti in input, mentre il lavoro “sporco”
è affidato interamente all’Interface Plugin che, deve in prima istanza procurarsi una versione aggiornata dei parametri e successivamente impostare
le variabili di lavoro del Component Plugin ad esso associato. Come detto,
l’operazione è del tutto trasparente per il Component Plugin che si troverà le
variabili di lavoro correttamente inizializzate con i valori corretti. Ovviamente questa fase deve avvenire in un momento in cui il Component Plugin non
è operativo; generalmente accade quando viene creata una nuova sessione di
HuMoR oppure al verificarsi di eventi esterni (come il lancio di signals6 , in
particolare il segnale SIGUSR1).
2.1.1
Interface Plugin
Come si vede dal listato 2.1, la classe di un’Interface Plugin è semplice:
la parte pubblica ha solamente due metodi, read() e write(). Intuitivamente
il primo (VERIFICARE) viene chiamato quando si vuole che il plugin legga
una versione aggiornata dei parametri di funzionamento, mentre il secondo
6
Un signal, o segnale, è un evento generato dal sistema operativo o da un altro software
per avvertire il destinatario del segnale del verificarsi di particolari eventi.
2.1 Semplicità
16
quando si vuole memorizzare i parametri di funzionamento correnti (può
essere utile se l’algoritmo implementato aggiorna metodicamente i propri
parametri di lavoro).
Listing 2.1: Struttura di un Interface Plugin
/∗ ∗
∗ Generic I n t e r f a c e i n t e r f a c e
∗/
class InterfacePlugin : public Plugin
{
public :
InterfacePlugin ( )
: component ( 0 )
{};
virtual ˜ InterfacePlugin ( ) { } ;
virtual bool setup ( const std : : string& setup_data ) = 0 ;
void setComponent ( ComponentPlugin ∗ o ) ;
static std : : string getType ( ) { return " Interface " ; }
protected :
ComponentPlugin ∗ component ;
friend class plugin_table ;
};
La struttura dell’Interface Plugin è volutamente priva di informazioni sul
tipo di supporto in cui i parametri verranno letti e memorizzati; il comportamento dipende unicamente dall’implementazione che l’utente farà all’interno
dei due metodi. Si potranno avere quindi Interface Plugin che leggono e
scrivono su file, piuttosto che su database, piuttosto che su socket per la
comunicazione remota verso possibili repository dedicati.
2.1.2
Component Plugin
La classe del Component Plugin è paradossalmente più semplice da analizzare: nel LISTATO 2 si vede chiaramente che l’interfaccia pubblica della
2.1 Semplicità
17
classe implementa un singolo metodo (VERIFICARE), run(), che sarà invocato tutte le volte che il core di HuMoR ritiene necessaria l’esecuzione della
parte computativa del plugin. L’utente avrà quindi l’onere di implementare il
proprio algoritmo all’interno del metodo (VERIFICARE), potendo avvalersi
dell’accesso a tutte le variabili di lavoro del core di HuMoR, che si occupa
principalmente della condivisione dei dati tra i vari plugin (sarà spiegato con
maggior dettaglio nel paragrafo 2.2.1).
2.1.3
HuMoR Plugin
Perché i due plugin, il Component e l’Interface Plugin, possano essere riconosciuti e utilizzati da HuMoR è necessaria una struttura aggiuntiva
che faccia da collante alle due precedenti e che implementi tutti i metodi e
le informazioni necessarie per descrivere il Component e l’Interface Plugin
in esso contenuti. Quello che potremmo, quindi, chiamare HuMoR Plugin,
mostrato nel LISTATO 3, è ancora più semplice da implementare, quasi automatico, in quanto l’utente deve utilizzare le due macro7 INITPLUGIN e
ENDPLUGIN, che delineano l’inizio e la fine dello HuMoR Plugin, e al loro interno elencare quali classi implementano il Component Plugin e quali
l’Interface Plugin, utilizzando le macro dedicate COMPONENTPLUGIN e
INTERFACEPLUGIN.
Una volta creato lo HuMoR Plugin è sufficiente compilarlo e copiarlo nella
directory che contiene tutti gli HuMoR Plugin, in modo che al lancio di una
nuova sessione di HuMoR, vengano caricati in strutture di memoria apposite
e assegnati correttamente alle funzionalità descritte nelle informazioni dello
HuMoR Plugin. La parte che si occupa di caricare, analizzare e istanziare
ogni singolo HuMoR Plugin è mostrata nel LISTATO 4, sezione del codice che
peraltro è del tutto trasparente all’utente che voglia solamente implementare
il proprio algoritmo.
7
DEFINIRE COSA è UNA MACRO
2.2 Modularità
2.2
18
Modularità
Formalizzato il concetto di plugin (paragrafo 2.1), si è scelto di applicare
tale struttura a tutte le parti principali di HuMoR. Sono stati creati quindi
un plugin di input, chiamato CameraPlugin (VERIFICARE), un plugin per
l’analisi del movimento, chiamato MotionDetectionPlugin, un plugin per il
tracciamento del movimento, chiamato TrackerPlugin e due categorie speciali
di plugin:
• HuMoRCorePlugin, deputato alla gestione del core di HuMoR e quindi
alla gestione di tutto il flusso dei dati e alla loro condivisione con gli
altri plugin
• DataConsumerPlugin, collocato alla fine del ciclo di analisi delle immagini ottenute in input, come si può vedere nella FIGURA HO PERSO
IL CONTO, ha il compito di implementare tutte le elaborazioni di
più alto livello semantico, rispetto ai precedenti plugin. I DataConsumerPlugin possono essere molteplici, al contrario di quanto accade
per gli altri plugin, e vengono invocati nell’esatto ordine in cui vengono
elencati nei parametri di configurazione dello HuMoRCorePlugin.
Per quanto sia interessante approfondire la struttura di tutti i tipi di plugin
implementati, verranno analizzati in dettaglio solamente questi ultimi due,
possedendo una struttura e delle funzionalità sicuramente più avanzate.
2.2.1
HuMoRCore Plugin
La parte più interessante dello HuMoRCorePlugin è il metodo loop(),
come si può vedere nel LISTATO X (HuMoR Daemon -¿ HuMoR Core -¿
loop()), nella parte privata dell’interfaccia. Per creare una nuova sessione di
HuMoR si deve far partire un programma chiamato HuMoR Daemon, che si
occupa solamente di configurare il core di HuMoR, prelevando i parametri
necessari da un file di configurazione (LISTATO XX) e di far partire su di
un thread parallelo l’esecuzione del core di HuMoR, che si limiterà ad invocare il metodo loop() sopra citato. Il flusso logico delle chiamate ad i vari
2.2 Modularità
19
plugin è descritto nel codice implementato in tale metodo (LISTATO X):
il primo passaggio consiste nel calcolare il framerate effettivo a cui HuMoR
sta lavorando ed eventualmente introdurre dei ritardi per ridurlo, se nel file
di configurazione viene indicato un framerate massimo (campo delay e fps).
Successivamente si procede con il prelevare dal CameraPlugin un fotogramma
da analizzare ed eventualmente applicare un pre-filtro se il campo prefilter
è impostato a true. Si continua invocando il MotionDetectorPlugin che restituisce una maschera di pixel dove un pixel bianco rappresenta una zona
etichettata come movimento e un pixel nero rappresenta una zona etichettata
come non movimento. Se il numero totale dei pixel identificati come movimento supera una certa soglia, si procede chiamando il tracker, che restituirà
il vettore traklist (vedere il paragrafo 1.2) aggiornato con le features degli
oggetti identificati. Infine ci sarà la chiamata a tutti i DataConsumerPlugin, nello stesso ordine in cui sono stati elencati nel campo data-consumer,
e l’applicazione del ritardo per ridurre il framerate. A questo punto il ciclo
può iniziare nuovamente e continuare fintanto che non si verifica un qualche
condizione di stop, che generalmente provoca l’interruzione del thread del
core di HuMoR.
2.2.2
DataConsumer Plugin
I plugin DataConsumer hanno il compito di effettuare post-analisi su tutti i dati elaborati dal Motion Detector e dal Tracker; vengono invocati per
ultimi nel flusso logico di esecuzione, come spiegato nel paragrafo 2.2.1 e
dispongono di una grossa quantità di informazioni pre-elaborate. Possono
essere utilizzati per effettuare processing ad un livello più alto di comprensione semantica oppure per effettuare semplici controlli sul funzionamento
della pipeline esecutiva. Attualmente sono stati implementati molti plugin
DataConsumer, che offrono funzionalità come disegnare bounding box intorno alla regione identificata come movimento, oppure filtrare il movimento,
rilevato dal Motion Detector, sulla base di maschere fornite come parametri
di funzionamento del plugin, oppure eseguire azioni personalizzabili, sempre tramite i parametri di configurazione, al verificarsi di determinati eventi.
2.3 Efficienza
20
Inoltre i vari plugin DataConsumer, essendo invocati in modo sequenziale,
esattamente come sono specificati nei parametri di configurazione del core di
HuMoR, possono essere concatenati opportunamente per fornire dati elaborati al plugin che segue, in maniera totalmente collaborativa, per raggiungere
livelli di elaborazione anche molto complessi.
Nel capitolo 3 verranno discussioni più in dettaglio alcuni plugin DataConsumer.
2.3
Efficienza
Rendere efficiente un framework coinvolge principalmente due aspetti:
• ottimizzare gli algoritmi maggiormente utilizzati
• condividere i dati comuni senza spreco di risorse
Sul primo punto si può fare ben poco in quanto è l’utente stesso a dover
implementare i propri algoritmi ed è quindi affidato all’utente il compito di
implementare algoritmi che siano veloci e quanto più possibile ottimizzati.
Gli algoritmi attualmente presenti dentro HuMoR (Motion Detector e Tracker) hanno subito più volte operazioni di ottimizzazione e al momento attuale
riescono ad avere delle buone performance.
Il secondo punto invece è stato maggiormente analizzato, fino a giungere
alla conclusione che il metodo migliore per non sprecare risorse, fosse passare
l’intero ambiente di lavoro del core di HuMoR a tutti i plugin di tipo DataConsumer e solamente le informazioni necessarie ai plugin Camera, MotionDetector e Tracker, avendo cura di passare tutte le variabili per riferimento8 .
Come si può vedere dagli snapshots presenti nel LISTATO XXX, il metodo
apply() di ogni plugin prende come parametri i riferimenti delle variabili necessarie, mentre il metodo consumeData() dei plugin DataConsumer prende
8
Passare una variabile per riferimento ad una funzione, in C++, consiste nel passare
l’indirizzo di memoria dove il dato è presente, al contrario del passaggio per valore che
crea una copia in memoria del dato da passare alla funzione. Con dati particolarmente
strutturati e complessi, il passaggio per valore causa un grosso spreco di risorse, pur
garantendo l’integrità del dato originale.
2.3 Efficienza
21
come argomento puntatore const all’istanza corrente del core di HuMoR, in
questo modo può accedere a tutte le elaborazioni effettuate dai precedenti
plugin, ma grazie al vincolo const non ha la possibilità di modificarli.
Un altro aspetto tenuto in forte considerazione, nella primissima fase progettuale, è stato di scegliere un linguaggio di programmazione espressivo e
performante. La scelta è ricaduta immediatamente su C++; è un linguaggio
aderente al paradigma della programmazione ad oggetti (OOP), caratteristica fondamentale nell’ottenere una bassa complessità del codice rispetto alla
complessità concettuale che si deve raggiungere, e soprattutto è un linguaggio i cui compilatori, ad esempio la suite Gcc[3]9 per Linux, sono capaci di
ottenere forti ottimizzazioni sul codice binario prodotto.
Non è un caso se la maggioranza dei grossi software e delle librerie attualmente prodotte sfruttino proprio questo linguaggio di programmazione.
9
Implementa la versione definita nello standard ISO 1482 e parte del nuovo 0x.
Capitolo 3
Esemplificazioni dell’utilizzo di
HuMoR
3.1
Rimozione di oggetti da una scena
3.2
Tracciamento di oggetti in movimento
3.3
Rilevazione di percorsi
3.4
Interfaccia di controllo per giochi
3.5
Un Avatar: LIA
Conclusioni
Listings
2.1
Struttura di un Interface Plugin . . . . . . . . . . . . . . . . . 16
Elenco delle figure
2.1
Struttura di un plugin . . . . . . . . . . . . . . . . . . . . . . 15
Bibliografia
[1] Miroslaw Bober. Mpeg-7 visual shape descriptors. 2001.
[2] Spiegazione
su
cosa
è
il
http://www.gnu.org/philosophy/free-sw.it.html.
software
libero.
[3] Gcc, the gnu compiler collection. http://gcc.gnu.org/.
[4] Licenza gnu gpl. http://www.gnu.org/licenses/licenses.it.html.
[5] Ming-Kuei Hu. Visual pattern recognition by moment invariants. 1962.
[6] Homepage dell’ide, integrated development environment, distribuito con
kde. http://www.kdevelop.org/.
[7] Alireza Khotanzad and Yaw Hua Hong. Invariant image recognition by
zernike moments. 1990.
[8] Gilles Labonté.
A som neural network that reveals continuos
displacement fields. 1998.
[9] Spiegazione
tratta
da
wikipedia
http://it.wikipedia.org/wiki/Linux.
[10] David G. Lowe.
keypoints. 2004.
su
cosa
è
linux.
Distinctive image features from scale-invariant
[11] Sito web di the mathworks, azienda produttrice del software matlab.
http://www.mathworks.com.
BIBLIOGRAFIA
[12] Homepage del popolare
http://www.vim.org.
27
editor
di
testo
vim,
vi
improved.