Post on 12-May-2020
1
UNIVERSITATEA „ALEXANDRU IOAN CUZA” IAŞI
FACULTATEA DE INFORMATICĂ
LUCRARE DE LICENŢĂ
MyUniAssistant: Dezvoltarea unei aplicații
Android de informare și recunoaștere facială
Propusă de
Hălceanu I. Andrei
Sesiunea: Februarie, 2017
Coordonator știinţific
Asistent, dr. Vasile Alaiba
2
UNIVERSITATEA „ALEXANDRU IOAN CUZA” IAŞI
FACULTATEA DE INFORMATICĂ
LUCRARE DE LICENŢĂ
MyUniAssistant: Dezvoltarea unei aplicații
Android de informare și recunoaștere facială
Hălceanu I. Andrei
Sesiunea: Februarie, 2017
Coordonator știinţific
Asistent, dr. Vasile Alaiba
3
DECLARAŢIE PRIVIND ORIGINALITATEA ŞI
RESPECTAREA DREPTURILOR DE AUTOR
Prin prezenta declar că Lucrarea de licență cu titlul „MyUniAssistant:
Dezvoltarea unei aplicații Android de informare și recunoaștere facială” este
scrisă de mine şi nu a mai fost prezentată niciodată la o altă facultate sau
instituţie de învățământ superior din ţară sau străinătate. De asemenea, declar că
toate sursele utilizate, inclusiv cele preluate de pe Internet, sunt indicate în
lucrare, cu respectarea regulilor de evitare a plagiatului:
− toate fragmentele de text reproduse exact, chiar şi în traducere proprie din
altă limbă, sunt scrise între ghilimele şi deţin referinţa precisă a sursei;
− reformularea în cuvinte proprii a textelor scrise de către alţi autori deţine
referinţa precisă;
− codul sursă, imagini etc. preluate din proiecte open source sau alte surse
sunt utilizate cu respectarea drepturilor de autor şi deţin referinţe precise;
− rezumarea ideilor altor autori precizează referinţa precisă la textul
original.
Iaşi,
Absolvent Hălceanu Andrei
_________________________
(semnătura în original)
4
DECLARAŢIE DE CONSIMŢĂMÂNT
Prin prezenta declar că sunt de acord ca Lucrarea de licență cu titlul
„MyUniAssistant: Dezvoltarea unei aplicații Android de informare și
recunoaștere facială”, codul sursă al programelor şi celelalte conţinuturi (grafice,
multimedia, date de test etc.) care însoţesc această lucrare să fie utilizate în
cadrul Facultăţii de Informatică.
De asemenea, sunt de acord ca Facultatea de Informatică de la Universitatea
„Alexandru Ioan Cuza” Iași să utilizeze, modifice, reproducă şi să distribuie în
scopuri necomerciale programele-calculator, format executabil şi sursă, realizate
de mine în cadrul prezentei lucrări de licenţă.
Iaşi,
Absolvent Hălceanu Andrei
_________________________
(semnătura în original)
5
Introducere ....................................................................................................................... 7
1. Motivație ............................................................................................................................. 7
2. Context ................................................................................................................................. 7
3. Cerințe funcționale ................................................................................................................ 9
4. Abordare tehnică ................................................................................................................ 10
Contribuții ....................................................................................................................... 11
Capitolul 1: Dezvoltarea componentei server ................................................................... 12
1.1. Arhitectura componentei server ....................................................................................... 12
1.2. Implementare .................................................................................................................. 13
1.2.1. Structură și concepte .......................................................................................................................... 13
1.2.2. Server TCP concurent ......................................................................................................................... 16
1.2.3. Procesarea imaginilor ......................................................................................................................... 17
1.2.4. Autentificare ....................................................................................................................................... 20
1.3. Recunoașterea facială....................................................................................................... 21
1.3.1. Implementarea etapelor de recunoaștere facială .............................................................................. 21
1.3.2. Antrenarea algoritmului de recunoaștere facială ............................................................................... 22
1.4. Comunicarea cu partea de client ....................................................................................... 25
1.5. Baza de date .................................................................................................................... 25
1.6. Interfața serverului .......................................................................................................... 28
1.6.1. Fereastra principală ............................................................................................................................ 29
1.6.2. Fereastra de autentificare .................................................................................................................. 29
1.6.3. Bara de meniu ..................................................................................................................................... 30
1.6.4. Zona de stare și istoricul ..................................................................................................................... 32
Capitolul 2: Dezvoltarea componentei client .................................................................... 32
2.1. Arhitectura componentei client ........................................................................................ 33
2.2. Implementare .................................................................................................................. 34
2.2.1. Permisiuni și activități ......................................................................................................................... 34
2.2.2. Autentificare ....................................................................................................................................... 36
2.2.3. Accesarea camerei dispozitivului ........................................................................................................ 37
2.2.4. Selectarea feței ................................................................................................................................... 38
2.2.5. Căutarea după nume .......................................................................................................................... 38
2.2.6. Căutări salvate .................................................................................................................................... 39
2.2.7. Fișiere auxiliare ................................................................................................................................... 39
2.3. Comunicarea cu serverul .................................................................................................. 40
6
2.4. Interfața componentei client ............................................................................................ 40
2.4.1. Bara de titlu ........................................................................................................................................ 40
2.4.2. Activitatea principală și fereastra de autentificare ............................................................................. 41
2.4.3. Activitatea de detectare și recunoaștere facială ................................................................................ 42
2.4.4. Activitatea de căutare ......................................................................................................................... 42
2.4.5. Activități adiționale ............................................................................................................................. 43
Capitolul 3: Procesul de recunoaștere facială ................................................................... 44
3.1. Detectarea fețelor ............................................................................................................ 44
3.2. Recunoașterea fețelor ...................................................................................................... 47
3.2.1. Extragerea punctelor .......................................................................................................................... 47
3.2.2. Utilizarea punctelor extrase pentru comparare ................................................................................. 48
Concluzii finale ................................................................................................................ 49
Referințe ......................................................................................................................... 50
7
Introducere
1. Motivație
V-a fost vreodată greu să vă adaptați în cadrul unei firme sau facultăți la început? Nu
ați dispus de carnetul de student la un examen și nu v-ați putut confirma identitatea? Ați avut
nevoie de informații referitoare la un profesor/manager/orice alt membru al personalului și nu
le-ați putut obține imediat? Această aplicație are ca scop rezolvarea acestor probleme direct de
pe telefonul mobil.
Aplicația poate fi utilizată pentru obținerea unor anumite informații despre o persoană
după numele sau o fotografie a acesteia. Desigur, persoanele înregistrate în baza de date fac
parte dintr-un cadru restrâns, cum ar fi o facultate, firmă sau alt tip de instituție, iar accesul
este permis numai utilizatorilor autentificați, conectați la rețeaua locală.
Pe lângă aceasta, aplicația poate fi utilizată și pentru confirmarea identității unei
persoane și poate înlocui alte metode de recunoaștere existente, cum ar fi ecusoanele,
carnetele de student, plăcuțele de identificare sau alte simboluri distinctive.
2. Context
Încă din anii 1964-1965, a început să fie utilizat computerul pentru a recunoaște fețe
umane. De-a lungul timpului au apărut numeroase metode și algoritmi în acest domeniu,
încercând a se depăși obstacole ca poziția capului, expresia facială, intensitatea luminii,
direcția acesteia, dar și probleme de flexibilitate, scalabilitate sau de viteză computațională.
În prezent se utilizează detecția și recunoașterea fețelor în multe domenii, cum ar fi
sistemele de supraveghere, rețelele sociale, controlul accesului pe dispozitive, în clădiri sau
zone cu securitate ridicată, chiar și pentru divertisment. Algoritmii de recunoaștere se aplică
pe fotografii sau clipuri video înregistrate sau în transmisiune directă (de exemplu, camere de
supraveghere), atât în mediu color, cât și alb-negru.
8
Cu toate că s-au realizat progrese foarte mari de-a lungul timpului, acest domeniu este
încă în dezvoltare. Deși se raporta atingerea unui nivel de acuratețe de peste 90% a mai multor
algoritmi, un studiu recent efectuat de Universitatea Washington arată că, folosind un milion
de imagini ca test, acesta scade drastic. Sistemul cu cele mai bune rezultate dintre cele testate
este FaceNet, deținut de Google, cu o acuratețe de 75%. Acesta atingea un nivel de
recunoaștere de aproape 100% în testele precedente, în care s-au utilizat circa 13 000 de
imagini. [1]
Graficul 1: Rata de identificare a unor algoritmi de recunoaștere facială în funcție de numărul
imaginilor de test cu care au fost confruntate, Universitatea Washington
Din punct de vedere a detectării și recunoașterii fețelor, aplicația realizată de mine nu
aduce nimic nou, ci utilizează și combină algoritmi deja existenți pentru a obține rezultate cât
mai corecte. Totuși, aceasta nu este o simplă aplicație de recunoaștere facială, având și alte
funcționalități pe lângă aceasta; poate deveni un asistent de nădejde în cadrul facultății
noastre, atât pentru studenți, cât și pentru profesori.
Aplicația poate fi utilizată doar în interiorul facultății de către utilizatorii autentificați
pentru obținerea unor informații (legate de identitate, contact ș.a.m.d.) ale altor membri.
Aceasta rulează pe telefoanele mobile cu sistem de operare Android și este realizată în limba
engleză, putând fi folosită astfel și de studenți sau invitați străini.
9
3. Cerințe funcționale
Principala funcționalitate reprezintă recunoașterea facială a profesorilor, studenților și a
personalului administrativ al facultății. Primul pas este realizarea fotografiei, care se inițiază
din aplicație prin simpla apăsare a unui buton. Urmează partea de detectare a feței în imagine,
lucru care se poate face automat sau manual. În caz că nu este detectată nici o față automat,
utilizatorul va trebui să o încadreze într-un pătrat. Ultima parte constă în încercarea de a
recunoaște persoana respectivă, primindu-se apoi informațiile cerute.
De asemenea, se poate realiza căutarea unei persoane după nume. În acest caz se vor
obține aceleași informații ca la încărcarea unei poze. Câmpul de căutare va oferi și sugestii,
astfel utilizatorul va ști dacă o persoană se află în baza de date înainte de a iniția căutarea.
Se pot obține informații prin cele două moduri specificate mai sus. Referitor la studenți se
pot afla numele, anul, grupa, cursurile opționale alese, adresa de e-mail, iar despre profesori
numele, cursurile pe care le predau, legătura (url) către orarul acestora, cabinetul de
consultații, titlul pe care aceștia îl dețin în cadrul facultății, adresa de e-mail și eventual
numărul de locuri disponibile pentru licență sau disertație. De asemenea, se pot afla câteva
informații de bază și despre personalul administrativ al facultății.
Utilizatorii pot edita anumite informații direct de pe dispozitivul mobil (se va oferi access
doar la modificarea propriei adrese de e-mail și a parolei, iar în cazul profesorilor și numărul
locurilor disponibile pentru licență/disertație).
Pe partea de server administratorii pot modifica orice informații ale utilizatorilor, cum ar
fi numele, grupa sau cursurile opționale în cazul unui transfer, actualizarea fotografiilor etc.
Singura excepție este parola, care poate fi schimbată doar de către utilizator. Pentru a facilita
acestea, serverul dispune de o interfață prietenoasă, iar administratorii vor trebui să se
autentifice din motive de securitate. Studenții și profesorii nu vor dispune de drepturi de
administrator, iar cei care sunt excepții vor deține un cont separat de cel principal, utilizat
numai în acest scop.
Membrii noi ai facultății trebuie să se înregistreze, lucru care trebuie făcut la începutul
fiecărui an de studiu și oricând se realizează un transfer. Aceasta constă atât în înregistrarea
informațiilor și a fotografiilor persoanelor noi, cât și în actualizarea disciplinelor.
10
4. Abordare tehnică
Aplicația este alcătuită din două componente: un server ce va rula pe un dispozitiv de
tip desktop din facultate și clientul care va rula pe dispozitive mobile.
Serverul este programat în Java și deține o interfață simplă, ușor de folosit de către
administratori. Algoritmii importanți folosiți la recunoașterea facială, dar și codul ce face
legătura cu datele obținute de aceștia sunt scriși în C++ din motive de performanță și integrați
prin intermediul JNI - Java Native Interface. Serverul va avea acces la fotografiile tuturor
persoanelor înregistrate, acestea fiind stocate în directoare pe computerul pe care rulează
serverul și la informațiile referitoare la acestea, care se vor găsi într-o bază de date locală.
Clientul va putea fi instalat pe orice dispozitiv cu sistem de operare Android cu
versiunea 4.0 sau mai nouă (nivelul 14 de API). La nivelul clientului se poate face o poză ce
se va trimite la server pentru recunoașterea persoanei din ea. De asemenea, va conține o zonă
de editare a propriilor informații și o zonă de căutare. Comunicarea dintre server și client se
realizează prin socket-uri, iar datele se trimit prin stream-uri de input/output. Pentru realizarea
comunicării, clientul trebuie să fie conectat la rețeaua de internet a facultății.
Procesul de recunoaștere facială l-am împărțit în două etape: detectarea feței în
imagine și recunoașterea în sine. Pentru detectarea feței am utilizat metoda Haar Cascade
(cascadă Haar) sau mai bine zis funcționalitățile acesteia din biblioteca OpenCV. Pentru
partea de recunoaștere am folosit un algoritm de multi-clasificare implementat în biblioteca
dlib de tip OvO (one-vs.one trainer).
Biblioteca OpenCV (Open Source Computer Vision) este utilizată pentru performanță
computațională, axându-se în special pe aplicații în real-time [2]. Aceasta utilizează procesarea
pe mai multe nuclee și oferă suport pentru C/C++, Python, Java pe mai multe sisteme de
operare.
Metoda utilizată încorporează o cascadă de clasificatori ce sunt antrenați cu imagini
atât pozitive (care conțin fețe), cât și negative, din care se extrag caracteristici de tip haar.
„Fiecare caracteristică este o valoare obținută din diferența dintre două calcule de pixeli.” [2]
Acestea se obțin după diferite șabloane în două culori, fiecare calcul realizându-se cu ajutorul
pixelilor din zonele de o anumită culoare. Aceste șabloane însă trebuie aplicate în fiecare zonă
din imagine, în mai multe dimensiuni, ceea ce presupune foarte multe calcule. Totodată, doar
anumite caracteristici sunt de ajutor pentru recunoașterea unor părți ale feței umane. În acest
11
scop a fost introdus conceput de imagine integrală, respectiv AdaBoost pentru eliminarea
caracteristicilor nefolositoare.
Biblioteca dlib „conține algoritmi de învățare automată și unelte pentru crearea de
programe complexe în C++ ce rezolvă probleme reale.” Este folosită „în multe domenii cum
ar fi robotică, dispozitive încorporate, telefoane mobile și medii computaționale mari de
performanță ridicată.” [3]
IDE-urile folosite în acest proiect sunt Android Studio, Eclipse Java Neon și Microsoft
Visual Studio 2015.
Contribuții
În această lucrare am încercat să realizez o aplicație de tip asistent ușor de utilizat de
orice membru al facultății în scop de identificare sau informare. Aplicația client este realizată
pe sistemul de operare Android, componenta server poate rula pe un computer în cadrul
facultății, iar comunicarea dintre acestea se face prin intermediul rețelei locale. Ambele
componente au o interfață simplă și intuitivă, ușurând accesul utilizatorilor. Baza de date
conține informații în general despre persoane celebre, fiind construită doar pentru a testa
funcționalitățile programului.
Am împărțit lucrarea în două capitole referitoare la modul de funcționare a
componentelor aplicației (server și client) și unul ce cuprinde una din principalele
funcționalități explicată în detaliu, tehnologiile și conceptele utilizate în dezvoltarea sa și
implementarea acestora. Capitolele se regăsesc în următoare ordine:
Capitolul 1: Dezvoltarea componentei server
Capitolul 2: Dezvoltarea componentei client
Capitolul 3: Procesul de recunoaștere facială
12
Capitolul 1: Dezvoltarea componentei server
Serverul aplicației este de tip TCP (Transmission Control Protocol), comunicarea
realizându-se bidirecțional prin intermediul sockeților și acceptă conexiunile clienților în mod
concurent, implementând conceptul de thread pool (acumulare de fire de execuție).
1.1. Arhitectura componentei server
Figura 1: Diagramă reprezentativă a arhitecturii componentei server
13
În figura 1 se poate observa o reprezentare simplă a arhitecturii serverului. Aceasta
este descrisă în detaliu în subcapitolul 1.2.
1.2. Implementare
Serverul este programat în limbajul Java, folosind Eclipse Java Neon. Unele
funcționalități legate de recunoașterea facială sunt programate în C++, cu ajutorul IDE-ului
Microsoft Visual Studio 2015 și integrate prin intermediul JNI. Programul trebuie rulat de pe
un computer al facultății conectat la rețeaua de internet.
1.2.1. Structură și concepte
Figura 2: Structura componentei server
14
Serverul este împărțit în cinci pachete (fig. 2), fiecare ocupându-se de anumite
funcționalități ale acestuia:
mainPackage, care deține clasele principale ce inițializează programul, îl leagă de
baza de date locală și rulează firele de execuție. Totodată, se poate spune că este și un
pachet de control, de aici apelându-se metodele din celelalte pachete.
guiPackage, pachetul ce se ocupă de interfața serverului. Mai multe detalii despre
acesta se găsesc în subcapitolul 1.6.
workerPackage, care deține una din principalele funcționalități ale programului,
recunoașterea facială. Conținutul acestuia și modul de funcționare sunt explicate
detaliat în subcapitolul 1.3.
dataPackage, pachetul care accesează baza de date locală. Acesta conține modelele se
serializare utilizate și tranzacții de creare, actualizare, ștergere și de căutare. Modul de
funcționare a acestui pachet este explicat în subcapitolul 1.5.
addPackage, un pachet adițional în care se află clase ajutătoare pentru celelalte
pachete.
În cadrul serverului am utilizat mai multe concepte sau versiuni ale acestora. Cele mai
importante sunt șabloanele de proiectare mvc, singleton și observer.
Figura 3: Conceptele utilizate în cadrul serverului
15
Model-View-Controller (MVC) este un șablon arhitectural ce împarte o aplicație în
trei componente strâns legate între ele: modelul, view-ul și controller-ul. Modelul este partea
ce se ocupă cu datele deținute de program și tot ce are legătura cu acestea (interogări ale bazei
de date, autentificare, modificări de date, procesarea informațiilor noi etc.). View-ul
reprezintă partea grafică a aplicației, încorporând tot ce ține de ferestre, text afișat, butoane,
cu care va interacționa utilizatorul. Componenta Controller leagă modelul de view, preluând
comenzile pe care utilizatorii le dau prin intermediul interfeței, procesând datele respective și
oferind un eventual răspuns.
Am utilizat MVC în cadrul serverului, sau mai exact o variație a acestui concept.
View-ul este încorporat de pachetul guiPackage, controller-ul se regăsește în pachetul
principal, însă modelul este „divizat” în mai multe pachete; astfel există clase de procesare a
datelor atât în dataPackage (ce are access la informațiile din baza de date), cât și în
workerPackage (unde au loc principalele operații de procesare a imaginilor).
Singleton este un șablon de proiectare care presupune restricționarea instanțierii unei
clase la un singur obiect. Altfel spus, este o clasă cu un singur obiect. Acest lucru este necesar
atunci când avem nevoie de coordonarea anumitor acțiuni în întregul program.
Am implementat acest concept în cadrul clasei Controller, deoarece pe lângă faptul că
aveam nevoie de o singură instanță a clasei, era necesar ca unele metode și variabile să fie de
tip static pentru a putea fi accesate sau apelate din View.
Șablonul Observer este utilizat atunci când anumite obiecte trebuiesc notificate
automat de modificări aplicate asupra unui anumit alt obiect. Altfel spus, este necesar atunci
când există o dependență de unu-la-mai-mulți între obiectul modificat și celelalte. Acest
Observer este atașat obiectului respectiv și conține metode de notificare apelate în cazul
modificării stării obiectului; obiectul propriu-zis nu cunoaște obiectele notificate și nu se află
în contact direct cu ele.
În acest caz, observer-ul este atașat clasei WorkerRunnable din pachetul
workerPackage. Când în cadrul acestuia se realizează o operație, observer-ul notifică instanța
clasei Controller și afișează informații despre operația realizată în istoricul serverului, care
poate fi citit de administrator în orice moment.
16
Altfel spus, observer-ul ce aparține serverului implementează conceptul de Logging,
adică păstrarea (de obicei într-un fișier) a unor mesaje, erori, excepții sau a altor evenimente
apărute în cadrul unui sistem de operare sau a oricărui alt tip de program. [4] În acest caz, sunt
afișate pe ecran operațiile aplicate la nivel de server, iar în cazul în care acestea sunt cerute de
client se specifică și care anume (numărul de ordine al clientului).
Pe lângă pachete, serverul mai conține în directorul external fișiere .jar ale
bibliotecilor externe utilizate și elemente grafice încapsulate în interfață. Directorul images
conține imaginile persoanelor din facultate, iar în PrevalenceBase sunt serializate informațiile
despre acestea.
1.2.2. Server TCP concurent
TCP este un protocol de comunicare în rețea ce se concentrează asupra efectuării unei
conexiuni stabile prin care se trimit fluxuri de octeți din ambele direcții. Acesta folosește un
alt protocol de comunicare de nivel mai jos (IP = Internet Protocol) pentru a stabili
conexiunea. Astfel, datele trimise sau primite sunt convertite în pachete numite datagrame IP.
Deși de obicei nu se poate garanta sosirea datagramelor la destinație (în cazul protocolului
UDP nu se efectuează o conexiune, deci pachetele pot să nu ajungă sau să fie primite în altă
ordine decât au fost trimise), protocolul TCP se ocupă de acest lucru, prin retrimiterea
pachetelor și eventual alertarea programatorului în cazul lipsei unei rute sau pierderea unei
conexiuni. [5]
Un server poate fi iterativ sau concurent. Cele iterative primesc o singură cerere odată
de la un client și nu vor procesa o altă cerere până când nu este satisfăcută prima; acest tip de
server este implementat atunci când serviciul oferit are o durată scurtă de timp. Se utilizează
un server concurent atunci când nu se știe durata procesării cererilor făcute de clienți. Acestea
acceptă toate cererile și creează câte un proces pentru fiecare. Pe scurt, un server concurent
procesează mai multe cereri în paralel.
Un thread pool reprezintă un grup de fire de execuție cărora li se asociază anumite
operații. În cadrul unui server se poate utiliza acest concept pentru a limita numărul de
conexiuni, lucru ce are anumite avantaje. În primul rând, dacă operațiile efectuate la nivel de
server necesită memorie mai multă, lățime de bandă mai mare sau un timp mai lung de
procesare și acesta acceptă mai multe conexiuni în paralel, va fi supraîncărcat și va întâmpina
17
probleme de performanță. În plus, cu cât sunt mai multe cereri în paralel, cu atât mai lent vor
fi procesate. De aceea, limitarea numărului de fire de execuție poate micșora riscul de apariție
a unor probleme ca suprasolicitarea resurselor.
Din aceste motive, am decis să implementez acest concept în cadrul serverului, fixând
o limită de 20 de clienți. În acest scop, am utilizat interfața ExecutorService din Java, un
mecanism asincron (în paralel) de execuție care efectuează instrucțiuni în fundal;
ExecutorService este o implementare pentru thread pool.
Sursă de cod 1: Utilizarea interfeței ExecutorService
Declararea grupului de fire de execuție se realizează ca în sursa de cod 1, unde se dă
ca parametru numărul maxim de fire. Atunci când un client cere stabilirea unei conexiuni, este
apelată funcția execute, care asignează socketul corespunzător unei noi instanțe a clasei
WorkerRunnable, ce se va ocupa de cererea clientului respectiv.
1.2.3. Procesarea imaginilor
Fotografiile făcute pe dispozitivele Android ajung la server sub forma unor vectori de
octeți. Acestea sunt salvate cu extensia jpg pentru a fi mai apoi preluate de biblioteca
OpenCV. Am decis să salvez imaginile astfel în urma efectuării unor teste. Am încercat
salvarea imaginilor în trei moduri; cu extensia png, cu extensia jpg și cu ajutorul bibliotecii
PngEncoder. [6] Am folosit 100 de imagini în cadrul testelor, cu diverse rezoluții între
339x200 și 4252x2835. Majoritatea sunt fotografii făcute cu telefonul mobil.
Testul a fost executat în felul următor: programul a parcurs toate imaginile dintr-un
director, le-a importat și transformat în vectori de octeți, pe care apoi le-a salvat în cele trei
moduri. Clasa ImageProcessing din sursa de cod 2 se ocupă de acest lucru, cronometrând
durata fiecărei metode pentru a o putea alege pe cea mai rapidă. Am repetat testul de încă
nouă ori după prima executare, pentru obținerea unui rezultat cât mai corect.
18
Sursă de cod 2: Clasa de procesare imagini ImageProcessing
În cadrul testului se face câte un total pentru fiecare mod de salvare în variabilele
totalPng, totalJpg și totalEnc. Rezultatele obținute ca timp total de salvare a celor 100 de
imagini se găsesc în tabelul 1.
Extensia png Extensia jpg PngEncoder
61 ms 54 ms 51 504 ms
64 ms 65 ms 47 459 ms
66 ms 51 ms 48 210 ms
65 ms 40 ms 47 313 ms
57 ms 104 ms 47 758 ms
119 ms 213 ms 54 436 ms
125 ms 72 ms 50 980 ms
122 ms 58 ms 51 737 ms
50 ms 64 ms 57 078 ms
61 ms 57 ms 52 202 ms
Tabelul 1: Timpul de salvare a 100 de imagini în cele trei moduri, în cinci teste
În medie, imaginile au fost salvate în primul mod în 79 milisecunde, în cel de al doilea
în 77.8 milisecunde, iar în cel de-al treilea mod în 50 867.7 milisecunde (50.868 secunde).
Biblioteca PngEncoder ar trebui să salveze imagini de cinci/șapte ori mai repede decât
metodele obișnuite de scriere (ImageIO) [6]. Însă în acest caz, se realizează un pas în plus,
convertirea vectorului de octeți într-un BufferedOutputStream pe lângă apelarea funcției
encode din bibliotecă. Prin compararea rezultatelor, am decis utilizarea salvării cu extensia
jpg. În graficul 2 se pot observa aceste rezultate.
19
Pentru decuparea imaginilor (după detectarea fețelor) am folosit o funcționalitate din
biblioteca OpenCV, având ca parametri reprezentarea Mat a imaginii și coordonatele zonei ce
trebuie decupată, ca în sursa de cod 3.
Sursă de cod 3: Decuparea imaginilor
Graficul 2: Timpul total de salvare a celor 100 de imagini cu extesiile png (albastru) și jpg (roșu)
Grafic realizat cu http://www.onlinecharttool.com
Din moment ce pentru detectarea fețelor culorile nu sunt necesare, înainte de aplicarea
clasificatorului pe imagine aceasta este convertită în mod grayscale, adică toate culorile sunt
transformate în nuanțe de gri. Acest lucru oferă și un plus de performanță algoritmului de
detectare. Conversia se realizează cu ușurință prin intermediul unei funcționalități a bibliotecii
OpenCV, citind imaginea direct în mod grayscale. Acest lucru se poate observa în sursa de
cod 4, unde este inițializată reprezentarea Mat a imaginii. Ultimul parametru a funcției imread
reprezintă tipul de conversie, 0 însemnând modul grayscale.
20
Sursă de cod 4: Conversia imaginii în grayscale
1.2.4. Autentificare
Pentru a avea access la componenta server, administratorul trebuie să se autentifice
folosind un cont cu drepturi corespunzătoare. Altfel, serverul nu va putea nici măcar să fie
pornit. Verificarea drepturilor se realizează printr-o interogare în baza de date, unde avem un
câmp care specifică acest lucru.
Procesul verificării autenticității unui cont se realizează astfel: este verificată adresa de
e-mail, este comparată parola introdusă cu cea înregistrată, iar în cazul în care datele oferite
de utilizator trec de primele două etape, se verifică dacă acesta are drepturi de administrator.
Parolele salvate în baza de date nu sunt reținute în format brut, ci sunt criptate mai întâi. La
prima încărcare a datelor dintr-un fișier extern, se folosește o parolă de bază pentru toți
utilizatorii, cu excepția administratorilor. Se recomandă însă schimbarea acesteia imediat
după pornirea serverului.
Criptarea parolei se realizează cu ajutorul AES (Advanced Encryption Standard), mai
exact implementarea acestui concept din pachetul crypto din Java. Este una dintre cele mai
cunoscute și folosite metode de criptare și este implementată în mai multe limbaje. În Java
este adăugată sub forma extensiei oficiale JCE (Java Cryptography Extension). Am utilizat
această implementare de bază cu o cheie pe 128 de biți. Conținutul funcției de criptare este
prezentat în sursa de cod 5.
Sursă de cod 5: Funcția de criptare a parolelor
21
1.3. Recunoașterea facială
La nivelul serverului se realizează întregul proces de detecție și recunoaștere a fețelor,
cu excepția selectării manuale a unei fețe. Clasa FaceProcessing cuprinde aceste
funcționalități. La inițializarea unui obiect de acest tip, se încarcă și biblioteca, la fel ca în
sursa de cod 4.
1.3.1. Implementarea etapelor de recunoaștere facială
Pentru detectarea fețelor, în primul rând este nevoie de un clasificator de tip cascadă.
Un clasificator identifică din ce categorie dintr-un set predefinit fac parte niște date noi.
Clasificatorii sunt utilizați în filtre de spam, recunoaștere de obiecte/fețe, recunoașterea unei
boli după simptome etc. Sunt una din metodele folosite în recunoașterea unui șablon.
„Cascada” se referă la aplicarea mai multor clasificatori (mai mulți pași) asupra unei zone de
interes până când datele sunt respinse sau acceptate la sfârșit, după ce au trecut de toți pașii.
Acest clasificator pe care l-am folosit încarcă un fișier xml ce conține date pre-
antrenate din biblioteca OpenCV. Am ales utilizarea unui clasificator frontal al fețelor, pe care
l-am încărcat ca în sursa de cod 6.
Sursă de cod 6: Încărcarea fișierului xml de clasificatorul utilizat la detectarea fețelor
După încărcarea clasificatorului și conversia imaginii, este apelată funcția
detectMultiScale ca în sursa de cod 7, care detectează fețele din imagine și returnează zonele
în care se află acestea. Ca parametri se folosesc imaginea, vectorul în care vor fi salvate
regiunile fețelor, factorul de scalare, numărul minim de vecini și dimensiunea minimă și
maximă a ferestrei de detecție. Factorul de scalare se referă la cât de mult este redusă
imaginea la fiecare scalare, iar numărul de vecini reprezintă câți vecini poate avea fiecare
candidat. După apelarea funcției, se realizează selecția feței la nivelul clientului.
22
Sursă de cod 7: Funcție de detectare a fețelor
Serverul primește fața selectată de utilizator sub forma coordonatelor unui dreptunghi
ce o încadrează. Din imaginea primită dinainte de la client, se va decupa numai fața selectată,
salvându-se ca imagine nouă în format grayscale. Pe imaginea obținută se aplică un algoritm
de extragere a punctelor principale ce caracterizează o față. În acest scop am utilizat un fișier
.dat de predicție a formelor, în acest caz o față. Încărcarea fișierului de predicție se face ca în
sursa de cod 8. Dând ca argument imaginea, se returnează un obiect care conține 68 de
puncte, sau mai exact coordonatele acestora.
Sursă de cod 8: Încărcarea modelului pentru predicție
Aceste puncte nu vor fi date mai departe funcției de recunoaștere, ci se vor calcula
distanțele euclidiene între anumite puncte pe care le-am considerat importante, distanțe care
apoi sunt raportate la înălțimea sau lățimea feței. Aceste 17 distanțe vor fi încorporate într-o
matrice cu o singură coloană (sau un vector-coloană), după care algoritmul de recunoaștere va
face o predicție. Modelul obținut în urma antrenării este încărcat și din acesta este
deserializată funcția de recunoaștere apelată prin JNI.
1.3.2. Antrenarea algoritmului de recunoaștere facială
Pentru antrenarea algoritmului de recunoaștere am folosit inițial baza de date PubFig,
oferită de departamentul de Computer Science al Universității Columbia. [7] [8] Aceasta conține
200 de oameni cunoscuți (actori, sportivi etc.), având în total aproximativ 60 000 de imagini.
Baza de date oferă două liste cu nume și două cu url către imagini, numele persoanei aflate în
imagine și alte proprietăți (numărul imaginii, coordonatele dreptunghiului în care se află fața
persoanei etc.).
23
Am realizat un mic program în C++ care descarcă câte 25 de imagini pentru fiecare
persoană din listele respective, ajungând la un număr de 5 000 de imagini. Am împărțit
pregătirea acestora pentru antrenare în patru etape:
descărcarea imaginilor. În această etapă am introdus numărarea imaginilor, pentru a
mă asigura că vor fi destule pentru procesul de antrenare. De aceea, la incrementarea
numărului de imagini pentru o persoană, m-am asigurat că accesarea paginii nu
returnează un cod de eroare. Pentru descărcarea imaginilor am folosit funcția
URLDownloadToFile din Windows API, aranjându-le în directoare create cu funcția
CreateDirectory.
Sursă de cod 9: Descărcarea unei imagini
verificarea imaginilor descărcate. Din cauză că unele imagini nu se mai găsesc la
url-urile respective și au fost descărcate în schimb imagini albe cu text corespunzător
sau unele au fost descărcate de mai multe ori de la adrese diferite, am realizat o
verificare manuală. În cazul în care după ștergerea imaginilor ce nu puteau fi folosite
au rămas mai puțin de 12 pentru o persoană, am descărcat manual astfel încât pentru
fiecare persoană să existe limita minimă respectivă de imagini. După efectuarea
acestui pas au rămas 3 717 imagini din 5 000.
decuparea imaginilor. Imaginile descărcate au fost decupate conform coordonatelor
primite odată cu descărcarea lor. Am ales utilizarea acestora și nu a detectorului facial
implementat deja deoarece unele imagini conțineau mai multe persoane. La decuparea
unor imagini au apărut erori, dar am ales să le ignor deoarece nu a scăzut consistent
numărul de imagini, după această etapă rămânând 3 694 din 3 715. Imaginile decupate
au fost salvate în mod grayscale.
24
extragerea punctelor. Din imaginile obținute, am extras mai apoi punctele necesare
antrenamentului și am împărțit fișierele text în care acestea au fost salvate în
directoare de antrenament, respectiv de testare. Am păstrat pentru fiecare persoană
câte 10 imagini de antrenament, restul urmând a fi folosit pentru a testa algoritmul.
Algoritmul de recunoaștere facială este realizat prin modificări aduse unui algoritm
din biblioteca dlib. Acesta creează un „antrenor” de tip one-vs.-one care conține la rândul său
două instanțe de tip kernel, unul polinomial și unul de tip RBF (radial basis function), utilizați
de un „antrenor” de tip KRR (Kernel Ridge Regression), respectiv de un SVM (Support
Machine Vector). Primul se ocupă de ocupă de subproblema clasificării binare, iar celălalt de
subproblema de tip clasa 1 vs. clasa 2.
După inițierea componentelor specificate mai sus, am realizat validarea încrucișată a
datelor prin două împăturiri. Asta înseamnă că datele unei persoane sunt împărțite în două
seturi și sunt folosite pe rând ca date de antrenament, respectiv de testare și invers. Înainte de
aceasta însă, sunt amestecate la întâmplare datele.
Antrenamentul este inițiat după terminarea procesului de validare încrucișată. Funcția
de predicție obținută în urma antrenării este serializată, pentru a putea fi folosită oricând un
client trimite trimite o cerere de recunoaștere a feței.
În urma antrenării algoritmului cu punctele extrase din imaginile preluate din baza de
date de mai sus, nu am obținut un rezultat satisfăcător. Am realizat mai multe antrenări cu
seturi de mărime diferită de imagini, cu validare încrucișată de două tipuri sau fără, dar
procentajul cel mai mare obținut a fost de 21%. Din acest motiv, am re-antrenat algoritmul
folosind imagini dintr-o altă bază de date, Faces94 [9]. Aceasta conține 153 de persoane, toate
imaginile fiind fotografiate frontal. Am ales această modificare deoarece este mai eficientă
pentru tipul de detector al fețelor și extragerea punctelor implementate în server. Procentajul
obținut pentru aceste seturi noi a crescut considerabil, ajungând la 41%. La creșterea
numărului de imagini din setul de antrenament, respectiv setul de testare procentajul scade
foarte puțin, cu aproximativ 2%.
25
1.4. Comunicarea cu partea de client
Comunicarea dintre server și clienți se realizează prin intermediul sockeților, Socket în
cadrul clienților și SocketServer la nivel de server. Aceștia sunt de tip TCP, oferind
comunicare bidirecțională și sigură. „Clasa Socket reprezintă un canal de comunicare între
două porturi de comunicare TCP aparținând unuia sau mai multor dispozitive.” [5]
Un socket al unui client este conectat automat la socketul serverului a cărui adresă și
port o primește când este creat, nefiind necesară o funcție de conectare. În cazul în care nu
primește un răspuns de la server, constructorul se poate bloca pentru o perioadă de timp.
Acesta nu este un comportament obișnuit și este cauzat de mai mulți factori, cum ar fi
sistemul de operare, însă poate avea loc. Din acest motiv am realizat conexiunea sockeților în
fire de execuție separate, astfel încât serverul și clienții vor continua să ruleze în cazul unei
probleme de conexiune.
Conexiunea dintre server și client se realizează doar atunci când utilizatorul
componentei client cere date sau confirmare de la server. Socket-ul clientului inițiază
comunicarea, trimite cererea pe care apoi serverul o procesează și răspunde cu datele cerute,
după care conexiunea este încheiată. În cazul închiderii aplicației client, conexiunea este
întreruptă fără a provoca daune serverului.
1.5. Baza de date
La nivelul serverului sunt salvate atât fotografiile persoanelor din facultate
înregistrate, cât și informațiile despre acestea. Imaginile sunt clasificate în directoare numite
după numele complet al persoanelor respective, iar informațiile sunt serializate separat în
directorul PrevalenceBase după cum am menționat în subcapitolul 1.2.1.
Implementarea bazei de date și a tuturor funcționalităților oferite de aceasta se
regăsesc în pachetul dataPackage al serverului. În figura 4 se pot observa toate clasele din
acest pachet. Acestea se ocupă de obținerea și prelucrarea datelor din baza de date locală.
26
Figura 4: Pachetul dataPackage, ce conține baza de date
Pentru serializarea datelor am folosit biblioteca Prevayler din Java. Aceasta este o
bibliotecă de tip open-source folosită la serializarea obiectelor. „Este o implementare a
șablonului de proiectare Prevalent System, care ține obiectele în memorie pentru o accesare
mai ușoară, iar tranzacțiile sunt salvate în cazul în care este nevoie de recuperarea stării
sistemului.” [10] Prevayler oferă tranzacții mai rapide decât bazele de date obișnuite, deoarece
ține obiectele în memoria RAM pe toată durata rulării programului. Acest lucru nu prezintă un
impact prea mare asupra performanței, deoarece numărul persoanelor din baza de date este
limitat, iar cantitatea informațiilor puse la dispoziție de server este mică.
Sursă de cod 10: Inițializarea bazei de date
Prevayler este inițializat ca în sursa de cod 10. Este încărcată baza de date, dacă ea
există deja sau altfel este creată una nouă. Un obiect de tip Person deține toate informațiile
despre o persoană. Aproape toate tranzacțiile implementate în server folosesc obiecte de tip
Person pentru accesarea sau modificarea datelor.
27
Pachetul dataPackage conține un controller al său din care sunt executate tranzacțiile
și la care are acces componenta controller din proiectarea MVC a serverului. În sursa de cod
10 este prezentat constructorul acestui controller, urmând ca în orice accesare a bazei de date
să se apeleze metode asupra acelei variabile prevayler. Un exemplu este adăugarea unei
persoane, din sursa de cod 11, unde se execută o metodă prestabilită din clasa de creare
CreatePersonTransaction.
Sursă de cod 11: Executarea interogării de creare a unei persoane noi
Clasa Root realizează o mapare între numele persoanei și obiectul de tip Person
corespunzător. De asemenea, conține o mapare între adresa de e-mail a unei persoane și
numele acesteia. Motivul pentru care am introdus o a doua mapare este că în cazul
autentificării sau modificării unor date la nivel de client este necesară efectuarea unei
interogări folosind adresa de e-mail, lucru care nu este posibil altfel.
O tranzacție de preluare a unei persoane din baza de date se realizează cu ajutorul
clasei din sursa de cod 12. Ca argument se folosește numele complet, considerat o „cheie
unică” în baza locală. Metoda getPersons() accesează map-ul din clasa Root și returnează
persoana cu numele dat ca argument.
Sursă de cod 12: Căutarea unei persoane în baza de date
28
Similar tranzacției GetPerson, se poate prelua o persoană și prin intermediul adresei
de e-mail. Procedura constă în obținerea numelui persoanei din cel de-al doilea map, după
care este efectuat același lucru ca în funcția de interogare de mai sus.
Tranzacția de creare a unei persoane se realizează ca în sursa de cod 13. Aceasta este
apelată la adăugarea unei noi persoane în baza de date. De asemenea, serverul prezintă
funcționalitatea de importare a întregii baze de date dintr-un fișier, care este parsat de clasa
LoadInfo, după care toate datele noi (aflate prin verificare) sunt serializate și adăugate, iar
cele deja existente sunt actualizate, dacă au avut loc modificări. Similar se face și operația de
actualizare a datelor.
Sursă de cod 13: Adăugarea unei persoane în baza de date
Pachetul conține și o clasă care se ocupă de preluarea tuturor numelor persoanelor
înregistrate, pas necesar căutării în timp real implementate pe componenta client. De
asemenea, este responsabil și cu verificarea datelor de autentificare.
1.6. Interfața serverului
Pentru utilizarea cu ușurință a componentei server de către administratori, am oferit
acesteia o interfață simplă și prietenoasă. Pentru implementarea interfeței am folosit pachetul
Swing din Java. Acesta face parte din JFC (Java Foundation Classes), un API de la Oracle ce
ajută la construirea interfețelor grafice pentru programe Java. Pe lângă componentele de bază
(butoane, panouri, meniuri de tip dropdown), oferă și access la componente mai complexe,
cum ar fi tabele, arbori sau liste. Este de asemenea independent din punct de vedere a
platformei.
29
1.6.1. Fereastra principală
Tot ce ține de interfața grafică se găsește în clasa MainUI. Componentele ferestrei
principale sunt bara de meniu, zona în care se poate verifica starea serverului și panoul cu
istoricul. Am structurat fereastra astfel pentru a fi ușor de intuit și utilizat. În cazul apariției
unor probleme în cadrul aplicației, se vor primi mesaje de erorare în care se va specifica
concret cauza. Tema interfeței este cea de bază a sistemului de operare, în acest caz tema
Aero de la Windows 7. În figura 5 se poate observa interfața generală a serverului.
Figura 5: Fereastra principală a serverului
1.6.2. Fereastra de autentificare
Înainte de a accesa fereastra prezentată mai sus, utilizatorul trebuie să se autentifice. Acest
lucru se poate face introducând datele contului într-o fereastră de tip dialog, ca în figura 6.
Implementarea interfeței acestei ferestre se găsește în clasa LoginDialog din pachetul guiPackage și
este destul de simplă, extinzând clasa de bază JDialog din Swing și adăugând particularitățile
corespunzătoare.
30
Figura 6: Fereastra de autentificare
În cazul introducerii unor date incorecte, utilizatorul (administratorul) va primi unul din
mesajele de eroare prezentate în figura 7, după caz. La fel ca în acest exemplu, sunt tratate și alte
excepții la nivel de server, fiecare declanșând un mesaj de eroare personalizat, ce ajută administratorul
la identificare cauzei erorii respective.
Figura 7: Mesaje de eroare ce pot apărea la autentificare
1.6.3. Bara de meniu
Bara de meniu conține 3 submeniuri: Server, Database și Features. Din submeniul
Server se poate porni/opri/reseta serverul. Am adăugat aceste opțiuni deoarece înainte de
pornirea serverului, este nevoie de încărcarea bazei de date din fișierele în care s-a făcut
serializarea. Deși acest lucru se putea face și automat, am decis încărcarea manuală deoarece
am oferit și opțiunea de a importa baza de date dintr-un fișier extern (cu condiția ca acesta să
fie scris conform unor reguli prestabilite, pentru a putea fi parsat).
31
Figura 8: Bara de meniuri și submeniurile corespunzătoare
În figura 8 se pot observa comenzile ce pot fi alese din submeniuri. În submeniul
server este disponibilă la început doar comanda de start, urmând ca după accesarea ei să se
activeze celelalte două, iar cea de start să fie dezactivată. Submeniul Database conține trei
comenzi: încărcarea bazei de date din fișierele serializate, lucru necesar înainte de pornirea
serverului (fără de care utilizatorul primește un mesaj de eroare), încărcarea informațiilor în
baza de date dintr-un fișier extern (în cazul în care nu poate fi parsat, se primește un alt mesaj
de eroare) și comanda de export a bazei de date într-un fișier text, căruia mai apoi pot fi aduse
modificări și poate fi importat din nou.
Prin import și export administratorul are acces direct asupra informațiilor din baza de
date cu excepția parolei, care nu poate fi modificată decât de pe componenta client de către
utilizatorul autentificat care deține acel cont; numai pentru persoanele noi adăugate într-un
fișier de import se salvează parola în baza de date. De asemenea, dacă datele unei persoane
sunt șterse dintr-un fișier exportat (decrementându-se și numărul de pe primul rând al
fișierului) atunci prin importarea acelui fișier persoana respectivă va fi ștearsă din baza de
date, fără însă a se șterge și directorul de fotografii ale sale. Acesta trebuie șters manual.
Submeniul Features conține o singură comandă, prin care administratorul poate
extrage toate punctele din fețele persoanelor din baza de date. Acest lucru este folositor în
cazul în care se dorește repetarea antrenării algoritmului de recunoaștere.
32
1.6.4. Zona de stare și istoricul
În figura 9 este prezentată zona de stare atunci când atât serverul, cât și baza de date
sunt active. Deoarece serverul nu poate fi pornit fără ca baza de date să fie încărcată
(utilizatorul primește un mesaj de eroare dacă încearcă să facă acest lucru), singura stare ce nu
se regăsește aici este cazul în care doar baza de date este încărcată.
Figura 9: Zona de stare după încărcarea bazei de date și pornirea serverului
De asemenea, se poate observa și în zona istoricului că serverul este activ și așteaptă
conexiuni la portul 1234. Liniile sunt numerotate, pentru a putea parcurge istoricul cu
ușurință, iar zona este de tip scrollable (poate fi derulată) și nu are limită de linii deoarece am
vrut să păstrez un istoric complet de la pornirea serverului, fără a se pierde nici o
comandă/funcționalitate realizată.
În zona de stare, sub statusul bazei de date și a serverului sunt reprezentați și clienții
conectați, sub forma unui arbore. La conectarea cu succes a fiecărui client se introduce un nod
în arbore cu numărul de ordine, adresa IP și portul. La încheierea sau întreruperea conexiunii,
nodul respectiv clientului este șters automat din arbore. Acest lucru informă administratorul
asupra clienților conectați în orice moment.
Capitolul 2: Dezvoltarea componentei client
Componenta client este programată în limbajul Android cu ajutorul IDE-ului Android
Studio. Poate fi instalat pe orice dispozitiv cu sistem de operare Android, cu condiția ca acesta
să aibă versiunea cel puțin 4.0 (Ice Cream Sandwich), adică nivelul 14 al API-ului. Motivul
pentru care am ales să realizez aplicația client pe acest sistem de operare este că în ultimii ani
Android a dominat piața dispozitivelor mobile cu un procent de 86.8%. [11] De asemenea,
33
având în vedere că la facultatea noastră se predau cursuri de programare pe Android, am
presupus că mulți studenți dețin dispozitive mobile cu acest sistem de operare. În orice caz,
rescrierea programului pentru alte sisteme de operare mobile se poate face cu ușurință.
2.1. Arhitectura componentei client
Figura 10: Diagramă arhitecturală a componentei client
În figura de mai sus am prezentat o diagramă simplă a componentei server. Activitățile
sunt încadrate în dreptunghiuri albastre, celelalte elemente vizuale conținute de aceste
activități se regăsesc în dreptunghiuri roșii, respectiv în dreptunghiul galben, iar în
dreptunghiuri albe sunt componente externe programului, comunicarea cu acestea fiind
reprezentată prin linii punctate. În subcapitolul 2.2 am explicat în detaliu cum funcționează
aceste elemente ce alcătuiesc arhitectura componentei client.
34
2.2. Implementare
Pe lângă elementele prezentate în figura 10, în aplicație sunt implementate și mesaje
de informare sau de eroare cu scopul de a facilita experiența utilizatorului și totodată de a-l
ghida asupra pașilor pe care trebuie să-i urmeze pentru a accesa anumite funcționalități. De
asemenea, aceștia sunt prezentați în detaliu și în zona de Help.
2.2.1. Permisiuni și activități
Aplicațiile Android au nevoie uneori de permisiuni de accesare a unor componente
hardware sau software ale sistemului de operare. Permisiunile trebuiesc menționate în fișierul
AndroidManifest.xml al proiectului. Acesta este unul din fișierele principale ale proiectului și
conține permisiuni necesare, activitățile din aplicație, Intent-uri și setări globale ale aplicației,
cum ar fi iconița ce va reprezenta aplicația în meniu, tema sau numele aplicației.
Figura 11: Fișierul AndroidManifest.xml
35
O activitate face legătura între utilizator și funcționalitățile din spatele aplicației. De
exemplu, activitatea InfoActivity este responsabilă numai cu afișarea informațiilor primite de
la server. Astfel, orice activitate își creează o „fereastră” ce conține elemente cu care
utilizatorul poate interacționa. Activitățile conțin anumite metode în care dezvoltatorul poate
preciza ce se întâmplă cu datele deținute de acea activitate sau cu activitatea în sine în
anumite cazuri: onCreate, onStart, onPause, onDestroy etc. De exemplu, funcția onCreate se
regăsește în fiecare activitate și trebuie de obicei suprascrisă.
Un Intent este o descriere abstractă a unei operații ce trebuie îndeplinită. [12] Acestea se
folosesc pentru a face trecerea de la o activitate la alta sau pentru a accesa un serviciu sau o
componentă hardware a dispozitivului.
În aplicație am avut nevoie de trei permisiuni, care se pot observa și în figura 11.
Principala funcționalitate a sistemului de operare de care aplicația are nevoie este conexiunea
la Internet. Pe lângă aceasta, am introdus și permisiunile de acces la serviciul de utilizare a
camerei telefonului și la memoria internă a acestuia. Pentru a putea face fotografii din
program este însă nevoie de acces și la componenta hardware, lucru care se face cu ajutorul
etichetei „uses-feature”.
Aplicația conține 7 activități, fiecare axându-se pe o anumită funcționalitate:
MainActivity, principala activitate ce conține un mesaj de întâmpinare și butoane care
duc spre alte activități.
DetectionActivity, care inițiază accesul la camera telefonului, afișează imaginea și
face conexiunea cu serverul în scopul recunoașterii unei fețe.
SearchActivity, în care utilizatorul poate căuta o persoană după nume și care face
legătura cu activitatea de afișare a informațiilor.
BookmarkActivity, unde utilizatorul poate vedea sub formă de listă numele unor
persoane pe care le salvase din căutări anterioare și șterge din aceastea.
InfoActivity, o activitate alcătuită din fragmente în care sunt afișate informațiile
despre o persoană primite de la server, fie din căutarea după nume, recunoașterea
facială sau încărcarea acestora din salvările locale.
SettingsActivity, zona în care un utilizator își poate modifica date legate de cont.
36
HelpActivity, activitatea de „ajutor” care oferă utilizatorului informații asupra
funcționalităților oferite de aplicație și pașii pe care trebuie să îi urmeze în utilizarea
acestora.
Pentru realizarea activităților InfoActivity și HelpActivity am utilizat fragmente.
Acestea sunt plasate în cadre prestabilite în arhitectura activității și pot fi schimbate cu altele
oricând. Un fragment reprezintă un anumit comportament sau o parte a interfeței grafice,
avantajul cel mai mare acestora fiind faptul că pot fi refolosite în alte componente grafice sau
chiar alte activități. [12] Fragmentele pot fi comparate cu niște șabloane în care datele pot fi
modificate cu ușurință, păstrând același format și aceleași elemente grafice.
2.2.2. Autentificare
Înainte de încărcarea activității principale în aplicație, utilizatorul trebuie să
completeze câmpurile cu datele dale de autentificare. Acestea fac parte dintr-o fereastră care
nu poate fi închisă, încercându-se astfel păstrarea unui nivel de securitate ridicat. Verificarea
datelor de autentificare se realizează la nivelul serverului exact ca verificarea contului de
administrator, singura diferență fiind faptul că utilizatorul are nevoie de drepturi speciale la
nivel de client. Parola introdusă este criptată înainte de a fi trimisă cu aceeași cheie,
micșorând astfel riscul de interceptare a datelor utilizatorului. Verificarea se face în felul
următor: după conectarea prin socket la server se trimite adresa de e-mail, iar dacă acesta este
înregistrată, se trimite forma criptată a parolei care este comparată cu cea din baza de date;
dacă parola este corectă se primește de la server sub formă de confirmare categoria din care
face parte utilizatorul (student, profesor, sau personal administrativ).
Adresa de e-mail și parola criptată sunt memorate și utilizate la modificarea setărilor
din SettingsActivity. Adresa este necesară pentru identificarea utilizatorului în baza de date,
iar parola pentru o dublă-verificarea înainte de schimbarea sa.
37
2.2.3. Accesarea camerei dispozitivului
Figura 12: Intent-ul care se ocupă de accesarea camerei
Camera foto a dispozitivului este utilizată cu ajutorul funcțiilor din figura de mai sus.
Mai întâi este creat un Intent care cere inițiază programul de bază de făcut fotografii. Acesta
trimite rezultatul celei de-a doua metode, care verifică dacă au fost returnate codurile corecte
și dacă s-au primit date în urma efectuării Intent-ului. Am făcut această verificare deoarece
este posibil ca utilizatorul să închidă serviciul respectiv fără a face o fotografie, ceea ce ar
produce erori în metoda de trimitere a datelor către server.
De asemenea, după ce utilizatorul face o poză, aceasta este afișată în activitate în
DrawView. Acesta este un element grafic extins dintr-un ImageView care permite
utilizatorului să „deseneze” pe el. Mai multe detalii despre acest element se pot găsi în
subcapitolul 2.4.3, unde este prezentată și interfața acestuia.
38
2.2.4. Selectarea feței
După trimiterea fotografiei la server și primirea rezultatului, ce constă în coordonatele
tuturor fețelor din imagine dacă s-a găsit cel puțin una, utilizatorul trebuie să aleagă o față ce
vrea să fie recunoscută. Pentru a facilita selectarea fețelor, pe imaginea afișată se pot vedea
pătrate ce încadrează fețele găsite. Utilizatorul trebuie doar să selecteze una și să apese
butonul pentru confirmare.
Figura 13: Pregătirea pentru selecția feței
Coordonatele pătratelor ce încadrează fețele sunt primite de la server, apoi desenate pe
ImageView, căruia i se setează un OnTouchListener. Acesta transmite coordonatele fiecărei
atingeri a ecranului, iar dacă punctul respectiv aparține unui pătrat, acesta își schimbă
culoarea pentru a arăta că a fost selectat. După apăsarea butonului, serverului primește selecția
și trimite înapoi date despre persoana respectivă.
În cazul în care nu a fost detectată nici o față, utilizatorului i se cere să facă acest lucru
manual. Acest lucru se face prin atingerea ecranului, urmând să fie afișat un pătrat cu centrul
în punctul respectiv. Utilizatorul poate mișcora sau mări pătratul respectiv cu ajutorul a două
butoane aflate în partea de jos a activității.
2.2.5. Căutarea după nume
Această funcționalitate poate fi accesată din activitatea SearchActivity, la care se
poate ajunge din activitatea principală. Utilizatorul va fi întâmpinat cu un ecran de încărcare,
timp în care serverul va trimite numele tuturor persoanelor, pentru a face căutarea mai ușoară.
Activitatea deține un câmp de text cu proprietatea de auto-completare. Astfel, atunci
când utilizatorul scrie primele litere ale unui nume, vor apărea toate numele care încep cu
acele litere într-o zonă de tip „drop-down”. Prin apăsarea pe un anumit nume, acesta va apărea
în câmpul de text. Utilizatorul trebuie doar să mai confirme prin apăsarea butonului Get
Information, după care se trimite cererea către server.
39
2.2.6. Căutări salvate
Activitatea BookmarkActivity afișează utilizatorului numele persoanelor pe care
acesta le-a căutat în trecut și a ales să le salveze. Acest lucru este de ajutor pentru că datele se
salvează local, deci nu este nevoie de o nouă căutare la nivel de server pentru a le obține.
Dezavantajul este că fiind salvate local, utilizatorul nu le poate utiliza pe un alt dispozitiv
Android, chiar dacă este autentificat cu același cont.
Pentru salvarea numelor am utilizat interfața SharedPreferences, care este folosită la
memorarea unor anumit date în interiorul fișierelor aplicației, astfel încât să poată fi accesate
doar din aplicație. Am salvat numele sub forma unui șir de caractere, pe care la încărcare îl
transform într-un obiect JSON ca în figura de mai jos. Salvarea datelor se face similar, cu
metoda putString. De asemenea, utilizatorul poate șterge datele despre o persoană,
modificându-se obiectul care este salvat din nou.
Figura 14: Încărcarea datelor salvate în obiectul JSON
2.2.7. Fișiere auxiliare
Fișierele xml din directorul layout sunt folosite ca fișiere de proiectare a interfeței
grafice și poziționare a elementelor conținute. Acestea sunt făcute pentru activități, dar și
pentru alte elemente grafice mai complexe, cum ar fi bara de titlu a aplicației, ferestrele de
afișare mesaje, autentificare sau confirmare.
Pe lângă fișierele ce conțin clasele aplicației și fișierele xml de proiectare a
activităților și a altor elemente, la nivel de client se găsesc și fișiere xml ce conțin anumite
valori. În acest caz, avem două fișiere auxiliare: strings și colors. Fișierul strings conține
valori de tip text care se regăsesc pe butoane, ca titluri sau mesaje afișate și ajută la
reutilizarea și modificarea cu ușurință a textului, iar în colors avem culorile folosite în
elementele grafice, încărcate cu ajutorul codurilor hexazecimale.
40
2.3. Comunicarea cu serverul
Comunicarea cu serverul se efectuează prin intermediul unui socket conectat la adresa
IP a acestuia. Conexiunea este realizată din mai multe activități, realizând operațiile necesare
fiecăreia. Un exemplu este funcția Connect din figura de mai jos, care inițiază procesul de
căutare a unei persoane. Metoda este apelată dintr-un fir de execuție diferit de cel care se
ocupă de interfața aplicației, lucru de altfel necesar în Android. De asemenea, funcțiile ce
lucrează direct cu elementele grafice apelate din acest fir de execuție sunt încadrate de metoda
runOnUiThread.
Figura 15: Funcția de conectare a clientului la server
2.4. Interfața componentei client
Android oferă dezvoltatorilor o gamă variată de elemente grafice ce pot fi folosite în
orice aplicație. Pe lângă utilizarea acestora, am creat câteva elemente puțin mai complexe,
cum ar fi bara de titlu sau ferestrele de confirmare.
2.4.1. Bara de titlu
Din moment ce bara de titlu obișnuită era foarte simplă, conținând doar titlul aplicației
pe un fundal implicit de culoare albastră, am decis proiectarea unei bare noi în fișierul
app_bar.xml. Astfel, am schimbat culoarea în stilul aplicației, introducând și logo-ul facultății.
41
Figura 16: Bara de titlu
2.4.2. Activitatea principală și fereastra de autentificare
La deschiderea aplicației, utilizatorul este întâmpinat de fereastra de autentificare,
unde este nevoit să introducă datele contului său pentru a ajunge la activitatea principală. În
cazul introducerii unor date greșite, va apărea un mesaj care specifică exact cauza. După
autentificare, fereastra va dispărea, oferind acces la activitatea principală, care conține un
mesaj de întâmpinare și un meniu.
Figura 17: Fereastra de autentificare (stânga) și activitatea principală (dreapta)
Meniul conținut de prima activitate constă în cinci butoane:
Take photo, care duce către activitatea de recunoaștere facială DetectionActivity,
prezentată în detaliu în subcapitolul 2.4.3.
42
Search, care inițiază căutarea persoanelor implementată în SearchActivity, care se
regăsește în subcapitolul 2.4.4.
Bookmarks, care afișează utilizatorului căutările salvate.
Settings, unde utilizatorul poate modifica detalii legate de cont.
Help, care duce spre zona în care sunt explicate principalele funcționalități ale
aplicației și pașii pe care acestea îi urmează.
2.4.3. Activitatea de detectare și recunoaștere facială
Această activitate conține o zonă de afișare a imaginii obținute de la camera foto și
câteva butoane de comandă. Utilizatorul poate decide selectarea manuală sau automată a feței
din imagine.
2.4.4. Activitatea de căutare
Figura 18: Activitate de detectare (1. după încărcarea fotografiei, 2.după detectarea automată a feței,
3. după selectarea feței detectate și 4. după selectarea manuală a feței)
Selecția feței după detectarea automată se face doar prin apăsarea în interiorul ei,
pătratul selectat devenind de culoare verde. În cazul selecției manuale se apasă pe fața pe care
utilizatorul o dorește selectată și apoi se folosesc săgețile pentru a micșora sau mări pătratul.
43
2.4.5. Activități adiționale
Figura 19: Activități adiționale: 1. activitatea de căutare, 2. activitatea de afișare informații,
3. activitatea de afișare/ștergere a căutărilor salvate și 4. activitatea de editare informații
În figura 19 sunt prezentate celelate activități importante ale aplicației. Activitatea de
căutare de la 1. conține pe lângă câmpul ce se poate observa în imagine și un buton de
confirmare în partea de jos a ecranului. În activitatea de la 2. se afișează toate informațiile
disponibile despre o persoană căutată sau recunoscută la nivel de server, oferind și opțiunea
de salvare locală a datelor. Activitatea de la 3. afișează salvările locale, utilizatorul putând
trece la afișarea informațiilor unei persoane printr-o simplă apăsare pe numele ei. De
asemenea, dacă ține degetul apăsat pe numele o persoanei, activează o fereastră de confirmare
în care are opțiunea de a șterge datele respective din listă. În ultima activitate, utilizatorul
poate schimba adresa de e-mail sau parola, iar dacă este profesor poate edita și numărul de
locuri disponibile pentru licență.
De asemenea, în HelpActivity se găsește o secțiune de ajutor a utilizatorului, unde am
explicat pas cu pas cum se poate accesa fiecare funcționalitate în parte. Aceasta servește drept
documentație, conținând răspunsuri la întrebările pe care utilizatorul le poate pune.
44
Capitolul 3: Procesul de recunoaștere facială
Recunoașterea fețelor este una din principalele funcționalități ale aplicației. Aceasta se
realizează în totalitate la nivelul serverului, trimițându-se între timp de la o componentă la
cealaltă date necesare acestui proces: imaginea în sine, fețele detectate, „coordonatele” feței
selectate de utilizator și informațiile despre persoana respectivă. Recunoașterea unei fețe este
realizată în mai mulți pași.
3.1. Detectarea fețelor
Pentru acest pas am ales să folosesc implementarea din biblioteca OpenCV a
algoritmului de detecție Haar Cascade. Această metodă a fost introdusă în anul 2001 de Paul
Viola și Michael Jones ca nouă abordare a detectării de obiecte și oferă o viteză de procesare a
imaginilor mai mare și o acuratețe ridicată. Tehnica Viola-Jones a obținut rezultate bune în
detectarea fețelor umane și a unor categorii de obiecte, cum ar fi avioane și mașini. În alte
domenii au rezultat multe clasificări eronate.
Algoritmul utilizează anumite caracteristici pentru clasificarea imaginilor. Pentru
extragerea acestora se folosesc șabloane bazate pe funcții Haar. Aceste șabloane sunt alcătuite
din dreptunghiuri sau pătrate. „Principalul motiv pentru care s-a ales lucrul cu aceste
caracteristici și nu cu pixeli este abilitatea acestora de a ajuta la codificarea unor informații
specifice care sunt dificile de învățat folosind date de antrenament finite.” [13]
Funcțiile sau undele Haar au fost introduse în 1910 de matematicianul Alfred Haar,
urmând să fie publicate de-a lungul timpului generalizări și modificări ale acestora. Sunt
utilizate în prezent în domenii ca procesare de imagini (de exemplu: compresie), descriere de
date, extragere de trăsături/caracteristici ale imaginilor etc. „Datorită cerințelor
computaționale mici ale acesteia, reprezentarea Haar este în principal folosită la procesarea de
imagini și recunoașterea șabloanelor. Din acest motiv procesarea semnalelor bidimensionale
este un domeniu în care această reprezentare este aplicată eficient datorită structurii sale
asemănătoare unei unde.” [14]
45
Figura 20: Exemplu de șabloane folosite la extragerea trăsăturilor Haar din fereastra de detecție
După cum se poate observa în figura de mai sus, există mai multe tipuri de șabloane.
Acestea se clasifică în funcție de numărul de dreptunghiuri din care sunt alcătuite (două, trei
și patru) sau în funcție de zona ocupată de dreptunghiurile negre (trăsături de margine în (1)-
(2), trăsături liniare în (3)-(4) și trăsături de centru, în care zona neagră se află în mijlocul
zonei albe, împărțind același centru). Șabloanele pot fi rotite ca în (6), acest lucru oferind
uneori un plus de acuratețe. Caracteristicile sau trăsăturile din zona în care se aplică șablonul
se obțin scăzând „suma de pixeli” din zona gri din cea din zona neagră. Prin sumă de pixeli se
referă la suma valorilor de intesitate a pixelilor, adică valoarea imaginii integrale (conceptul
de imagine integrală este explicat mai jos).
Biblioteca de detectare a obiectelor a lui Paul Viola și Michael Jones din lucrarea
publicată în 2001 a avut trei contribuții principale, după cum urmează:
O nouă reprezentare a imaginilor numită imagine integrală. Aceasta poate fi
obținută„dintr-o imagine prin aplicarea unor operații pe fiecare pixel.” [13] Mai exact,
la coordonatele x și y în imaginea integrală se regăsește „suma pixelilor” de deasupra
și din stânga pixelului de coordonate (x, y) din imaginea inițială, după cum se poate
observa în formula din figura 21.
46
Figura 21: Formula de obținere a imaginii integrale;
ii(x, y) – imaginea integrală, i(x’, y’) – imaginea inițială
Construirea unui clasificator folosind trăsături mai puține, însă de o importanță mai
mare, obținute prin utilizarea AdaBoost. „În orice fereastră de detecție dintr-o imagine
numărul de caracteristici Haar este foarte mare, mai mare decât numărul pixelilor.” [13]
Din acest motiv sunt eliminate majoritatea caracteristicilor care joacă un rol mai puțin
important în detectarea obiectelor. Acest lucru l-au realizat utilizând o versiune puțin
modificată a procedurii AdaBoost.
Figura 22: Primele două caracteristici selectate de AdaBoost. Prima măsoară diferența în
intesitate dintre zona ochilor și cea de deasupra lor, iar a doua diferența dintre regiunile ochilor și
cea dintre ei. Șabloanele se aplică pe fereastra de detecție conform exemplului de pe rândul de jos.
Combinarea mai multor clasificatori în cascadă pentru creșterea vitezei de detectare,
prin concentrarea lor asupra zonelor din imagine în care cel mai probabil se află
obiectul respectiv.
47
Prin urmare, metoda inventată de Paul Viola și Michael Jones crește viteza
computațională și totodată acuratețea de detectare a obiectelor. Folosind această metodă, a
fost construit un sistem de detectare a fețelor de 15 ori mai rapid decât cele precedente,
ținându-se cont și de obstacole ca lumina, poziția, mărimea feței sau unghiul din care a fost
făcută fotografia.
Această metodă a fost integrată în biblioteca OpenCV, care oferă mai mulți
clasificatori pre-antrenați (pentru detectarea fețelor, a ochilor, a zâmbetului etc.). Am utilizat
unul din acești clasificatori, încărcând datele dintr-un fișier XML ce conține caracteristici
obținute în urma antrenamentului. Mai multe detalii despre încărcarea fișierului și utilizarea
acestuia la detectarea unor noi fețe se pot regăsi în Capitolul 1.
3.2. Recunoașterea fețelor
Pasul de recunoaștere a fețelor se realizează la rândul său în două etape: extragerea
punctelor principale ale feței și compararea acestora cu fețele deja învățate de algoritmul de
recunoaștere. Acest pas este programat în C++ și integrat prin JNI, la fel ca detectarea fețelor.
3.2.1. Extragerea punctelor
După obținerea unei zone din imagine în care știm cu siguranță că se află o față
umană, următorul pas este extragerea unor trăsături care definesc fața respectivă. În acest scop
am ales să găsesc locația punctelor principale care formează ochii, nasul, gura, sprâncenele și
linia exterioară a feței. Pentru a extrage aceste puncte din imagini am utilizat biblioteca dlib,
care implementează un detector a feței folosind metoda HOG (Histogram of Oriented
Gradients). Această metodă a fost introdusă în 2005 de Navneet Dalal and Bill Triggs,
cercetători ai institutului INRIA (French National Institute for Research in Computer Science
and Automation).
Metoda HOG presupune înlocuirea fiecărui pixel din imagine cu o săgeată care arată
în ce direcție se întunecă imaginea, lucru care se face comparând pixelul respectiv cu cei
vecini. Deoarece acest lucru nu este optim din punct de vedere al performanței, „în practică se
împarte imaginea în regiuni mici (celule), pentru fiecare celulă rezultând o histogramă locală
48
de gradienți orientată într-o singură direcție” [15]. Direcția unei celule se obține din direcțiile
pixelilor conținuți; se alege direcția majoritară. Astfel, vom ajunge la o reprezentare a
imaginii pe care o comparăm cu un șablon pentru a determina poziția punctelor.
Extragerea punctelor, ca și detectarea fețelor pe care le-am implementat funcționează
mai bine pe partea frontală. Din acest motiv, după găsirea punctelor am aplicat transformări
bidimensionale asupra imaginii astfel încât să ajungă la formă aproximativ centrată, după care
am extras din nou punctele din imaginea modificată.
3.2.2. Utilizarea punctelor extrase pentru comparare
Punctele obținute sunt utilizate în calcule de distanțe după extragere, deoarece nu pot
fi folosite în formă „brută” în algoritmul de învățare. Astfel, am calculat distanța euclidiană
între anumite puncte, făcând mai apoi un raport între înălțime sau lățime cu acestea, după caz.
Aceste măsurători obținute au fost folosite la antrenare. Folosind ca reper figura 23, am ales
ca lățime distanța dintre punctele 0 și 16, iar înălțimea distanța dintre 8 și 24 (am schimbat
coordonata X a punctului 24 cu cea a lui 27, pentru a obține o linie verticală.
Figura 23: Punctele extrase dintr-o față; imagine realizată de Brandon Amos [16]
49
Am ales distanțe ca 17-21, 36-39, 31-35 pe lățime sau 27-33, 24-44 pe înălțime, după
mai multe experimente, considerând că acestea și celelalte 12 sunt mai importante decât restul
distanțelor care pot fi calculate. De asemenea, faptul că am ales mai puține distanțe
reprezentative a scăzut durata procesului de antrenare.
Concluzii finale
Ideea de aplicație-asistent poate fi implementată atât în cadrul unei facultăți, cât și
pentru o instituție publică sau o companie, fiind utilă tuturor membrilor acestora. Facilitează
confirmarea identității și acces la anumite informații, implementând în același timp și
elemente de securitate. Este de asemenea ușor de utilizat, comenzile sunt intuitive și oferă o
secțiune de „ajutor” care explică funcționalitățile pas cu pas.
Cu toate că algoritmii utilizați nu sunt cei mai eficienți în detectarea și recunoașterea
fețelor, aceștia au obținut rezultate bune în cazul imaginilor frontale ale fețelor, lucru pe care
l-am urmărit în realizarea aplicației și un procentaj decent la final. De asemenea, celelalte
funcționalități sunt complete, rapide și ghidează utilizatorul prin pașii pe care acesta trebuie să
îi urmeze.
Se pot aduce pe viitor îmbunătățiri algoritmilor (în special celui de recunoaștere), se
poate crește nivelul de securitate și se pot adăuga funcționalități noi, cum ar fi primirea ca
notificări a unor anunțuri importante la nivel de aplicație sau realizearea unei versiuni
„offline” care permite vizualizarea și editarea datelor salvate.
50
Referințe
[1] Jennifer Langston, How well do facial recognition algorithms cope with a million
strangers? http://www.washington.edu/news/2016/06/23/how-well-do-facial-recognition-algorithms-
cope-with-a-million-strangers/
[2] Pagina oficială OpenCV, http://opencv.org/
[3] Pagina oficială dlib, http://dlib.net/
[4] Pagina Wikipedia pentru logging, https://en.wikipedia.org/wiki/Logfile
[5] D. Reilly, M. Reilly, Java(TM) Network Programming and Distributed Computing, pg.
110-124, 2002.
[6] L. Atherton, Improving Image Output Performance in Java,
https://blog.idrsolutions.com/2014/10/imageio-write-executorservice-io-bound-applications-java/
[7] Baza de date PubFig, http://www.cs.columbia.edu/CAVE/databases/pubfig/download/
[8] N. Kumar, A. C. Berg, P. N. Belhumeur, S. K. Nayar, Attribute and Simile Classifiers for
Face Verification, 2009.
[9] Baza de date Faces94, http://cswww.essex.ac.uk/mv/allfaces/faces94.html
[10] Pagina oficială Prevayler, http://prevayler.org/
[11] IDC – International Data Corporation, Smartphone OS Market Share, 2016 Q3,
http://www.idc.com/promo/smartphone-market-share/os
[12] Pagina oficială Android pentru dezvoltatori, https://developer.android.com
[13] P. Viola, M. Jones, Rapid Object Detection using a Boosted Cascade of Simple Features,
pg. 1-2, 2001.
[14] P. Porwik, A. Lisowska, The Haar-Wavelet Transform in Digital Image Processing: Its
Status and Achievements, pg. 84, 2004.
[15] Navneet Dalal and Bill Triggs, Histogram of Oriented Gradients for Human Detection,
pg. 2, 2005.
[16] B. Amos, Pagina contului de github, http://bamos.github.io/