Sunteți pe pagina 1din 46

UNIVERSITATEA “ȘTEFAN CEL MARE”, SUCEAVA

FACULTATEA DE INGINERIE ELECTRICĂ ȘI ȘTIINȚA CALCULATOARELOR


PROGRAM DE STUDIU: CALCULATOARE

PROIECT DE DIPLOMĂ

Achiziția și procesarea mișcării umane folosind senzorul


Microsoft Kinect

Profesor îndrumător: Absolvent:


Prof. univ. dr. ing. Vatavu Radu-Daniel Bercheș Antonela

Suceava 2016
Cuprins
Capitolul 1 – Introducere .............................................................................................................................. 3
1.1 Scopul acestei lucrări ...................................................................................................................... 5
1.2 Structura documentului .................................................................................................................. 6
Capitolul 2 - Senzorul Microsoft Kinect......................................................................................................... 7
2.1 Componentele hardware a senzorului Kinect................................................................................. 8
2.2 Cum funcționează senzorul Kinect .................................................................................................. 9
2.3 Camera RGB .................................................................................................................................. 12
2.4 Senzorul de adâncime ................................................................................................................... 13
2.5 Skeleton tracking........................................................................................................................... 14
2.6 Matricea de microfoane................................................................................................................ 15
2.7 Instalarea și configurarea echipamentului ................................................................................... 16
2.8 Microsoft Kinect SDK..................................................................................................................... 17
2.9 Motorul de înclinație al senzorului Kinect .................................................................................... 21
2.10 Controlul butoanelor................................................................................................................... 22
Capitolul 3 - Platforma de viziune artificială AForge.NET ........................................................................... 23
3.1 AForge.Imaging ............................................................................................................................. 24
3.2 AForge.Vision ................................................................................................................................ 26
Capitolul 4 - Detecția mișcării în secvențe video preluate de la senzorul Kinect ....................................... 30
4.1 Algoritmul SimpleBackgroundModelingDetector de detecție a mișcării (Pseudocod) ................. 31
4.2 Implementarea algoritmului de detecție a mișcării umane (C#) .................................................. 37
4.3 Pregătirea formatului imaginii necesar platformei Aforge.NET ................................................... 40
Capitolul 5 - Detecția mișcării în secvențe Skeleton preluate de la senzorul Kinect .................................. 42
Capitolul 6 - Concluzii.................................................................................................................................. 44
Referințe ..................................................................................................................................................... 46

2
Capitolul 1 – Introducere

În ultimii ani, datorită dezvoltării tehnologice care a implicat diferite sectoare a


Tehnologiei Informației, s-a asistat la un interes crescut cu privire la Ambient Intelligent (AmI).
Este vorba de o disciplină în curs de dezvoltare care își propune să introducă inteligența în
mediile în care omul trăiește. Obiectivul este revoluționarea design-ului mediului domestic, și nu
numai, creând o realitate în care clădirile pot înțelege, prin tehnici de inteligență artificială,
nevoia oamenilor și să se activeze în mod automat pentru a le satisface. Totul fără nevoia de
comenzi explicite din partea unui utilizator uman, care, fără să-și dea măcar seama, se va găsi
înconjurat de o mulțime de tehnologii perfect integrate în obiectele de uz cotidian. Având în
vedere că AmI țintește să se introducă în case, în birouri, pe diferite scene, este evident că
interacțiunea cu omul trebuie să fie una cât mai naturală și cât mai puțin invazivă, astfel încât să
se poată familiariza cu noua tehnologie fără să se simtă amenințat.
Realitatea augmentată este o actualitate care devine din ce în ce mai palpabilă. Senzorul
Kinect al corporației Microsoft s-a dezvăluit a fi o invenție destul de apreciată atât în Statele
Unite cât și în Europa datorită faptului că permite utilizatorului să interacționeze și să comunice
gesturi consolei și computerului folosindu-se doar de propriul corp, fără ajutorul unui controller
fizic. Această tehnologie a revoluționat lumea jocurilor și realitatea virtuală. Kinect-ul a stârnit
curiozitatea multor programatori care lucrează la reverse engineering1 cu scopul de a găsi noi
modalități de folosire al acestui dispozitiv. Cercetările recente din domeniul Computer Vision
s-au focalizat tot mai mult pe crearea de sisteme care să perceapă omul și interacțiunea sa cu
sistemele de calcul, pe dezvoltarea de metode și sisteme computaționale în stare să perceapă
lumea din imagini, într-un mod cât mai apropiat de percepția umană. De altfel, a devenit din ce
în ce mai importantă înțelegerea activității umane dintr-un video. Interesul tot mai mare în
analiza mișcării umane este puternic motivată de îmbunătățirile recente din acest domeniu cât
privește disponibilitatea de echipamente hardware cu cost scăzut, cum ar fi camerele video de
supraveghere și o varietate de noi aplicații promițătoare, cum ar fi sistemele pentru identificarea
unei persoane. Scopul detecției mișcării este de a recunoaște mișcarea obiectelor din imagini.
Mai mult, identificarea obiectelor în mișcare poate contribui la recunoașterea lor. Prin urmare,
obiectivul este identificarea pixelilor care aparțin aceluiași obiect. Orice sistem de detecție a
mișcării bazat pe eliminarea fundalului trebuie să gestioneze o serie de situații critice, cum ar fi:
- zgomotul imaginii, din cauza calității slabe a sursei de imagini;
- variații treptate a condițiilor de iluminare din scenă;
- micile mișcări ale obiectelor non-statice sau pur și simplu prezența de obiecte deranjante în
cadru;
- regiunile umbră sunt proiectate de obiectele din prim-plan și sunt detectate ca obiecte în
mișcare.

1
Reverse engineering sau Inginerie inversă se referă la un proces care constă în analiza detaliată a funcționării,
proiectării și dezvoltării unui obiect (dispozitiv, component electric, mecanism, software, etc) cu scopul de a
produce un nou dispozitiv sau aplicație care să aibă noi funcționalități sau similare, îmbunătățind eficiența sa, fără
a copia nimic din cel original.

3
Această lucrare se inspiră din ambiția AmI de a îmbunătăți viața și confortul omului și de
a crea o lume virtuală în care acesta să fie transpus, având în vedere și evoluția tehnologică din
ziua de azi și a percepției realității. Urmând tendințele actuale, mi-am propus dezvoltarea unui
sistem de monitorizare a omului într-un mediu închis care să achiziționeze și să proceseze
mișcarea umană. Lucrarea de față se bazează pe un algoritm de detecție a mișcării important în
sistemul de securitate deoarece detectează mișcarea într-o anumită zonă. Această aplicație, însă,
poate avea aplicabilitate și în alte domenii precum cel al graficii computerizate. Grafica
computerizată 2D și 3D are multe aplicații în industria de divertisment, în jocurile video și în
producția de film. Datele achiziționate cu tehnologii actuale precum Kinect pot fi procesate și
preluate de alte aplicații în scopul creării de imagini și efecte vizuale dinamice care se mișcă și se
modelează în timp real pe baza mișcării oamenilor din cadru.
În ultimii ani, s-au revoluționat mult și reprezentările TV și cinematografice. Putem lua
ca exemplu scena de la Eurovision Song Contest. Scenografii au folosit luminile ca și
componentă puternică pentru a crea profunzime, s-au focalizat pe expresii mai delicate fără
pixeli și proiecții și au creat iluzii optice folosindu-se de sală și de lumini. Fiecare efect în parte
este unic și oferă ceva nou. Într-un anumit sens scena oferă posibilități nelimitate, dar în același
timp ne obligă să gândim într-un mod diferit. Ea ne transpune într-o altă lume. Creativitatea ne și
provoacă, ne și inspiră. Un proverb chinezesc spune că “O imagine valorează cât o mie de
cuvinte” dar acesta poate fi transpus pentru această eră a computerului astfel “O imagine
valorează mai mult decât câțiva kilobytes de date”. Este firesc să ne așteptăm ca comunicarea
grafică să fie mult mai rezonabilă cât timp computerul este folosit și pentru aceste scopuri, să
reprezinte obiecte în spațiul 2D și 3D. Datele achiziționate cu senzorul Kinect pot fi folosite și în
astfel de reprezentări grafice. Așadar, scenele nu vor mai fi statice și lipsite de creativitate ci vor
transpune publicul într-o nouă dimensiune, în cea virtuală. Interpreții muzicali și trupele vor
putea comunica cu publicul mult mai ușor, iar versurile melodiei vor avea un alt impact.
Interpretarea muzicală va fi una augmentată.
Senzorul Kinect a deschis noi orizonturi nu doar în domeniul jocurilor, dar în general
revoluționează întreaga lume a interacțiunii dintre om-tehnologie, permițând oamenilor să se
raporteze la mașină într-un mod cât mai natural, prin cuvinte și mișcări. Datele achiziționate cu
acest senzor vor putea fi utilizate pe viitor și pentru a îmbunătăți confortul domestic (probabil
prin reglarea automată a luminilor din casă), pentru supravegherea persoanelor cu vulnerabilități
(alertă în caz de comportament neobișnuit sau chiar suport pas cu pas pentru persoanele cu
probleme de memorie care să îi asiste cât timp aceștia se deplasează dintr-o cameră în alta),
pentru monitorizarea siguranței pacienților dintr-un spital (detecție dacă aceștia cad pe jos), în
jocuri video, pentru a controla roboți, în educație, etc.

4
Figura 1.1 Componentele hardware a senzorului Kinect
(http://buildsmartrobots.ning.com/profiles/blogs/building-a-kinect-based-robot-for-under-500-00)

1.1 Scopul acestei lucrări

Scopul acestei lucrări de diplomă este de a achiziționa date video cu privire la mișcarea
umană, cu ajutorul senzorului Kinect și de a le procesa prin algoritmi de detecție cu scopul de a
le folosi ulterior pentru crearea de efecte grafice proiectate pe ecrane de dimensiuni mari la
concerte muzicale. Cu ajutorul unui algoritm de detecție a mișcării am identificat prezența
mișcării apreciată prin zonele de mișcare din cadru și intensitatea mișcării. Intensitatea mișcării
este apreciată cu o valoare din intervalul [0,1], 0 nefiind mișcare (No motion) iar 1 gradul cel
mai mare de mișcare. În cadrul aplicației, algoritmul detectează mișcare când intensitatea este
mai mare de valoarea 0.02. Cu cât intensitatea mișcării este mai mare, cu atât efectul se
mișcă/modelează mai repede. Cu ajutorul coordonatelor zonelor de mișcare transmise, efectul va
apărea în zona aferentă din cadrul canvas-ului efectului. Numărul zonelor de mișcare reprezintă,
în schimb, numărul de obiecte create.

De altfel, am captat și cele 20 de încheieturi ale interpretului muzical de pe scenă și mișcările


acestuia (când ridică mâna dreaptă sau stângă, ambele, sau când acestea nu sunt ridicate).
Aplicația poate transmite toate coordonatele articulațiilor (vezi fig. 2.5.2) pentru a fi transpuse
sub formă de efect sau pentru a le porni.
Senzorul Kinect, pentru a oferi rezultate bune, trebuie mai întâi configurat și calibrat
(vezi Capitolul 2.7 - Instalarea și configurarea echipamentului). In figura 1.2 se poate vedea
modul în care a fost gândită instalarea echipamentelor în cadrul concertului muzical.

5
Figura 1.2 Poziționarea echipamentelor în sală

1.2 Structura documentului

Primul capitol prezintă scopul lucrării și câteva noțiuni introductive referitoare la


problema dată.
Capitolul 2 este dedicat detaliilor tehnice a senzorului Microsoft Kinect, cum
funcționează acesta, modul de preluare a datelor, formatul folosit pentru imagini și detalii
legate de instalarea și configurarea dispozitivului în cameră.
Capitolul 3 prezintă platforma de viziune artificială Aforge.NET și modul de lucru cu
aceasta.
Capitolul 4 conține implementarea și explicația algoritmului de detecție a mișcării
umane din secvențele video preluate de la Kinect, procesarea datelor video și pregătirea lor
pentru formatul cerut de Aforge.NET.
Capitolul 5 explică modul de preluare a scheletului și procesarea acestor date pentru a fi
trimise către aplicația de realizare a efectelor grafice.
În capitolul 6 sunt prezentate rezultatele lucrării, dezvoltările ulterioare și concluziile
referitoare la tema propusă.

6
Capitolul 2 - Senzorul Microsoft Kinect

Kinect este un senzor de mișcare creat de Microsoft Corporation, inițial cunoscut ca


“Project Natal”, prezentat presei pentru prima data în 2009. Termenul Kinect derivă din uniunea
a doi termeni: -kinetic (în română cinetic, adică care ține de mișcare, energic, activ, dinamic) și
–connect (în română conexiune, adică a fi conectat). Acești termeni simbolizează conexiunea
care se dorește a crea între om și mașină. Microsoft a intenționat ca să transforme, cu ajutorul
Kinect-ului, camera de zi în sală de gimnastică, în ring, în discotecă sau stadion, schimbând
modul de divertisment de acasă. Jocurile realizate pentru Kinect ne permit să interacționăm
mișcând mâinile, sărind sau să realizăm forme specifice cu corpul nostru. Senzorul este capabil
să înregistreze mișcările corpului uman în cele trei dimensiuni și să le proceseze în timp real.
După cum jucătorul se mișcă în spațiu, acesta va transforma datele captate în mișcări din lumea
virtuală a jocului. Pe lângă mișcări, dispozitivul are și un sistem de recunoaștere vocală folosit
pentru comenzi vocale și o videocameră care filmează jucătorul în timp ce joacă. Kinect-ul este
sensibil la mișcarea corpului uman, astfel încât, diferit de concurența sa, Wiimote de la Nintendo
sau PlayStation Move de la Sony, face ca jucătorul să fie controller-ul consolei Xbox 360 fără
utilizarea altor instrumente.

Figura 2 Senzorul Microsoft Kinect v1.8


(https://it.wikipedia.org/wiki/Microsoft_Kinect)

Această tehnologie a fost creată, inițial, pentru lumea jocurilor dar poate fi conectat cu un
adaptor și la PC. Există două modele de Kinect: versiunea pentru consola Xbox360 (sau Xbox
One) și versiunea dotată cu SDK (Software Development Kit). Odată instalat driver-ul Microsoft,
acesta oferă accesul la funcțiile audio, video și la senzorii de adâncime ale senzorului. Windows
SDK permite dezvoltatorilor de software să creeze aplicații care suportă recunoașterea vocii și a
gesturilor. Computerul conectat la Kinect cu SDK v1.8 trebuie să aibă un procesor care rulează
pe 32-bit (x86) sau 64-bit (x64) și care are două sau mai multe nuclee fizice cu viteză de
procesare de minim 2.66 GHz, un controller USB 2.0 sau 3.0 dedicat, minim 2GB de memorie
RAM și să fie dotat cu un sistem de operare Windows 7, Windows 8, Windows 8.1 sau Windows
Embedded Standard 7.

7
Caracteristici Microsoft Kinect Kinect One

Producător Microsoft Microsoft


Data prezentării 1 iunie 2009 21 mai 2013
Windows SDK Kinect v1.8 Kinect v2.0
Consola Xbox 360 Xbox One
Rezoluție cameră infraroșu 320x240 pixeli 512x424 pixeli
Rezoluție cameră RGB 640x480 pixeli 1920x1080 pixeli (1080p)
Nr. maxim corpuri
4 persoane 6 persoane
recunoscute simultan
frecvența cardiacă, dispoziția,
Percepție frecvența cardiacă
greutatea și înălțimea utilizatorului
Distanța de captare infraroșu 2,5m 1,4m
Tabel 1: Diferențele dintre Microsoft Kinect și Kinect One

2.1 Componentele hardware a senzorului Kinect

Figura 2.1.1 Poziția senzorilor la Kinect


(https://msdn.microsoft.com/en-us/library/jj131033.aspx)

Senzorul Microsoft Kinect v1.8 este echipat cu:


 Matrice de microfoane multidirecționale cu recunoaștere vocală (3 în dreapta și 1 în
stânga)
 Cameră RGB folosită pentru recunoașterea vizuală a corpului în mișcare, captează
spectrul vizual uman (Color CMOS)
 Senzor dublu de adâncime cu raze infraroșu (emițător-receptor) pentru reconstruirea
imaginii 3D
 Motor de înclinare pentru mișcarea fizică a senzorului Kinect în diferite unghiuri
Captarea imaginii din cadrul proiectului constă în folosirea senzorului CMOS RGB.
Camera RGB are o rezoluție de până la 320 x 240 pixeli, cu o viteză de 12 imagini pe secundă
(FPS – frames per second). Se poate ajunge și la 30 de imagini pe secundă la o rezoluție de
640 x 480 pixeli, cu 8 biți pe fiecare canal. Camera RGB oferă posibilitatea de a efectua filtre de
culoare, operații de saturație a culorilor și echilibrarea automată a albului. Senzorul infraroșu
8
folosește o matrice de 320x240 pixeli. Kinect recunoaște mișcarea până la 48 de puncte în spațiu
și poate recepta mișcările a până la 4 oameni simultan, care stau în picioare sau așezat, la o
distanță de 1,2 m până la 3,5 m și are un unghi de vizualizare de 58 ° orizontal și 45 ° vertical.

2.2 Cum funcționează senzorul Kinect


Senzorii de care dispune dispozitivul îi permite acestuia să urmărească în timp real
mișcările unui om. Este un proces destul de complicat care se folosește de două lucruri
importante: un proiector IR și o cameră IR VGA. Kinect proiectează un laser pe întregul spațiu
capturat. Din acest moment, sarcina este preluată de către cameră, care poate să separe omul de
obiecte (ex. masă) ce sunt considerate “depth field”. Kinect este setat să țină minte trăsăturile
umane (două mâini, două picioare, un cap, etc.) pentru a diferenția al doilea corp uman de un
obiect. După realizarea acestui lucru, Kinect transformă corpul uman într-un schelet cu articulații
și este capabil de acest lucru chiar si atunci când omul este îmbrăcat în haine largi sau are părul
lăsat pe umeri (Figura 2.5.2).

Senzorul Kinect, deci, deduce poziția corpului printr-un proces (Figura 2.2.1) care este format
din următoarele două etape:
Etapa 1: se construiește o hartă de adâncime folosind analiza luminii structurate creată prin
emitorul de infraroșu
Etapa 2: se deduce poziția folosind algoritmi de tracking implementat în softul dezvoltat de
Microsoft.

Figura 2.2.1. Etapele procesului de recunoaștere a poziției corpului efectuat de Kinect

9
Fluxul de date este manevrat ca o succesiune de cadre unice. La momentul inițializării,
dezvoltatorul trebuie să definească ce tipologii de imagini dorește să primească de la dispozitiv.
În particular, există următoarele opțiuni:
 Color: Aplicația necesită accesul la imaginile color (Fig. 2.2.2a)
Aceste imagini color sunt disponibile în două formate: RGB și YUV. Pentru aceste
formate, informațiile vin codate la 32 bit pentru RGB, respectiv la 16 bit pentru YUV.
Rezultă că imaginile YUV ocupă mai puțină memorie, dar sunt disponibile doar cu
rezoluția de 640x480 pixeli și cu o frecvență de 15 cadre pe secundă. Formatul RGB
permite în schimb aceeași frecvență la o rezoluție de 1280x1024, sau 30 FPS pentru o
rezoluție de 640x480.
 Adâncime: Aplicația necesită accesul la imaginile de adâncime (Fig. 2.2.2b).
Senzorul de adâncime întoarce un cadru în care fiecare pixel reprezintă distanța
carteziană, în milimetri, între planul camerei video și obiectul cel mai apropiat de la
coordonatele x și y a pixelului din interiorul Field of View (FOV) a senzorului (figura
2.2.3). O valoare egală cu 0 indică faptul că senzorul nu a găsit nimic în acel punct,
pentru că obiectele în acea zonă sunt prea depărtate sau prea apropiate pentru a putea fi
detectate de senzor. În alte cuvinte, senzorul este “orb” în afara unui interval de distanțe
determinat. Pentru imaginile de adâncime sunt disponibile rezoluțiile 640x480 pixeli,
320x240 pixeli sau 80x60 pixeli.
 Adâncime și indicele persoanelor: Aplicația necesită accesul la imaginile de adâncime
și are nevoie de indicele persoanelor din cadru generat de motorul de tracking (fig.
2.2.2c). Deci motorul de tracking se activează iar pentru fiecare pixel a imaginii de
adâncime sistemul va întoarce, pe lângă distanța măsurată în acel punct, o valoare
întreagă i care indică că acel pixel face parte din silueta persoanei cu indicele i (dacă în
acel punct nu s-a identificat nici o persoană, atunci i=0). În figura 2.2.4 se prezintă un
exemplu de imagine de adâncime în care s-au evidențiat cu culori diferite pixelii pentru
care indicele persoanei este diferită de zero, semn că sistemul a recunoscut în acel punct o
persoană. La persoane diferite vor exista diferiți indici (reprezentați cu culori diferite în
figură).
Kinect poate procesa date input de la senzorul de adâncime pentru a identifica până la
patru figuri umane ce se află în fața senzorului și să creeze ceea ce se numește player
segmentation map. Această hartă este un bitmap în care fiecărui pixel îi este asociat o
valoare ce reprezintă indicele persoanei asignat ei, ce se găsește în câmpul vizual, cel mai
aproape de camera video în acel determinat pixel.
Diferit de ceea ce se întâmplă cu imaginile de adâncime simple, în acest caz este
suportată o rezoluție de 320x240 pixeli.
 Skeleton: Aplicația necesită accesul la informațiile cu privire la poziția încheieturilor
scheletului persoanei din cadru (Fig. 2.2.2d).

Primele două cadre (Color și adâncime) se pot activa și pe doi senzori Kinect în simultan,
conectați la același computer, în timp ce celelalte două doar pentru un Kinect la un

10
moment dat, având în vedere faptul că SDK-ul permite inițializarea unui singur motor de
tracking.

Figura 2.2.2 Cadre preluate de la Kinect: a) color; b) adâncime; c) adâncime și indicele persoanelor; d) skeleton

Figura 2.2.3 Reprezentarea grafică a modului în care senzorul de adâncime


calculează distanța obiectelor în raport cu planul camerei video
(https://blogs.msdn.microsoft.com/msroboticsstudio/2011/11/29/kinect-for-robotics/)

Figura 2.2.4 Imagine de adâncime în care sunt evidențiați cu culori diferite


pixelii la care corespund trei indici a trei persoane diferite

11
2.3 Camera RGB

Camera RGB a senzorului Kinect v1.8 are o rezoluție de


640x480 pixeli și funcționează cu o rată de cadre (framerate) de 30
Hz. Se poate ajunge la o rezoluție și mai mare (1280x1024 pixeli) dar
cu un framerate de 15 Hz. Imaginea captată de această cameră
CMOS 2 este codată ca imagine Bayer pattern3. Senzorii care
funcționează pe acest model nu au aberații cromatice introduse prin
prisma dicroică [12]. Dezavantajul acestor senzori este reducerea
sensibilității (aproximativ 2/3 din lumină este filtrată, deci
nefolosită), pe lângă introducerea unor imagini false (dacă
interpolarea nu vine făcută corect) și reducerea rezoluției efectivă a
componentei culorii.
În figura 2.3.1 se poate vedea cum funcționează filtrul Bayer pattern:
1. Imagine originală
2. Imagine cu o rezoluție de 120x80 pixeli captată de un senzor
cu Bayer4 (fig. 2.3.1 și fig. 2.3.2)
3. Imagine color-codată cu filtrul de culoare Bayer
4. Imaginea reconstruită după interpolarea informațiilor
culorilor lipsă.

Figura 2.3.1 Funcționarea filtrului Bayer pattern


(https://en.wikipedia.org/wiki/Bayer_filter)

2
CMOS – acronimul lui Complementary metal-oxide semiconductor, este o tehnologie utilizată în producerea de
circuite integrate. La senzorul CMOS, fiecare pixel citit are o ieșire individuală pentru a furniza direct un semnal
video de tip digital (diferit de cel CCD – Charge Coupled Device – în care pixelii se citesc în grupuri, prin noduri de
ieșire, pentru a genera semnal video analog în tensiune, care eventual vine apoi transformat în semnal digital de
videocameră). Senzorul CCD este folosit mai mult pentru videocamerele de tip analogic, iar cel CMOS este mai
adecvat pentru videocamerele IP/de supraveghere.
3
Bayer pattern este un model de așezare a filtrelor roșii, verzi și albastre (RGB) peste fotositurile captatorului
camerei digitale. Deoarece ochiul uman este mai sensibil la verde, raportul R:G:B în modelul Bayer este 1:2:1.
Având în vedere că fiecare pixel, în aproape toate camerele/videocamerele cu un senzor, poate primi doar o
singură informație cu privire la cantitatea de lumină, i se pune în față un filtru pentru a capta doar o singură
culoare primară (RGB). Celelalte componente le obține prin interpolare, adică culoarea fiecărui pixel este calculată
folosind valorile pixelilor învecinați .
4
Filtrul Bayer oferă informații despre intensitatea luminii în regiunile de lungimi de undă roși, verzi și albastre
(RGB). Datele brute ale imaginii captate de senzor sunt apoi convertite într-o imagine complet color (cu
reprezentări ale tuturor celor trei culori primare reprezentate la fiecare pixel) de către un algoritm de demozaicare
ce este croit pentru fiecare tip de filtru de culoare.

12
Figura 2.3.2 Dispunerea filtrelor de culoare pe matricea Bayer
(http://www.hatiandskoll.com/2013/04/11/building-a-digital-camera-
sensor-from-a-charge-coupled-device/)

2.4 Senzorul de adâncime


Senzorul de adâncime oferă informații cu privire la cât de departe se află obiectele din
imagine și constă într-un laser infraroșu cu o lungime de undă de 830 nm care proiectează un
model specific de puncte în cadrul său. Camera infraroșu (IR) înregistrează aceste modele a
obiectelor iar DSP (Digital Signal Processor) le calculează distanța cu senzorul prin corelarea
imaginii reale cu modele de referință stocate. Rezultatul elaborării pattern-ului proiectat de IR
este o imagine de adâncime brută (raw depth image), adică valorile de adâncime a unui punct nu
sunt valori exprimate în vreo unitate de măsură; este necesară o procedură de calibrare care pune
în corespondență valorile brute cu valorile exprimate în scară metrică.

Senzorul de adâncime are o rezoluție de 640x480 pixeli. Fiecare pixel deține 11 biți de
informație de adâncime, prin urmare, sunt posibile 2048 (211) valori diferite pentru
reprezentarea distanțelor. Librăriile de acces la imaginea de adâncime permit conversia celor 11
biți de valori în milimetri, în sistemul de coordonate.

13
Figura 2.4.1 Diagrama flux a senzorului de adâncime

Senzorul de adâncime captează o suprafață de aproximativ 0.7 m până la 7 m. Cel mai


bun interval este însă de 1.2 m până la 3.5 m. Câmpul vizual acoperă 58 ° pe orizontal, 45° pe
vertical și 70 ° pe diagonal.

2.5 Skeleton tracking

Skeleton tracking, în documentația de la Microsoft, se referă la operația de localizare a


încheieturilor care descriu poziția figurii umane din cadru. Motorul de tracking oferă informații
despre poziția a până la doi oameni care se află în fața senzorului Kinect. Aceste date se trimit
aplicației ca un set de puncte, denumite skeleton joint (fig. 2.5.1). Aplicația preia datele cu
privire la articulațiile scheletului exact ca și în cadrele cu imagini: invocă o anumită metodă și
trimite un pointer la buffer.

Informațiile despre skeleton joint sunt disponibile până la maxim două persoane (fig.
2.5.2). Pot fi detectate însă și până la un maxim de patru persoane, dar va fi posibil doar un
tracking „pasiv”, adică se va crea și pentru ei un index a persoanelor dar va întoarce doar poziția
centrului de masă calculat pentru persoană în loc de cea a tuturor celor 20 de articulații normal
identificate. Astfel nu se va știi poziția omului, ci doar poziția sa în spațiu.

14
Figura 2.5.1 Poziția încheieturilor, oferite de motorul de tracking, în raport cu corpul uman
(https://blogs.msdn.microsoft.com/msroboticsstudio/2011/11/29/kinect-for-robotics/)

Figura 2.5.2 Tracking activ pentru doi oameni


(http://www.deviak.com/category/Programming/Kinect)

2.6 Matricea de microfoane

Senzorul Kinect conține o matrice de microfoane cu 4 canale, cu ADC5, care rulează la o


rezoluție de 24 biți și are o rată de eșantionare de 16 kHz. Din cauza ratei mici de eșantionare și a
frecvenței de tăiere6 de circa 8kHz, microfoanele sunt folosite în principal pentru a înregistra
vocea și pentru a detecta comenzi vocale. Cele 4 microfoanele cu electret [14] sunt localizare pe
bara senzorului, în spatele unui grilaj, pe partea de jos. Microfoanele recunosc vocea și în

5
Convertor analog-digital (din engleza Analog-Digital Converter)
6
Frecvența de tăiere este un parametru definitoriu a filtrelor electrice trece-jos și trece-sus [13].

15
prezența gălăgiei sau al ecoului și pot capta sunetul de la mai multe persoane care vorbesc din
mai multe direcții și poziții. Microfoanele sunt plasate în poziții diferite pentru a putea
recunoaște de unde vine sunetul și distanța de la sursă. Dat fiind faptul că microfoanele se află în
locuri diferite, sunetul va ajunge la fiecare microfon la diferite intervale de timp. Odată ce sursa
și poziția sunetului sunt calculate, toate părțile audio de la cele patru microfoane se unesc și
produc un semnal cu un sunet de înaltă calitate. Unghiul de captare a sunetului se află în
domeniul [-50°, +50°] (fig. 2.6.1). Calculul unghiului se bazează pe coordonatele camerei
Kinect, unde x și y definesc planul orizontal. Un număr negativ indică faptul că sursa audio se
află în partea dreaptă a senzorului, o valoare pozitivă înseamnă că este în partea stângă iar zero
indică că sursa este în față senzorului, central.

Figura 2.6.1 Unghiurile de captare a sunetului


(https://www.safaribooksonline.com/library/view/kinect-for-windows/9781849692380/ch07s09.html)

2.7 Instalarea și configurarea echipamentului


De multe ori, la aplicațiile care fac recurs la viziunea artificială este nevoie să se
cunoască:

 Cunoașterea poziției obiectului în lumea reală.


 Cunoașterea exactă a dimensiunii a ceea ce se încadrează
Pentru a putea obține rezultate bune în urma achiziției datelor, senzorul Kinect trebuie poziționat
într-un cadru bine precis. În urmă rezultatelor experimentale obținute și a testelor empirice, s-au
tras următoarele concluzii:
- pentru o urmărire a mâinii, utilizatorul trebuie să se afle la o distanță de minim 1.8 m și maxim
2.5 m față de senzorul Microsoft Kinect, dar, aplicația, pe baza API-ului oferit de Microsoft nu
poate detecta degetele mâinii, astfel nu poate fi folosită în recunoașterea de gesturi complexe din
cauza rezoluției mici a senzorului Microsoft Kinect v1.8, dar, funcționează, totuși, foarte bine în
cazul în care se dorește urmărirea corpului uman;
- pentru a obține performanțe și mai bune, senzorul Kinect trebuie să se afle la o înălțime de
0.6m până la 2m. Poziția orizontală ideală, în schimb, este în fața scenei, pe centru.

16
- senzorul de recunoaștere tridimensională a senzorului folosește o combinație de laser și
infraroșu, tehnologii care nu depind de lumina vizibilă, deci se pot utiliza și în întuneric. În
schimb, camera RGB necesită o luminozitate bună a cadrului; nu funcționează corect într-un
mediu afectat direct de lumina soarelui, o suprafață reflectorizantă, sau o interferență cu lumina
cu o lungime de undă similară (aproximativ 830 nm).

2.8 Microsoft Kinect SDK

După cum am menționat și mai sus, Microsoft Kinect este un dispozitiv utilizabil și în
combinație cu computerul, nu doar cu consola de jocuri. SDK-ul oficial oferit de Microsoft
permite folosirea sa și dezvoltarea de aplicații bazate pe Kinect exclusiv pentru computerele
dotate cu sistemul de operare Windows. SDK-ul oficial a fost publicat de Microsoft în 2011 și
cuprinde o librărie care poate prelua și gestiona fluxul de date ce provine de la senzorii
dispozitivului și poate fi folosit atât în C++ cât și în unul din limbajele Managed din platforma
.NET. Mediul de dezvoltare necesar pentru folosirea acestui SDK este Microsoft Visual Studio.

Figura 2.8.1 Schemă conceptuală a SDK-ului de la Microsoft (https://msdn.microsoft.com/en-us/library/jj131023.aspx)

Driverele din Windows 7 au următoarele funcționalități:


- Permit accesul la matricea de microfoane cu ajutorul API-ului Audio Standard din
Windows
- Preiau cadrele de la camera video și de la senzorul de adâncime
- Oferă posibilitatea utilizării mai multor dispozitive simultan.

NUI (Natural User Interface) library este o librărie de bază a senzorului Kinect pentru Windows
API. Aceasta permite preluarea datelor de la senzorii de imagine și de la microfoane și
controlează dispozitivul (de exemplu inclinația echipamentului). Aplicațiile oferite de Microsoft,
în schimb, folosesc librăriile grafice DirectX, folosite exclusiv în sistemele de operare Windows,
ceea ce limitează portabilitatea aplicațiilor dezvoltate.
Aplicația prezentată în această lucrare a fost dezvoltată în mediul de dezvoltare Microsoft
Visual Studio 2015, în platforma .NET cu versiunea 4.5, în aplicația WPF (Windows
Presentation Foundation).
În cadrul proiectului am integrat librăria Microsoft.Kinect.dll din cadrul SDK-ului de la
Microsoft pentru a putea accesa secvențele video de la senzor, astfel:
using Microsoft.Kinect;

17
Variabila senzorului este globală și ne permite să activăm senzorul Kinect oriunde în program:
private KinectSensor sensor;
și de un Bitmap care va reține informația culorii:
private WriteableBitmap colorBitmap;
WriteableBitmap este o imagine sursă de tip bitmap care poate fi scrisă și actualizată. Bitmap-ul
reprezintă o mulțime de pixeli cu o anumită dimensiune și rezoluție. WriteableBitmap este adesea
folosit în loc de bitmap-urile normale deoarece este mai rentabil (din punct de vedere al costului
resurselor în memorie) și mai bune pentru streaming video. În alte cuvinte, WriteableBitmap este
o imagine care este actualizabilă, fără a fi nevoie creerea unei noi variabile la fiecare cadru.
Această imagine scrie noi octeți pentru a actualiza interfața utilizator.

Proprietatea KinectSensor.KinectSensors preia senzorii Kinect care sunt conectați la momentul


pornirii aplicației și îi pornește:
foreach (var potentialSensor in KinectSensor.KinectSensors)

{
if (potentialSensor.Status == KinectStatus.Connected)
{
this.sensor = potentialSensor;
break;
}
}

Primul lucru care trebuie făcut, după pornirea Kinectului este să se specifice care flux de date
(video color, de adâncime, date de tip skeleton, etc.) se dorește să se folosească, la ce rezoluție și
la câte cadre pe secundă:
this.sensor.ColorStream.Enable(ColorImageFormat.RgbResolution640x480Fps30);

În acest moment, camera video este pregătită pentru a furniza date imediat ce se pornește
senzorul:
this.sensor.Start();

În mod similar, se poate opri camera video a senzorului folosind metoda Stop().
Există două moduri de a prelua date de la senzor: modelul polling și cel bazat pe evenimente.
Metoda polling cere să se inspecteze o stare a flag-urilor, la intervale regulate, pentru ca datele să
fie gata pentru noi cadre. Această metodă este simplă dau nu prea eficientă și flexibilă. Cu
metoda bazată pe evenimente, fiecare senzor declanșează un eveniment când un nou cadru de
date este disponibil. Pentru a o folosi, trebuie să definim un event handler pentru
AllFramesReady. După cum sugerează și numele, acesta se apelează de fiecare dată când un
cadru video este gata pentru a fi procesat. Evenimentul poate fi utilizat astfel:
_sensor.AllFramesReady += Sensor_AllFramesReady;

Event handler trebuie însă să aibă o semnătură aparte:


private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)

18
Imaginea bitmap captată de sensor se află în argumentul evenimentului. Pentru a o folosi, se
poate trece prin două etape:
1. Să se folosească metoda OpenColorImageFrame pentru a prelua obiectul
ColorImageFrame
2. Să se folosească metoda CopyPixelDataTo pentru a prelua matricea de bytes a datelor
pixelilor.
Primul lucru în cadrul event handler-ului este să se obțină obiectul ColorImageFrame,
private void SensorColorFrameReady(object sender, ColorImageFrameReadyEventArgs e)
{
using (ColorImageFrame colorFrame = e.OpenColorImageFrame())
{
//...
}
}

să se copieze datele pixelilor din imagine într-un array temporar:


colorFrame.CopyPixelDataTo(this.colorPixels);

și să se scrie aceste date într-un bitmap:


this.colorBitmap.WritePixels(new Int32Rect
(0, 0, this.colorBitmap.PixelWidth, this.colorBitmap.PixelHeight), this.colorPixels,
this.colorBitmap.PixelWidth * sizeof(int), 0);
Acest bitmap poate fi convertit în alte formate pentru a fi afișat și procesat.

Cât privește preluarea datelor de la schelet (Skeleton), pentru a permite skeletal tracking,
se va apela metoda SkeletonStream.Enable(). Se poate accesa proprietatea
KinectSensor.SkeletonStream din clasa KinectSensor. Pentru a primi informații despre
recunoașterea omului în cadru, se va folosi evenimentul KinectSensor.SkeletonFrameReady sau
KinectSensor.AllFramesReady din clasa KinectSensor.
private KinectSensor sensor;

void StartKinectST()
{
sensor = KinectSensor.KinectSensors.FirstOrDefault(s => s.Status ==
KinectStatus.Connected);
sensor.SkeletonStream.Enable();
skeletonData = new Skeleton[sensor.SkeletonStream.FrameSkeletonArrayLength];
sensor.SkeletonFrameReady += new
EventHandler<SkeletonFrameReadyEventArgs>(kinect_SkeletonFrameReady);
sensor.Start();
}

Pentr a accesa informațiile despre Skeleton se vor folosi următoarele linii de cod:
private void kinect_SkeletonFrameReady(object sender, SkeletonFrameReadyEventArgs e)
{
using (SkeletonFrame skeletonFrame = e.OpenSkeletonFrame())
{
if (skeletonFrame != null && this.skeletonData != null)

19
skeletonFrame.CopySkeletonDataTo(this.skeletonData);
}
}
}

La fiecare eveniment KinectSensor.SkeletonFrameReady sau KinectSensor.AllFramesReady se


deschide cadrul și se apelează metoda SkeletonFrame.CopySkeletonDataTo pentru a copia datele
într-un array de obiecte Skeleton. Este recomandată refolosirea aceluiași array fără a se aloca
unul nou pentru fiecare cadru.
După cum am menționat și mai sus, Kinect v.1.8 poate prelua în mod „activ” scheletul cu
cele 20 joncțiuni de la maxim 2 persoane care se află în fața senzorului. Scheletului dintr-un
cadru i se poate determina starea (dacă este identificat sau nu) sau numai poziția sa (fără detaliile
despre încheieturi). Pentru a accesa datele despre schelet, trebuie să se acceseze obiectul
Skeleton returnat în fiecare cadru și să se verifice TrackingState, care poate fi Tracked,
PositionOnly sau NonTracked. Pentru tracked skeletons, o matrice de joncțiuni oferă poziția a 20
de încheieturi ale corpului uman recunoscute în spațiu. De exemplu, aplicații pot folosi
încheietura mâinii pentru a ghida un cursor pe ecran sau pentru a desena poziția corpului.
private void DrawSkeletons()
{
foreach (Skeleton skeleton in this.skeletonData)
{
if (skeleton.TrackingState == SkeletonTrackingState.Tracked)
{
DrawTrackedSkeletonJoints(skeleton.Joints);
}
else if (skeleton.TrackingState == SkeletonTrackingState.PositionOnly)
{
DrawSkeletonPosition(skeleton.Position);
}
}
}

Clasa Joint are un TrackingState care poate fi accesat pentru fiecare joncțiune a scheletului.
De exemplu, se pot prelua datele despre cap astfel:
private void DrawBonesAndJoints(Skeleton skeleton, DrawingContext drawingContext)
{
this.DrawBone(skeleton, drawingContext, JointType.Head, JointType.ShoulderCenter);

Aceste joncțiuni se pot desena de altfel pe imaginea RGB.


Când un utilizator se mișcă pe marginea câmpului vizual, sistemul de tracking a
scheletului avertizează aplicația că scheletul acestuia este decupat. Această informație poate fi
folosită de aplicație pentru a spune utilizatorului să se mute pe centru scenei ca să obțină o
monitorizare mai bună.
Proprietatea ClippedEdges verifică dacă valoarea enumerației FrameEdges este Bottom, Top,
Left sau Right. De exemplu, verificarea scheletului în zona Bottom:

20
private static void RenderClippedEdges(Skeleton skeleton, DrawingContext
drawingContext)
{
if (skeleton.ClippedEdges.HasFlag(FrameEdges.Bottom))
{
drawingContext.DrawRectangle(
Brushes.Red, null,
new Rect(0, RenderHeight - ClipBoundsThickness, RenderWidth,
ClipBoundsThickness));
}

Figura 2.8.2 Captură ColorStream și SkeletonStream

SDK-ul Microsoft pentru Kinect permite și selectarea utilizatorului în harta de adâncime.

2.9 Motorul de înclinație al senzorului Kinect


Librăria Microsoft.Kinect permite senzorului și reglarea nivelului de ridicare a câmpului
vizual cu ajutorul motorului de înclinație. Acest nivel este setat de proprietatea
KinectSensor.ElevationAngle. Valorile se calculează în grade și este limitat de valorile
MinElevationAngle și MaxElevationAngle. Unghiul de înclinare verticală este de ±27°, ceea ce
face ca volumul înconjurat de câmpului vizual să se dubleze efectiv. Înclinația este legată de
centrul de gravitație și nu de baza senzorului. Un unghi de ridicare egal cu zero indică faptul că
senzorul Kinect este orientat perpendicular pe centrul de gravitație. Unghiul este supus
limitărilor fizice ale senzorului. Dacă baza senzorului se sprijină pe o suprafață înclinată,
mijlocul domeniului de înclinație al senzorului nu va corespunde cu unghiul de ridicare egal cu
zero, iar senzorul poate să nu fie capabil fizic să ajungă la limitele exterioare ale domeniului
permise de API.

Dacă senzorul este deplasat astfel încât baza să fie la un unghi diferit față de gravitație, sau dacă
senzorul este înclinat manual, unghiul raportat de API se va schimba, chiar dacă unghiul de
ridicare nu a fost modificat în mod programatic.

21
Pentru a înclina în sus motorul, se va folosi următorul cod:
sensor.ElevationAngle += 4;

Respectiv, sensor.ElevationAngle -= 4; pentru a coborâ motorul de înclinație.


Este recomandat ca să nu se încline senzorul Kinect prea des, pentru a minimiza uzura și
a reduce timpul de înclinare. Motorul de înclinare nu este proiectat pentru mișcări constante sau
repetitive. Pentru a reduce uzura, aplicația nu trebuie să schimbe unghiul de ridicare mai mult
decât o dată pe secundă. Este bine să existe și o pauză de 20 de secunde după fiecare 15
schimbări consecutive. Dacă aplicația întrece această limită, motorul de înclinare se poate bloca
și vor apărea erori în cod.

2.10 Controlul butoanelor

Librăria Microsoft.Kinect.Toolkit.Controls permite utilizatorului interacțiunea la distanță


cu computerul. Această componentă conține controale WPF pentru interacțiunile Kinect care se
bazează pe gesturi (apăsarea unui buton, interacțiuni de prindere/lăsare și derulare, vizualizare
imagini) și sunt concepute pentru controlul cu mâna liberă a aplicațiilor și a altor forme de
interactivitate.
Pentru a prelua mișcarea mâinii, senzorul se folosește de imaginea de adâncime. La o anumită
distanță inițială a omului față de senzor, acesta va detecta imagine de adâncime și deci și distanța
față de mâna utilizatorului iar pe ecran va apărea o mână (figura 6.2). Când mâna (dreaptă sau
stângă, fără nici o diferență) se apropie de senzor, controlul de pe interfață, din zona mâinii, va fi
apăsat iar evenimentul creat se va declanșa. Pentru derularea paginilor, mâna va trebui să facă
gestul de închidere a mâinii.

22
Capitolul 3 - Platforma de viziune artificială AForge.NET
AForge.NET este o platformă de inteligență artificială dezvoltată în 2012 de Andrew
Kirillov pentru .NET Framework. Librăria este open source, scrisă în C#, dezvoltată pentru
programatorii și cercetătorii din domeniul viziunii și inteligenței artificiale.

Platforma conține mai multe librării, grupate pe mai multe categorii:


 AForge.Imaging – cea mai mare librărie a platformei; conține cod pentru procesare de
imagine care ajută la îmbunătățirea imaginii (de exemplu: filtrarea culorii liniare și
neliniare, filtrarea pixelilor de culoare, reducerea culorii, detecția frontierelor în imagini,
etc. )
 AForge.Vision – constă în algoritmi de detectare a mișcării și de procesare a mișcării
 AForge.Math – conține diferiți algoritmi matematici (de exemplu: algoritmul lui Graham
sau algoritm de detectare a formelor, etc.)
 AForge.Video – are diferite clase care oferă accesul la datele video (de exemplu: accesul
la fluxul JPEG și MJPEG, citirea/scrierea fișierelor, suport pentru senzorul Microsoft
Kinect, etc.)
 AForge.Robotics – conține clase care controlează unii roboți (de exemplu: kitul de
robotică Lego Mindstorm RCX și NXT, placa Qwert, etc.)
 AForge.Neuro – include implementarea unor arhitecturi comune de rețele neuronale și
algoritmi de învățare: rețele de la distanță, funcții de activare precum threshold, sigmoid,
sigmoid bipolar și alți algoritmi de învățare
 AForge.Genetic – clasele acestei librării au scopul de a rezolva diferite operații din ariile
Algoritmi genetici (GA - Genetic Algorithms), Programarea genetică (GP – Genetic
Programming) și Programarea expresiilor genetice (GEP – Gene Expression
Programming). Clasele conțin algoritmi de selecție (elită, rang), cromozomii GA (binari,
short array și double array) și altele.
 AForge.Fuzzy – această librărie este formată din diferite clase care efectuează calcule
fuzzy și sisteme cu logică nuanțată
 AForge.MachineLearning – conține câteva clase din domeniul machine learning (de
exemplu: algoritmii Qlearning și Sarsa learning, Bolzmann, Epsilon greedy și altele.
 AForge.Video.Kinect – conține clase care permit accesul la cadrele video și la datele de
adâncime ale senzorului Microsoft Kinect (vezi figura 3.1).
 Și altele…

Platforma este în curs de perfecționare constantă și vine și cu câteva exemple aplicative.

23
3.1 AForge.Imaging
Pentru a folosi această librărie trebuie adăugată în lista de referințe și în namespace-ul din cadrul
proiectului:

using AForge.Imaging;

Aplicația ImageViewer prezintă vizualizarea nu doar a formatelor imaginii suportate de


platforma .NET, dar și alte formate, suportate de spațiul de nume AForge.Imaging.Formats (de
exemplu formatul FITS, creat de NASA, folosit pentru imagini științifice și permite includerea în
fișier a unor informații de calibrare fotometrică și spațială). Pe lângă vizualizarea imaginii,
aplicația constă și în unele informații despre imagine, preluată din fișierul
imagine. Pot fi informații generice dar și specifice, cum ar fi tipul de
telescop folosit pentru observarea obiectului (fig. 3.1.1).

Figura 3.1.1 Vizualizarea unei imagini cu format .fit și a informațiilor sale


Figura 3.1.2 Diferite filtre de imagine din
spațiul de nume AForge.Imaging.Filters

Această librărie conține clase și interfețe pentru diferite implementări ale procesării de imagini
printre care Image (metode de bază legate de imagine), BlobCounter (calculează obiectele din
imagine, care sunt separate de fundal negru), Drawing (tratează primitivele grafice), RGB
(componentele RGB), UnmanagedImage (imagini din resursele unmanaged), etc.
Aplicația demonstrativă Filters Demo prezintă diferite filtre de imagine și cum pot ele fi aplicate
pe o imagine. În figura 3.1.2 se poate vedea o listă cu aceste filtre din spațiul de nume
AForge.Imaging.Filters. Filtrele sunt din diferite domenii, cum ar fi filtrarea culorilor, corecția
nivelelor culorilor, filtre de convoluție, filtre de detecție a frontierelor, filtre de binarizare, etc.

24
Figura 3.1.3 Imaginea originală în stânga, respectiv filtrul Invert aplicat în dreapta

Aplicația Blobs Explorer (figura 3.1.4) prezintă clasa BlobCounter care permite găsirea
tuturor obiectelor separate dintr-o anumită imagine. Aceasta găsește fiecare obiect în parte, îi
oferă proprietăți și cu ajutorul altor clase ale platformei i se poate da imaginii un tip de
evidențiere: convex hull, marginile stânga/dreapta, marginile sus/jos sau marginile de tip
patrulatere (dacă obiectul este într-adevăr un patrulater, atunci marginile sale ar trebui să fie
găsite cu bună precizie).

Figura 3.1.4 Aplicația Blobs Explorer

Mai sunt și alte aplicații demonstrative în cadrul acestei librării, de exemplu Texture
Demo care prezintă utilizarea diferitelor generatoare de textură din spațiul de nume
AForge.Imaging.Textures cum ar fi lemn, marmură, nori, Hough Transformation care poate fi
aplicat pentru detectarea liniilor drepte și a cercurilor cu o anumită rază sau Shape Checker care
permite detectarea unor forme geometrice simple (triunghi, pătrat, dreptunghi, cerc sau alte
patrulatere).

25
3.2 AForge.Vision
Dezvoltatorii platformei AForge.NET au oferit și un exemplu de aplicația Motion
Detector care experimentează diferiți algoritmi pentru detectarea mișcării. Algoritmii sunt
implementați în spațiul de nume AForge.Vision.Motion.

Cu această aplicație se poate activa/dezactiva detecția mișcării, se pot experimenta diferiți


algoritmi de post-procesare a mișcării, cum ar fi evidențierea regiunilor de mișcare sau calculul
numărului de obiecte în mișcare. Aceasta suportă diferite surse video, cum ar fi camera web,
instantanee JPEG și fluxuri MJPEG pe HTTP (cameră de supraveghere) și fișiere video locale.
Mai mult, permite specificarea regiunilor de interes unde ar trebui detectată mișcarea. Aplicația
poate să și arate istoricul mișcării (o diagramă în partea de jos) care prezintă nivelul de mișcare
detectată până în acel moment (figura 3.2.2).

Figura 3.2.1 Diagrama ce reprezintă istoricul mișcării

Clasele pentru detecția și procesarea mișcării oferite de AForge.Vision.Motion sunt următoarele:


 BlobCountingObjectsProcessing
 CustomFrameDifferenceDetector
 GridMotionAreaProcessing
 MotionAreaHighlighting
 MotionBorderHighlighting
 MotionDetector
 SimpleBackgroundModelingDetector
 TwoFramesDifferenceDetector

a) Algoritmi de detecție a mișcării


 Algoritmul TwoFramesDifferenceDetector (figura 3.2.3) se bazează pe diferența dintre
două cadre consecutive. Clasa implementează cel mai simplu și cel mai rapid algoritm de
detecție a mișcării. Cu cât diferența dintre cadre este mai mare, cu atât este mai mare
nivelul de mișcare. Diferitele cadre sunt segmentate (thresholded) iar apoi se calculează
cantitatea de pixeli diferență. Proprietatea SuppressNoise, la fel ca și în algoritmul
CustomFrameDifferentDetector, suprimă imaginile zgomotoase și aplică operatorul
morfologic de eroziune. Deși clasa poate fi utilizată ca atare pentru a efectua detecția

26
mișcării, este de preferat să fie folosită în combinație cu clasa MotionDetector, care oferă
caracteristici suplimentare și permite folosirea algoritmilor de post-procesare a mișcării.
Acest algoritm nu este prea adecvat pentru acele operații care cer o evidențiere precisă a
obiectelor în mișcare. Este însă recomandat pentru acele operații care doar solicită
detecția mișcării.

Figura 3.2.3 Evidențierea zonelor de mișcare detectate cu ajutorul algoritmului TwoFramesDifferenceDetector


(stânga: Motion Area Highlighting; dreapta: Grid Motion Area Processing)

 Algoritmul SimpleBackgroundModelingDetector (figura 3.2.4) se bazează pe


modelarea fundalului în funcție de obiectele în mișcare din cadru. În contrast cu ceilalți
doi algoritmi de mai sus, acesta se bazează pe găsirea diferenței dintre cadrul video
curent și un cadru care reprezintă fundalul. Acest detector de mișcare încearcă să
folosească tehnici simple de modelare a fundalului din cadru și să îl actualizeze din când
în când pentru a lua în calcul schimbările scenei. Caracteristica de modelare a fundalului
oferă abilitatea unei mai mare precizii la evidențierea zonelor de mișcare. Mai multe
detalii se pot găsi în Capitolul 4 - Detecția mișcării în secvențe video preluate de la
senzorul Kinect.

Figura 3.2.4 Evidențierea zonelor de mișcare detectate cu ajutorul algoritmului SimpleBackgroundModelingDetector. Evidențiere
de tip: a) Motion Border Highlighting; b) Blob Counting Processing; c) Motion Area Highlighting; d) Grid Motion Area
Processing

27
 Algoritmul CustomFrameDifferentDetector se bazează pe diferența dintre un cadru
video curent și fundal unui cadru predefinit. Diferitele cadre se segmentează
(thresholded) și se calculează cantitatea de pixeli diferență. Proprietatea SuppressNoise
suprimă imaginile zgomotoase și aplică operatorul morfologic de eroziune. Proprietatea
KeepObjectsEdges poate fi utilizată pentru a restabili marginile după suprimarea
imaginii. Dacă nu se specifică cadru de fundal predefinit cu metoda
SetBackgroundFrame(Bitmap), algoritmul va lua primul cadru video ca și fundal și va
calcula diferența altor cadre video cu acesta. Diferit de algoritmul
TwoFramesDifferenceDetector, CustomFrameDifferentDetector identifică obiectele care
nu fac parte din fundal (scenă) mult mai clar. Pe de o parte, acest algoritm este rapid
pentru ca se bazează pe o diferențiere simplă ca și cel care detectează diferența dintre
două cadre diferite. Pe de altă parte, însă, diferențiază cadrul video curent cu cadrul de
fundal, care ar putea permite identificarea obiectelor în mișcare dar nu și zonele de
schimbare (ca în algoritmul SimpleBackgroundModelingDetector). Cu toate acestea,
utilizatorul trebuie să specifice cadrul de fundal (sau algoritmul va lua primul cadru video
ca și cadru de fundal) iar algoritmul nu va încerca niciodată să se actualizeze pe diferite
cadre, ceea ce înseamnă că nu există adaptare la schimbări de scene.

b) Algoritmi de procesare a mișcării


 Algoritmul GridMotionAreaProcessing (vezi figura 3.2.4(d)) face procesarea grilajului
a cadrului de mișcare. Adică întreg cadru de mișcare va fi împărțit printr-o grilă într-un
anumit număr de celule iar nivelul mișcării se calculează pentru fiecare celulă. Informația
fiecărei celule despre nivelul mișcării poate fi preluată folosind proprietatea MotionGrid.
Proprietatea reprezintă o matrice de dimensiunea GridHeight x GridWidth (amândouă
valori sunt în mod predefinit setate la 16) care păstrează nivelul mișcării fiecărei celulei a
grilei. Dacă o anumită celulă are nivelul de mișcare egal cu 0.2, înseamnă că acea celulă
conține 20% din totalul schimbării. Algoritmul poate să și evidențieze acele celule care
au nivelul de mișcare peste un anumit prag. Pentru aceasta, este necesară setarea la true a
proprietății MotionAmountHighlight. Valoarea predefinită este setată la 0.15.
 Algoritmul MotionAreaHighlighting (vezi figura 3.2.3(stânga) și figura 3.2.4(c))
evidențiază zona de mișcare cu modele grilă de o anumită culoare specificată (predefinit
este culoarea roșu).
 Algoritmul MotionBorderHighlighting (vezi figura 3.2.4(a)) evidențiază doar marginile
zonei de mișcare cu o anumită culoare (predefinit este culoarea roșu). Acest algoritm se
presupune a fi utilizat numai cu algoritmi de detecție a mișcării care se bazează pe
identificarea diferenței cu cadrul de fundal (de exemplu algoritmul
SimpleBackgroundModelingDetector și CustomFrameDifferenceDetector) și permite
extragerea clară a obiectelor în mișcare.
 Algoritmul BlobCountingObjectsProcessing (vezi figura 3.2.4(b)) numără obiectele
care se mișcă în cadru și le evidențiază cu un dreptunghi de o anumită culoare . Aceste
obiecte sunt asigurate de interfața IMotionDetector. Algoritmul calculează și evidențiază

28
doar acele obiecte care satisfac dimensiunile limită a proprietăților MinObjectWidth și
MinObjectHeight.

Toate aceste clase pun în aplicare o interfață destul de simplă și comună, independent de
fluxul video sau format. Clasele doar analizează cadre video consecutive oferite de utilizator.
Clase diferite de detecție a mișcării pot folosi diferiți algoritmi pentru a detecta mișcarea. Dar
toate sunt similare în modul în care preiau cadrele video. Toate clasele conțin proprietăți despre
nivelul mișcării, care se află în domeniul [0,1]. De exemplu, dacă proprietatea este setată la 0.05
înseamnă că clasa a detectat 5% din nivelul total de mișcare. Analizând această proprietate și
comparând-o cu praguri predefinite, se poate da o alarmă, când nivelul mișcării detectate este
mai mare decât nivelul considerat în siguranță.
Pentru a extinde funcționalitățile acestei platforme, s-a creat proiectul Accord.NET. Mai
există și alte platforme open source de viziune artificială, cum ar fi OpenCV sau EmguCV. Deși
amândouă (AForge.NET și OpenCV) au cam aceleași funcționalități, AForge.NET conține mai
multe filtre și este adecvată pentru diferite transformări și manipulări de imagine, dar pare a fi
săracă în celelalte domenii (de exemplu operații cu matrice folosite mult în viziunea artificială).
OpenCV în schimb, are mai multe funcționalități dar este puțin mai complicat de programat cu
ea. EmguCV pare să aibă cele mai bune actualizări dar documentația nu este așa bogată.

29
Capitolul 4 - Detecția mișcării în secvențe video preluate de la senzorul
Kinect
Primul lucru realizat în procesarea imaginii capturate de către Kinect a fost alegerea
algoritmului cel mai eficient necesar rezolvării problemei mele, și anume algoritmul
SimpleBackgroundModelingDetector care face parte din librăria AForge.NET.
public class SimpleBackgroundModelingDetector : IMotionDetector

Clasa SimpleBackgroundModelingDetector implementează un algoritm de recunoaștere a


mișcării din secvența video, bazat pe diferența dintre cadrul curent și cadrul fundalului modelat.
Cadrul de diferență este segmentat (thresholding) iar cantitatea de pixeli diferență este calculată.
Inițial se ia primul frame capturat de Kinect ca și cadru de fundal. În timpul procesării video,
acesta este actualizat în mod constant, astfel încât se schimbă în sensul micșorării diferenței cu
cadrul video curent (cadrul de fundal este deplasat spre cadrul curent). Acest algoritm determină
coordonatele zonelor unde se face mișcarea. Pentru a suprima imaginile zgomotoase, se poate
aplica operatorul morfologic de erodare care este controlat de proprietatea SuppressNoise a
clasei. Prin erodare, fiecare pixel al obiectului care “atinge” fundalul este transformat în pixel-
fundal. Astfel, erodarea face obiectele mai mici și poate împărți un obiect mai mare în mai multe
obiecte mici. În cazul în care sunt necesare frontierele precise ale zonei în mișcare (ex. pentru
prelucrarea mișcării ulterioare) se poate folosi proprietatea KeepObjectsEdges pentru a restabili
frontierele după suprimarea zgomotului imaginii. Valoarea implicită este setată la false. Valoarea
parametrului KeepObjectsEdges specifică dacă filtrarea suplimentară trebuie făcută pentru a
restaura marginile obiectelor, după ce zgomotul imaginii a fost suprimat prin aplicarea filtrului
de dilatare 3x3 a procesării imaginii. La dilatare, fiecare pixel din fundal aflat în contact cu
obiectul este transformat în pixel-obiect. Astfel, dilatarea face obiectele mai mari și poate uni
mai multe obiecte. Trebuie luat în considerare faptul că schimbarea valorii parametrului la true
va duce la un timp mai mare de procesare a imaginii.

Librăria AForge.NET conține mai mulți algoritmi de detecție a mișcării. În cadrul


proiectului am ales algoritmul cel mai eficient pentru problema mea. Diferit de
TwoFramesDifferenceDetector, algoritmul SimpleBackgroundModelingDetector permite
identificarea destul de clară a obiectelor care nu fac parte din fundal (obiectele care, cel mai
probabil, sunt în mișcare). Comparativ cu CustomFrameDifferenceDetector, algoritmul folosit în
cadrul proiectului include și un mod de adaptare a fundalului, fapt ce-i permite să-și actualizeze
cadrul de fundal modelat pentru a lua în considerare scenele ce se schimbă. Datorită
caracteristicii de adaptare, algoritmul se poate adapta la modificările de fundal, ceea ce cu
algoritmul CustomFrameDifferenceDetector nu se poate face. Cu toate acestea, dacă obiectul în
mișcare se află în cadru pentru un timp (algoritmul nu-l tratează ca obiect nou în mișcare) iar
apoi se mișcă din nou, algoritmul poate găsi și diferenția cele două obiecte (și cel care se mișcă,
și cel care a rămas pentru un timp în cadru).

Algoritmul SimpleBackgroundModelingDetector însă, nu e aplicabil cazurilor în care


obiectul în mișcare se găsește în cadru în marea parte a timpului (ex. o persoană care stă în fața
30
camerei). Algoritmul este folosit mai mult în cazuri în care camera monitorizează un fel de scenă
statică, unde obiectele în mișcare apar din când în când (ex. coridor).

Experimentând în aplicația mea toți acești algoritmi, am ajuns la concluzia că algoritmul


SimpleBackgroundModelingDetector este cel mai potrivit pentru ceea ce am eu nevoie. Acesta se
adaptează ușor la schimbările de scenă (cu ajutorul proprietății
MillisecondsPerBackgroundUpdate se poate controla rata de actualizare a cadrului de fundal) și
permite nu numai identificarea destul de precisă a obiectelor în mișcare dar și a zonelor de
mișcare. Astfel, de pe scena concertului muzical se poate identifica nu doar care om se mișcă,
dar se pot determina și coordonatele zonelor unde acesta se mișcă.

Pentru a putea folosi acest algoritm am calculat obiectele separate din cadrul de mișcare.
Am reușit să implementez acest lucru folosindu-mă de un alt algoritm, tot din aceeași librărie,
BlobCountingObjectsProcessing. Acesta este folosit doar cu algoritmii care se bazează pe
diferențele dintre cadrele curente și cele ale fundalului și permite extragerea clară a obiectelor în
mișcare.

4.1 Algoritmul SimpleBackgroundModelingDetector de detecție a mișcării


(Pseudocod)
Clasa SimpleBackgroundModelingDetector implementează un algoritm de detecție a
mișcării care este bazat pe diferența dintre cadrul video curent și cadru de fundal modelat.
algoritm Simple-Background-Modeling-Detector (suppressNoise, keepObjectEdges)

Proprietatea DifferenceThreshold specifică câtă diferență există între pixeli. Reprezintă


pixelii în mișcare. Valoarea predefinită a pixelilor în mișcare este 15. Valoarea diferenței de
segmentare se află în domeniul [1, 255].

differenceThreshold ← 15
differenceThresholdNeg ← -15

proprietate DifferenceThreshold
differenceThreshold ← max( 1, min( 255, value ));
differenceThresholdNeg ← -differenceThreshold;
întoarce differenceThreshold

Proprietatea MotionFrame reprezintă o imagine cu formatul UnmanagedImage de tip


grayscale (alb-negru) care conține zona de mișcare detectată. Aceasta este segmentată. Toți
pixelii negri din cadrul de mișcare corespunde zonei una nu este detectată mișcarea. Pixelii albi,
în schimb, corespund zonelor unde există mișcare. Proprietatea este setată la null după
procesarea algoritmului a primului cadru video.

31
proprietate MotionFrame
întoarce motionFrame

Proprietatea MotionLevel reprezintă intensitatea mișcării; câte modificări s-au făcut în


ultimul cadru prelucrat. De exemplu, dacă valoarea acestei proprietăți este egal cu 0.5, înseamnă
că ultimul cadru procesat are un procent de 50% de diferențe comparativ cu cadrul de fundal
modelat. Variabila pixelsChanged reprezintă numărul de pixeli schimbați în noul cadru iar width
și height sunt dimensiunile cadrului procesat. Intensitatea mișcării se calculează împărțind
numărul de pixeli schimbați la dimensiunea cadrului.

proprietate MotionLevel
întoarce pixelsChanged / ( width * height )

Proprietatea SuppressNoise reprezintă un operator morfologic de eroziune care suprimă


pixelii cu zgomot. Valoarea ei specifică dacă trebuie aplicat un filtru suplimentar pentru a
suprima pixelii cu zgomot aplicând filtrul de eroziune 3x3 de procesare a imaginii. Dacă se
doresc identificarea precisă a frontierelor zonelor de mișcare (post-procesare de imagine), se va
folosi proprietatea KeepObjectsEdges. Aceasta va restabili marginile obiectelor, care nu sunt
zgomotoase. În mod predefinit, este setată la true. Atât folosirea proprietății SuppressNoise cât și
a celei KeepObjectsEdges vor conduce la un timp de procesare mai mare.

suppressNoise ← ADEVĂRAT
proprietate SuppressNoise
*) alocare cadru temporar (dacă este necesar)
dacă ((suppressNoise ) ȘI (tempFrame := NULL) ȘI (motionFrame != NULL)) atunci
tempFrame ← alocăMemorie (width, height, Format8bppIndexed )
sf. dacă
*) verificare dacă este necesar cadrul temporar
dacă ( (!suppressNoise ) ȘI (tempFrame != NULL ) )
*) dispunere tempFrame pe ecran
tempFrame ← NULL
sf. dacă
întoarce suppressNoise

keepObjectEdges ← FALS
proprietate keepObjectEdges
keepObjectEdges = value
întoarce keepObjectEdges

Cadrele se actualizează de la 1 până la 50 de ori pe fiecare fundal. Proprietatea


FramesPerBackgroundUpdate controlează viteza de adaptare a cadrului de fundal modelat la
schimbările scenei. După un anumit număr de cadre, cadrul de fundal se actualizează în sensul
descreșterii diferenței cu cadrul actual procesat. În mod predefinit, se actualizează de 2 ori.

32
Proprietatea are efect doar dacă proprietatea MillisecondsPerBackgroundUpdate este setată la 0.
Altfel, nu are efect iar actualizarea fundalului se va lua după valoarea proprietății
MillisecondsPerBackgroundUpdate.
proprietate FramesPerBackgroundUpdate
framesPerBackgroundUpdate ← max ( 1, min ( 50, value ) )
întoarce framesPerBackgroundUpdate

Valoarea proprietății MillisecondsPerBackgroundUpdate este o altă cale de a controla


viteza de adaptare a fundalului modelat la schimbările de scenă. Valoarea reprezintă în câte
milisecunde se face actualizarea fundalului; câte milisecunde trebuie să treacă între două cadre
consecutive pentru a avea o actualizare a fundalului, la o singură mișcare. De exemplu, dacă
această valoare este setată a 100 milisecunde iar intervalul de timp dintre două cadre consecutive
este egal cu 350, atunci fundalul se va actualiza pentru 3 nivele de intensitate în direcția de a
micșora diferența cu cadrul video actual (restul, cele 50 milisecunde, se va adăuga la diferența de
timp dintre două cadre succesive, deci precizia este păstrată).
Actualizarea cadrului de fundal se poate face la fiecare 0 milisecunde până la un maxim de 5000
milisecunde (5 secunde).
Spre deosebire de FramesPerBackgroundUpdate, metoda ghidată de această proprietate nu este
afectată de modificări a ratelor cadrelor. Dacă, pentru anumite motive, în cadrul unei surse video
încep să apară întârzieri între cadre, numărul de actualizări a fundalului rămâne același. Cu
această proprietate se poate estima de câte ori este nevoie de o modificare a fundalului, de
exemplu, de la un negru (valoarea intensității egal cu 0) la un alb (valoarea intensității egal cu
255). Dacă valoarea proprietății MillisecondsPerBackgroundUpdate este setată la 100, atunci vor
fi necesare aproximativ 25.5 secunde pentru o astfel de actualizare, indiferent de rata de cadre.
Actualizarea fundalului cu proprietatea MillisecondsPerBackgroundUpdate se face mai lent, în
comparație cu FramesPerBackgroundUpdate, deci are un impact mai mare asupra performanței.
Dacă această proprietate este setată la 0, atunci metoda care actualizează cadrul de fundal nu se
folosește, în schimb proprietatea FramesPerBackgroundUpdate, da.
proprietate MillisecondsPerBackgroundUpdate
millisecondsPerBackgroundUpdate = max ( 0, min( 5000, value ) )
întoarce millisecondsPerBackgroundUpdate

Metoda SimpleBackgroundModelingDetector poate lua în considerare atât operatorul


morfologic de suprimare a imaginii zgomotoase cât și proprietatea care identifică marginile
obiectelor identificate, in acest caz, acestea fiind setate la true. Dacă se dorește o procesare
rapidă a mișcării, acești parametri pot fi setați la false, având avantajul unui timp de procesare
mai mic.
procedură SimpleBackgroundModelingDetector()
sf. procedură
sau
procedură SimpleBackgroundModelingDetector(suppressNoise)
this.suppressNoise ← suppressNoise
sf. procedură

33
sau
procedură SimpleBackgroundModelingDetector(suppressNoise, keepObjectEdges)
this.suppressNoise ← suppressNoise
this.keepObjectEdges ← keepObjectEdges
sf. procedură

*) Procesare noi cadre de la sursa video și detecția mișcării


*) videoFrame - reprezintă cadrul video sursă ce urmează a fi procesat (detecția mișcării)
procedură ProcessFrame (videoFrame)
*) verificare cadru de fundal (backgroundFrame)
dacă backgroundFrame ← NULL atunci
*) width - lățimea cadrului videoFrame
*) height - înălțimea cadrului videoFrame
*) salvează dimensiunea imaginii
width = videoFrame.Width
height = videoFrame.Height

*) motionFrame - cadrul video precedent


*) backgroundFrame - cadrul video actual de fundal

*) Format8bppIndexed - un format de 8 biți per pixel, indexat (256 culori)


*) Stride - reprezintă dimensiunea liniei în octeți a cadrului motionFrame
*) alocare memorie pentru cadrele anterioare și actuale
backgroundFrame ← alocăMemorie (width, height, Format8bppIndexed )
motionFrame ← alocăMemorie (width, height, Format8bppIndexed )
frameSize ← Stride * height

*) buffer temporar
*) tempFrame – buffer-ul temporar folosit pentru suprimarea zgomotului
dacă ( suppressNoise ) atunci
tempFrame ← alocăMemorie ( width, height, Format8bppIndexed )
sf. dacă
*) conversia cadrului sursă (color) în grayscale
*) metoda ConvertToGrayscale din clasa Tools (Aforge.NET)
ConvertToGrayscale( videoFrame, backgroundFrame )
sf. dacă

*) verifică dimensiunea imaginii


dacă ( ( videoFrame.Width != width ) sau ( videoFrame.Height != height ) ) atunci
*) metoda ConvertToGrayscale din clasa Tools (Aforge.NET)
ConvertToGrayscale ( videoFrame, backgroundFrame )

*) pointeri la cadrul de fundal și la cadrele curente:

34
*) *backFrame, *currFrame, diff

*) actualizare cadru de fundal


millisecondsPerBackgroundUpdate ← 0
framesPerBackgroundUpdate ← 2
millisecondsLeftUnprocessed ← 0

dacă ( millisecondsPerBackgroundUpdate == 0 ) atunci


*) actualizare cadru de fundal folosind contorul cadrului
dacă ( ++framesCounter == framesPerBackgroundUpdate ) atunci
framesCounter ← 0
*) backFrame - conversie backgroundFrame la byte*
*) currFrame - conversie motionFrame la byte*

pentru i ← 0, frameSize execută


diff = *currFrame - *backFrame
dacă ( diff > 0 ) atunci
*backFrame++
altfel dacă ( diff < 0 ) atunci
*backFrame--
sf. dacă
sf. dacă
sf. pentru
altfel
*) actualizare cadru de fundal folosind timer
*) obține ora curentă și calculează diferența
timeDff ← currentTime - lastTimeMeasurment

*) salvează ora curentă ca ultima măsurătoare


lastTimeMeasurment ← currentTime
millisonds ← TotalMilliseconds + millisecondsLeftUnprocessed

*) salvează restul pentru a putea fi luat în considerare pe viitor


millisecondsLeftUnprocessed ← millisonds %
millisecondsPerBackgroundUpdate

*) obținere cantitatea cadrelor de fundal actualizate


updateAmount = millisonds / millisecondsPerBackgroundUpdate

*) backFrame - conversie backgroundFrame la byte*


*) currFrame - conversie motionFrame la byte*

pentru i ← 0, frameSize execută

35
diff = *currFrame - *backFrame
dacă ( diff > 0 ) atunci
dacă *backFrame += ( diff < updateAmount ) atunci
*backFrame ← diff
altfel *backFrame ← updateAmount
sf. dacă
altfel dacă ( diff < 0 ) atunci
dacă *backFrame += ( -diff < updateAmount ) atunci
*backFrame ← diff
altfel *backFrame ← -updateAmount
sf. dacă
sf. dacă
sf. dacă
sf. pentru
sf. dacă

pentru i ← 0, frameSize execută


*) diferența dintre cadre
diff = *currFrame - *backFrame
*) valoare prag diferența [1, 255]
dacă *currFrame ← ( diff >= differenceThreshold ) atunci
*currFrame ← 255
altfel dacă *currFrame ← ( diff >= differenceThresholdNeg) atunci
*currFrame ← 0
sf. pentru

*) suprimare zgomot și calcul cantitate de mișcare


dacă ( suppressNoise ) atunci
*) erosionFilter –reprezintă obiectul clasei BinaryErosion3x3()
*) dilatationFilter –reprezintă obiectul clasei BinaryDilatation3x3()
*) metoda CopyUnmanagedMemory din clasa SystemTools (AForge.NET)

CopyUnmanagedMemory( tempFrame, motionFrame, frameSize )


erosionFilter ( tempFrame, motionFrame )

dacă ( keepObjectEdges ) atunci


CopyUnmanagedMemory(tempFrame, motionFrame, frameSize )
dilatationFilter ( tempFrame, motionFrame )
sf. dacă
sf. dacă

pixelsChanged ← 0
*) calcul cantitatea pixelilor în mișcare

36
pentru i ← 0, frameSize execută
*) & - reprezintă operatorul ȘI logic
pixelsChanged += ( *motion & 1 )
sf. pentru
sf. dacă
sf. procedură
sfârșit

Detectorul mișcării (starea mișcării, fundalul, cadrul temporar, numărul de cadre cât și
zona mișcării) trebuie resetat la valoarea inițială. Acest lucru trebuie făcut înainte de a procesa
un nou flux de date, dar se poate face mereu când se dorește resetarea algoritmului de detecție a
mișcării.

4.2 Implementarea algoritmului de detecție a mișcării umane (C#)


Pentru a mă putea folosi de algoritmul de detecție a platformei AForge.NET, a fost
nevoie să adaug la referințe librăria AForge.Vision.Motion.dll care conține implementarea
algoritmului (vezi secțiunea 4.1 Algoritmul SimpleBackgroundModelingDetector de detecție a
mișcării (Pseudocod) pentru mai multe detalii).

mp - reprezintă un obiect care instanțiază clasa BlobCountingObjectsProcessing:


static BlobCountingObjectsProcessing mp = new BlobCountingObjectsProcessing(true);

Această clasă (implementată tot în platforma Aforge.NET) numără obiectele care se mișcă în
cadru și le evidențiază cu un dreptunghi de o anumită culoare . Aceste obiecte sunt asigurate de
interfața IMotionDetector. Algoritmul calculează și evidențiază doar acele obiecte care satisfac
dimensiunile limită a proprietăților MinObjectWidth și MinObjectHeight. Se poate configura
acest algoritm astfel încât să se ignore obiectele mai mici de o anumită dimensiune. Aceste
proprietăți se setează din cod astfel:
mp.MinObjectsHeight = 15;
mp.MinObjectsWidth = 15;

Dacă proprietatea HighlightMotionRegions este setată la true,


mp.HighlightMotionRegions = true;
obiectele găsite vor fi evidențiate pe fluxul video original:
mp.HighlightColor = System.Drawing.Color.FromArgb (255, 255, 0);

Variabila detector este un obiect care instanțiază clasa MotionDetector:


MotionDetector detector = new MotionDetector(new SimpleBackgroundModelingDetector(), mp);
MotionDetector este utilizată ca și clasă wrapper (înveliș) pentru algoritmi de detecție și
procesare a mișcării, permițând apelul algoritmilor doar cu un singur apel.
public MotionDetector(IMotionDetector detector, IMotionProcessing processor);

37
Spre deosebire de interfețele de procesare și detecție a mișcării, clasa MotionDetector oferă și
alte metode adiționale necesare, astfel încât algoritmii pot fi aplicați nu doar imaginilor
UnmanagedImage, dar și claselor Bitmap din .NET. Cu ajutorul proprietății MotionZones se
poate specifica un set de zone cu dreptunghiuri pentru evidențiere a zonelor, astfel este luată în
calcul și post-procesată doar mișcarea în aceste zone. Mișcarea din afara zonei de mișcare este
ignorată. Dacă este setată această proprietate, metoda ProcessFrame(UnmanagedImage) va reda
toate mișcările detectate de algoritm, dar nu este localizată în acea determinată zonă.
Imaginea lastFrame este de tipul Bitmap și a fost creată din necesitatea de a reține
ultimul cadru de procesat pentru a ajuta la conversia din formatul ColorImageFrame.
lastFrame = ImageToBitmap(frame);
Funcția care face această conversie se numește ImageToBitmap() și ia ca dată de intrare o
imagine cu formatul ColorImageFrame și returnează un Bitmap. Pentru mai multe detalii vezi
4.3 Pregătirea formatului imaginii necesar platformei Aforge.NET.

Acestei imagini lastFrame i se aplică algoritmul de procesare a mișcării. Dacă intensitatea


mișcării trece de valoarea 0.02, voi avea mișcare. Intervalul intensității mișcării este [0,1], 1 fiind
gradul cel mai mare de mișcare a obiectelor din cadru.
// process new video frame and check motion level
if (detector.ProcessFrame(lastFrame) > 0.02)
{
txtInfo.Text = "Motion";

}

Codul de bază implementat este următorul:


using AForge.Vision.Motion;

// create motion detector


static BlobCountingObjectsProcessing mp = new BlobCountingObjectsProcessing();
MotionDetector detector = new MotionDetector(new SimpleBackgroundModelingDetector(), mp);
private Bitmap lastFrame = null;

public Bitmap LastFrame


{
get
{
return lastFrame;
}
}

void Sensor_AllFramesReady(object sender, AllFramesReadyEventArgs e)


{
// Color frame
using (var frame = e.OpenColorImageFrame())
{
if (frame != null)
{
if (_mode == CameraMode.Color)
{
camera.Source = frame.ToBitmap();
}

38
// dispose old frame
if (lastFrame != null)
{
lastFrame.Dispose();
}

lastFrame = ImageToBitmap(frame);

int detectedObjectsCount = 0;

// process new video frame and check motion level


if (detector.ProcessFrame(lastFrame) > 0.02)
{
objectsCountLabel.Text = "Motion level: " +
(detector.ProcessFrame(lastFrame)).ToString("#.##");

System.Drawing.Rectangle[] rectangles = mp.ObjectRectangles;


txtInfo.Text = "Motion";

if (rectangles != null)
{
Console.WriteLine("left: {0} top: {1} right: {2} bottom: {3}",
rectangles[i].Left, rectangles[i].Top, rectangles[i].Right, rectangles[i].Bottom);

for (int i = 0; i < rectangles.Length; i++)


{
//get detectedObjectsCount with BlobCountingObjectsProcessing
if (detector.MotionProcessingAlgorithm is BlobCountingObjectsProcessing)
{
mp =
(BlobCountingObjectsProcessing)detector.MotionProcessingAlgorithm;
mp.HighlightMotionRegions = true;
mp.HighlightColor = System.Drawing.Color.FromArgb(255, 255, 0);
mp.MinObjectsHeight = 15;
mp.MinObjectsWidth = 15;

detectedObjectsCount = mp.ObjectsCount;
rectNr.Text = "Zones nr: " + detectedObjectsCount.ToString();
}
}
}
}
else
{
objectsCountLabel.Text = "Motion level: " +
(detector.ProcessFrame(lastFrame)).ToString("#.##");
txtInfo.Text = "No motion";
}

}
}
}

Zonele de mișcare le-am desenat pe canvas-ul unde este afișat fluxul color de date de la
senzorul Kinect. Acestea sunt reprezentate prin dreptunghiuri (în cazul de față laturile lor au
dimensiuni egale) de culoare albastră (vezi figura 3.2.1). Pentru fiecare zonă de mișcare se iau
coordonatele dreptunghiului (stânga, sus, dreapta, jos), se creează dreptunghiurile cu setările
corespunzătoare și se afișează pe zona de imagine.
System.Drawing.Rectangle[] rectangles = mp.ObjectRectangles;

//draw motion zones with rectangles


for (int i = 0; i < rectangles.Length; i++)

39
{
System.Windows.Shapes.Rectangle rect = new System.Windows.Shapes.Rectangle ();
rect = new System.Windows.Shapes.Rectangle();
rect.Stroke = System.Windows.Media.Brushes.Blue;

rect.HorizontalAlignment = HorizontalAlignment.Left;
rect.VerticalAlignment = VerticalAlignment.Center;
rect.Height = 80; //rectangles[i].Top;
rect.Width = 80; //rectangles[i].Right;

canvas.Children.Add(rect);
Canvas.SetLeft(rect, rectangles[i].Left);
Canvas.SetTop(rect, rectangles[i].Top);
Canvas.SetRight(rect, rectangles[i].Right);
Canvas.SetBottom(rect, rectangles[i].Bottom);
}

Figura 2.2.1 Detecția zonelor de mișcare și evidențierea lor

4.3 Pregătirea formatului imaginii necesar platformei Aforge.NET

Datele preluate cu senzorul Kinect trebuie pregătite pentru formatul cerut de librăria
Aforge.NET, pentru a fi procesate. Formatul imaginii captate de Kinect este de tipul
ColorImageFrame iar Aforge.NET (AForge.Imaging.UnmanagedImage) cere formatul Bitmap.

40
Bitmap ImageToBitmap(ColorImageFrame Image)
{//..}

Este nevoie de adăugarea librăriei pentru folosirea Bitmap-ului: using System.Drawing.Imaging;

Funcția preia formatul ColorImageFrame și returnează un Bitmap cu aceleași date ale pixelilor.
Metoda funcționează doar pentru ColorImageFrame care folosește 32 bit pentru formatul de date
RGBA (folosit și cu senzorul video a Kinectului).
Mai întâi se preia datele pixelilor ca un array de bytes:
byte[] pixeldata = new byte[Image.PixelDataLength];
Image.CopyPixelDataTo(pixeldata);

PixelDataLength dă numărul de bytes necesari pentru a stoca întreaga imagine.


Trebuie apoi creat un obiect de tip Bitmap care să conțină datele pixelilor și să fie setat la 32 bit
RGB (RGBA fără valoarea Alpha):
Bitmap bmap = new Bitmap(Image.Width, Image.Height,
System.Drawing.Imaging.PixelFormat.Format32bppRgb);

Obiectul Bitmap folosește o altă clasă (BitmapData) pentru a crea un buffer de memorie care să
stocheze datele biților. Metoda LockBits returnează un obiect de tip BitmapData care este blocat
în memoria buffer unde se află datele pixelilor. De obicei, această operație copiază datele
bitmap-ului din bitmap în buffer pentru a putea lucra cu ele. Se poate seta opțiunea WriteOnly
dacă se dorește ca memoria buffer să aloce dimensiunea corectă fără a transfera nimic din
obiectul Bitmap.
Deci, pentru a crea buffer-ul se face astfel:

BitmapData bmapdata = bmap.LockBits(


new System.Drawing.Rectangle(0, 0, Image.Width, Image.Height),
ImageLockMode.WriteOnly,
bmap.PixelFormat);

Memoria buffer așteaptă ca biții să fie transferați. Pentru a face acest lucru, este nevoie să se
folosească un transfer de tip memory-to-memory, oferit de funcții InterOp. Trebuie deci, adăugat
la începutul proiectului:
using System.Runtime.InteropServices;
Este nevoie de un pointer către zona de început a memoriei buffer iar apoi se va folosi metoda
Copy() pentru a transfera datele:
Marshal.Copy(pixeldata, 0, ptr, Image.PixelDataLength);
pixeldata stochează adresa de început a imaginii din buffer în ptr. Metoda Copy() va copia
datele bits în buffer-ul către care ptr pointează. Al doilea parametru al metodei Copy() este un
offset, de obicei zero, iar ultimul parametru returnează numărul total de bytes ce trebuie copiați.

Metoda UnlockBits(bmapdata) deblochează buffer-ul care transferă datele în obiectul de tip


Bitmap iar acesta vin returnat:

bmap.UnlockBits(bmapdata);
return bmap;
Bitmap-ul care este returnat poate fi utilizat în platforma de viziune artificială Aforge.NET.

41
Capitolul 5 - Detecția mișcării în secvențe Skeleton preluate de la
senzorul Kinect
Senzorul Kinect permite localizarea joncțiunilor care descriu poziția figurii umane
(skeleton tracking).

Figura 5.1 Skeleton tracking (resursă imagine din stânga:


https://channel9.msdn.com/coding4fun/kinect/Kinect-gestures-an-implementation-walk-through)

În cadrul proiectului am preluat datele referitoare la poziția mâinii drepte și stângi în


raport cu cotul drept, respectiv stâng. Dacă coordonata x și y a mâinii drepte este mai mare decât
cea a cea a cotului drept, atunci utilizatorul a ridicat mâna dreaptă. Același lucru este valabil și
pentru mâna stângă:
bool dreapta_sus, stanga_sus, maini_sus, maini_jos = false;

// Right hand above Right elbow


if (handRight.Position.Y > elbowRight.Position.Y)
{
if (handRight.Position.X > elbowRight.Position.X)
{
dreapta_sus = true;
stanga_sus = false;
maini_sus = false;
maini_jos = false;
this.gestureDetectionLabel.Text = "HELLO -- You just waved RIGHT hand!";
}
}
// Left hand above Left elbow
else if (handLeft.Position.Y > elbowLeft.Position.Y)
{
if (handLeft.Position.X > elbowLeft.Position.X)
{
stanga_sus = true;
dreapta_sus = false;
maini_sus = false;
maini_jos = false;
this.gestureDetectionLabel.Text = "You just waved LEFT hand!";
}

42
}

Amândouă mâini sunt ridicate dacă coordonata y a mâinii drepte și stângi este mai mare decât
cea a cotului drept, respectiv stâng.

// Right and Left hand up


if (handRight.Position.Y > elbowRight.Position.Y &&
handLeft.Position.Y > elbowLeft.Position.Y)
{
stanga_sus = false;
dreapta_sus = false;
maini_sus = true;
maini_jos = false;
this.gestureDetectionLabel.Text = "RIGHT and LEFT hands up!";
}

Pentru a detecta dacă mâinile nu sunt ridicate, am luat ca punct de referință joncțiunea spinei,
astfel:
// Right and Left hand down
if (handRight.Position.Y < spine.Position.Y && handLeft.Position.Y < spine.Position.Y)
{
stanga_sus = false;
dreapta_sus = false;
maini_sus = false;
maini_jos = true;
this.gestureDetectionLabel.Text = "RIGHT and LEFT hands down!";
}

Fig. 5.2 Detecția ridicării mâinii stângi și drepte deasupra cotului stâng, respectiv drept

43
Capitolul 6 - Concluzii

În lucrarea de față s-a dorit dezvoltarea unei aplicații care să achiziționeze date de la
senzorul Microsoft Kinect și să le proceseze prin algoritmi de detecție a mișcării. Zonele de
mișcare de pe scenă, numărul de zone, intensitatea mișcării și scheletul cu articulațiile corpului
sunt transmise și folosite în vederea realizării de efecte digitale care să fie proiectate pe ecrane de
dimensiuni mari pe toată durata concertului muzical.
Proiectul în ansamblu a fost gândit astfel încât prezența mișcării din cadru și ridicarea mâinilor
să pornească anumite efecte iar zonele de mișcare să le modeleze pe tot ecranul. Numărul de
zone va determina câte obiecte se vor crea iar valoarea intensității mișcării de pe scenă va
schimba culorile, viteza de rotație sau de mișcare a elementelor din reprezentarea grafică. Astfel,
concertul muzical va primi o nouă dimensiune, muzica va fi acompaniată de efecte dinamice,
modelate în timp real pe baza mișcării trupei de pe scenă și interacțiunea cu publicul va fi una
mult mai creativă.
Se poate demonstra cum datele achiziționate cu senzorul Kinect din cadrul proiectului pot
fi utile și în alte direcții precum cel educațional. De exemplu, se pot comanda controale printr-o
simplă mișcare a mâinii drepte sau stângi (figura 6.2). Pentru aceasta m-am folosit de harta de
adâncime a senzorului Kinect și de componenta Microsoft.Kinect.Toolkit.Controls care
implementează interacțiunile Kinect bazate pe gesturi, concepute pentru controlul fără mâini a
aplicațiilor și a altor forme de interactivitate. Kinect calculează distanța mâinii față de senzor cu
senzorul de adâncime. Dacă mâna se apropie de senzor și dacă mâna interactivă controlată de pe
formular se află pe control, acesta se va apăsa și evenimentul corespundent se va declanșa.
De altfel, cu ajutorul coordonatelor xy ale încheieturilor (cap, mâna dreaptă și mâna stângă)
preluate cu secvențele Skeleton se poate derula un fișier Powerpoint ridicând mâna dreaptă sau
stângă (figura 6.1).

Figura 6.1 Control fișier Powerpoint prin ridicarea mâinii stângi, respectiv drepte

44
Interfața grafică realizată în mediul de dezvoltare Visual Studio 2015, în limbajul de
programare C# se poate vedea în figura 6.2. Aceasta conține fluxul de date color împreună cu
articulațiile din secvențele Skeleton, harta de adâncime (în partea de stânga-jos, cu albastru) și
cea care identificatorul persoanelor (diferite persoane sunt reprezentate cu diferite culori).
Zonele de mișcare sunt reprezentate în imagine prin pătrate albastre. În partea de sus, din
dreapta, sunt afișate datele achiziționate cu Kinect referitoare la prezența mișcării din cadru,
detecția cărei mâini este ridicată, intensitatea mișcării și numărul de zone de mișcare. De
asemenea, de pe interfață se poate regla și motorul de înclinație.

Figura 6.2 Interfața grafică

Cu siguranță, la acest proiect pot fi făcute multe îmbunătățiri. De exemplu, se poate face
un streaming în timpul concertului, pe pagina de Facebook a trupei și să se preia like-urile la
postare și anumite comentarii făcute de public, cu scopul de a le afișa pe ecran sub formă de
efecte. De asemenea, s-ar putea capta și sunetul cu ajutorul microfonului multidirecțional al
senzorului Kinect, zona și unghiul de unde vine acesta pentru a putea „jongla” mai mult cu
culorile în cadrul efectului digital.

45
Referințe

[1] Giorio C., Fascinari M., “Kinect in Motion - Audio and Visual Tracking by Example”,
ISBN-13: 978-1849697187, Packt Publishing, 2013
[2] Reas C., Fry B., “Processing: A Programming Handbook for Visual Designers and Artists”,
ISBN-13: 978-0262028288, Massachusetts Institute of Technology, 2014
[3] AFORGE.NET Framework http://www.aforgenet.com/framework/ (ultima accesare: 13 iulie
2016)
[4] Accord.NET Framework http://accord-framework.net/ (ultima accesare: 13 iulie 2016)
[5] AFORGE.NET Framework http://www.aforgenet.com/framework/docs/ (ultima accesare: 13
iulie 2016)
[6] Microsoft Kinect v1.8 https://it.wikipedia.org/wiki/Microsoft_Kinect (ultima accesare: 13
iulie 2016)
[7] Microsoft Kinect v2.0 https://en.wikipedia.org/wiki/Kinect (ultima accesare: 13 iulie 2016)
[8] Reverse Engineering https://it.wikipedia.org/wiki/Reverse_engineering (ultima accesare: 13
iulie 2016)
[9] Bayer filter https://en.wikipedia.org/wiki/Bayer_filter (ultima accesare: 13 iulie 2016)
[10] CCD e CMOS, il cuore della telecamera http://www.dseitalia.it/tut_tel_ccd.htm (ultima
accesare: 13 iulie 2016)
[11] Dispozitive de captare a imaginii http://vega.unitbv.ro/~nicolaeg/SCTRI%20-
ROBOTICA/Note%20de%20curs/StPPT%20C8%20Dispozitive%20de%20captare%20a%20
imaginii..pdf (ultima accesare: 13 iulie 2016)
[12] Dichroic prism https://en.wikipedia.org/wiki/Dichroic_prism (ultima accesare: 13 iulie
2016)
[13] Cuttoff frequency https://en.wikipedia.org/wiki/Cutoff_frequency (ultima accesare: 13
iulie 2016)
[14] Electret microphone https://en.wikipedia.org/wiki/Electret_microphone (ultima accesare:
13 iulie 2016)
[15] Kinect for Windows SDK v1.8 https://www.microsoft.com/en-
ca/download/details.aspx?id=40278 (ultima accesare: 13 iulie 2016)
[16] Kinectic vision looking deep into depth http://www.slideshare.net/ppd1961/kinectic-
vision-looking-deep-into-depth (ultima accesare: 13 iulie 2016)
[17] Motion detection https://en.wikipedia.org/wiki/Motion_detection (ultima accesare: 13
iulie 2016)
[18] Computer vision https://en.wikipedia.org/wiki/Computer_vision (ultima accesare: 13
iulie 2016)
[19] Kinect for Windows Architecture https://msdn.microsoft.com/en-us/library/jj131023.aspx
(ultima accesare: 13 iulie 2016)
[20] Readme for Kinect for Windows SDK - Beta 2 release https://www.microsoft.com/en-
us/kinectforwindows/develop/readme.htm (ultima accesare: 13 iulie 2016)
[21] Getting the Next Frame of Data by Polling or Using Events
https://msdn.microsoft.com/en-us/library/hh973076.aspx (ultima accesare: 13 iulie 2016)
[22] Thresholding (image processing)
https://en.wikipedia.org/wiki/Thresholding_(image_processing)
(ultima accesare: 13 iulie 2016)

46

S-ar putea să vă placă și