67
Fakulteta za elektrotehniko, računalništvo in informatiko Smetanova ulica 17 2000 Maribor, Slovenija Pohitritev postopka za lokaliziranje obrazov iz knjižnice OpenCV na operacijskem sistemu Android Maribor, januar 2015

operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

  • Upload
    others

  • View
    3

  • Download
    0

Embed Size (px)

Citation preview

Page 1: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

Fakulteta za elektrotehniko, računalništvo in informatiko

Smetanova ulica 17 2000 Maribor, Slovenija

Pohitritev postopka za lokaliziranje

obrazov iz knjižnice OpenCV na

operacijskem sistemu Android

Maribor, januar 2015

Page 2: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

Pohitritev postopka za lokaliziranje

obrazov iz knjižnice OpenCV na

operacijskem sistemu Android

Diplomsko delo

Študent: Boris Špringar

Študijski program: Visokošolski strokovni

Računalništvo in informacijske tehnologije

Smer: /

Mentor: izr. prof. dr. Božidar Potočnik

Somentor: doc. dr. Boris Cigale

Lektorica: Ksenija Pečnik, prof. slov. jezika

Page 3: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

i

Page 4: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

ii

ZAHVALA

Zahvaljujem se svojemu mentorju, dr.

Božidarju Potočniku, somentorju,

doc. dr. Borisu Cigaletu, posebna

zahvala pa gre tudi mojim staršem, ki

so me podpirali tekom študija.

Page 5: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

iii

Pohitritev postopka za lokaliziranje

obrazov iz knjižnice OpenCV na

operacijskem sistemu Android

Ključne besede: Android, knjižnica OpenCV, razvojno okolje NDK, lokaliziranje obrazov,

pohitritev.

UDK: 004.932(043.2)

Povzetek

V diplomskem delu smo se ukvarjali s pohitritvijo postopkov za lokaliziranje obrazov.

Pregledno smo predstavili obstoječe algoritme za zaznavanje obrazov iz knjižnice

OpenCV. V praktičnem delu naloge smo spremenili osnovni algoritem za zaznavanje

obrazov iz knjižnice OpenCV, prirejen za mobilne naprave z operacijskim sistemom

Android, da algoritem za ceno manjše natančnosti deluje hitreje. Osnovni algoritem je

splošen in se lahko uporablja na vseh napravah, ki podpirajo izvajanje kode C++. Zaradi

želje po splošnosti se algoritem lahko izvaja na različnih napravah, a delovanje tega

algoritma na nobeni ni posebej hitro. V diplomskem delu smo ta algoritem spremenili iz

splošno namenskega v specifičnega tako, da smo mu odvzeli določene manj pomembne

funkcionalnosti, priredili kodo za naprave Android, ob tem pa smo optimizirali še hitrost

izvajanja, vse na račun malenkostnega zmanjšanja natančnosti lokaliziranja obrazov.

Eksperimentalni rezultati so pokazali, da s prilagajanjem algoritma ciljni napravi takšen

algoritem deluje bistveno hitreje (do 13 ms hitreje kot izvirni algoritem pri lokaliziranju

obrazov na enem posnetku) na račun zmanjšanja uspešnosti lokaliziranja obrazov za

18 %.

Page 6: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

iv

Acceleration of face localization algorithm

from OpenCV library on operating system

Android

Keywords: Android, OpenCV library, NDK development kit, face localization,

acceleration.

UDK: 004.932(043.2)

Abstract

In the thesis we were working on accelerating algorithms for face localization. We

reviewed existing algorithms from the open source computer vision library OpenCV. We

changed the basic face detection algorithm from the OpenCV library, adapted for Android

mobile devices, in such a way that the algorithm runs faster, for the price of lower

accuracy. The basic algorithm is general and can be used on any device that supports

C++ code execution. Because of that requirement of generality, the algorithm is indeed

suitable for many devices, but its speed is lacking on all of them. In this thesis, we

changed this algorithm from a general algorithm to a more specific one, by removing

some functionalities, adapting the code for Android devices and optimizing its speed in

exchange for marginally smaller face detection rate. Experimental results pointed out that

we can significantly improve the speed of the algorithm by adapting it to the target device

(we gained by face localization up to 13 ms with respect to the original algorithm), for the

price of 18% reduction in face detection rate.

Page 7: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

v

Kazalo

1. Uvod .......................................................................................................................... 1

2. Uporabljene tehnologije ............................................................................................. 3

2.1. Operacijski sistem Android ................................................................................. 3

2.2. Procesorska arhitektura ARM ............................................................................. 3

2.3. Android NDK ....................................................................................................... 3

2.4. CMake ................................................................................................................ 4

2.5. Knjižnica OpenCV............................................................................................... 5

2.6. Pregled algoritmov za zaznavanje obrazov ......................................................... 5

3. Algoritmi za zaznavanje obrazov v knjižnici OpenCV ................................................. 7

3.1. Haarove značilke ................................................................................................ 7

3.2. Histogrami HOG ................................................................................................11

3.3. Značilke LBP .....................................................................................................12

3.4. Kaskade klasifikatorjev ......................................................................................14

3.5. Razred DetectionBasedTracker .........................................................................16

4. Pohitritve algoritma za zaznavanje obrazov ..............................................................28

4.1. Odstranitev večnitenja v razredu DetectionBasedTracker ..................................28

4.2. Sprememba prikaza zaznanih objektov .............................................................30

4.3. Sprememba metode detectMultiScale() .............................................................32

4.4. Odstranitev klicev metode parallel_for_() ...........................................................33

4.5. Prilagajanje parametrov .....................................................................................34

4.6. Trivialne pohitritve..............................................................................................38

5. Rezultati ...................................................................................................................39

5.1. Opis eksperimentalnega okolja ..........................................................................39

5.2. Metrike učinkovitosti ..........................................................................................43

5.3. Rezultati testiranj na tablici ................................................................................44

6. Diskusija in zaključek ................................................................................................49

Viri ...................................................................................................................................50

Page 8: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

vi

Kazalo slik

Slika 3.1: Haarove značilke [35]. ....................................................................................... 8

Slika 3.2: Značilke, postavljene na obraz [37]. .................................................................. 8

Slika 3.3: Računanje seštevka za piksel v integralni sliki [39]. ........................................... 9

Slika 3.4: Računanje regije pravokotnika v integralni sliki [41]. .........................................10

Slika 3.5: Delovanje kaskade klasifikatorjev. ....................................................................10

Slika 3.6: Zaznavanje kotov z značilkami HOG [47]. ........................................................12

Slika 3.7: Obraz z vrisanimi gradienti [47]. .......................................................................12

Slika 3.8: Različne okolice za vzorec LBP [49]. ................................................................13

Slika 3.9: Računanje LBP za en piksel [51]. .....................................................................13

Slika 3.10: Rezultat LBP transformacije [50]. ...................................................................14

Slika 3.11: Uniformni LBP vzorci [31]. ..............................................................................14

Slika 3.12: Diagram klicev metod za DetectionBasedTracker. .........................................17

Slika 3.13: Diagram klicev metod za CascadeClassifier. ..................................................18

Slika 3.14: Integralne slike v kaskadi LBP [53]. ................................................................26

Slika 3.15: Ustvarjanje LBP s pomočjo binarnega ALI......................................................27

Slika 5.1: Testni strežnik. .................................................................................................40

Slika 5.2: Spremembe različic. .........................................................................................41

Slika 5.3: Android aplikacija. ............................................................................................42

Slika 5.4: Graf hitrosti za video. .......................................................................................46

Slika 5.5: Zaznavanje več obrazov – izvirni algoritem. .....................................................47

Slika 5.6: Zaznavanje več obrazov – pospešeni algoritem. ..............................................47

Page 9: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

vii

Kazalo kode

Koda 3.1: Kaskada klasifikatorjev v obliki XML. ...............................................................15

Koda 3.2: Metoda detectMultiScale(). ..............................................................................20

Koda 3.3: Metoda detectSingleScale(). ............................................................................21

Koda 3.4: Metoda operator() iz razreda CascadeClassifierInvoker. ..................................22

Koda 3.5: Metoda predictCategoricalStump(). .................................................................24

Koda 3.6: Metoda operator() iz razreda FeatureEvaluator. ..............................................24

Koda 3.7: Metoda calc(). ..................................................................................................25

Koda 3.8: Metoda CALC_SUM_. .....................................................................................27

Koda 4.1: Metoda runLargeDetector(). .............................................................................29

Koda 4.2: Dodana koda v metodi process(). ....................................................................30

Koda 4.3: Metoda calcTrackedObjectsPositionToShow(). ................................................31

Koda 4.4: Prilagojena metoda calcTrackedObjectsPositionToShow(). .............................32

Koda 4.5: Dodana koda v metodi detectMultiScale(). .......................................................32

Koda 4.6: Prilagojena koda v metodi detectMultiScale(). .................................................33

Koda 4.7: Izvirna metoda detectSingleScale()..................................................................34

Koda 4.8: Prilagojena metoda detectSingleScale(). .........................................................34

Koda 4.9: Parametri razreda DetectionBasedTracker. .....................................................38

Koda 5.1: Merjenje trajanja metode detect(). ...................................................................41

Page 10: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

viii

Uporabljene kratice

NDK Native Development Kit

SDK Software Development Kit

JNI Java Native Interface

ART Android runtime

RISC Reduced Instruction Set Computing

EABI Embedded Application Binary Interface

BSD Berkley Software Distribution

QR Quick Response

FPS Frames Per Second

CSV Comma Separated Values

NFL No Free Lunch

SVM Support Vector Machine

Page 11: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

1

1. Uvod

Že od začetkov računalniškega vida se ta ukvarja z zaznavanjem objektov. Naj si bo z

zaznavanjem robov in uporabo šablon ali z bolj prefinjenimi klasifikatorskimi metodami.

Zaznavanje objektov je procesorsko zahtevno, saj je treba posamično preiskati vsako

sliko s kamere, mobilne naprave pa niso znane po svoji procesorski moči, zato običajno

delamo s počasnimi enojedrnimi procesorji na arhitekturi ARM, ki imajo na voljo malo

pomnilnika. Prav tako Android aplikacije temeljijo na programskem jeziku Java, ki za

izvajanje uporablja Dalvik, to je virtualna naprava, ki deluje v jedru Linux. Imamo torej

dodano raven abstrakcije, kar sicer zniža hitrost, a izboljša splošnost in s tem

prenosljivost. Vsi Android programi delujejo na katerikoli Android napravi, podobno kot

Java aplikacije za namizne sisteme načeloma delujejo na kateremkoli računalniku, razen

če dodajamo sistemsko specifične ukaze. Knjižnica OpenCV je narejena v programskem

jeziku C++, ki se izvaja prek vmesnika NDK (angl. Native Development Kit), ki temelji na

JNI (angl. Java Native Interface). Uporaba NDK naredi aplikacijo kompleksnejšo, saj je za

vsak klic metod iz modulov C++ potrebna metoda v Java ovojnici. Če imamo veliko klicev

C++ metod, lahko to upočasni algoritem, a imamo v naši aplikaciji teh klicev malo, in sicer

le enega za vsako pridobljeno sliko, zato takšni klici ne predstavljajo velikega problema pri

časovni zahtevnosti. Na splošno pa je NDK priporočen samo za aplikacije, ki imajo

zahtevno procesorsko delo, na primer igre, simulacije, računalniški vid in za aplikacije,

kjer želimo uporabljati obstoječe knjižnice C++. Knjižnica OpenCV torej spada v dve od

teh kategorij; napisana je v programskem jeziku C++ in hkrati je detekcija obrazov

procesorsko zelo zahtevno opravilo.

Pri našem projektu se ukvarjamo z lokalizacijo obrazov z uporabo prenosnih naprav, ki

uporabljajo operacijski sistem Android. Za lokaliziranje obraza uporabljamo algoritme iz

odprtokodne knjižnice OpenCV. Namen diplomskega dela je bil spremeniti osnovne

algoritme iz knjižnice OpenCV, da bi delovali hitreje. Za to smo bili pripravljeni žrtvovati

splošnost in natančnost algoritma. V ta namen smo morali najprej natančno analizirati

delovanje teh algoritmov. Algoritem za zaznavanje, ki ga uporabljajo aplikacije Android, se

nahaja v razredu DetectionBasedTracker, ki za detekcijo uporablja razred

CascadeClassifier.

V naslednjih poglavjih smo najprej opisali obstoječe uporabljene tehnologije, kot so

operacijski sistem Android, procesorji ARM, knjižnica OpenCV, in obstoječe algoritme za

zaznavanje obrazov. Po tem smo pregledali implementacije algoritmov v knjižnici OpenCV

Page 12: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

2

(različica 2.4.9) in natančno opisali njihovo delovanje, nato pa smo opisali še naše

modifikacije algoritmov in predstavili rezultate naših meritev ter diskutirali o smiselnosti

pohitritev.

Page 13: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

3

2. Uporabljene tehnologije

2.1. Operacijski sistem Android

Android je operacijski sistem, ki ga za mobilne naprave razvija podjetje Google [1].

Temelji na jedru Linux, različica jedra pa je odvisna od naprave, najstarejša različica je

2.6.27 [2] [3]. V jedro so dodane funkcionalnosti za mobilne naprave, na primer razred

Binder, ki je sistem za medprocesno komunikacijo [4]. Aplikacije v operacijskem sistemu

Android temeljijo na kodi, napisani v programskem jeziku Java, ki jo izvaja virtualna

naprava Dalvik [5] [6], v novejših različicah pa eksperimentalna virtualna naprava ART

(angl. Android runtime).

2.2. Procesorska arhitektura ARM

Arhitektura ARM je procesorska arhitektura, ki temelji na RISC (angl. Reduced Instruction

Set Computing) [7] [8]. Ker uporabljajo RISC, je poraba takih procesorjev manjša, kar

prispeva k daljšemu trajanju baterije in manjšemu segrevanju, zaradi česar je ARM kot

nalašč za mobilne naprave, ki imajo omejeno zalogo energije in nimajo aktivnega hlajenja.

Naša Android naprava ima procesor Arm Cortex A8 [9], ki temelji na arhitekturi ARMv7a

[10], to je procesor z enim jedrom, 1000 Mhz taktom in 32-bitno arhitekturo.

2.3. Android NDK

Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča

izvajanje C++ kode na operacijskem sistemu Android [13]. Vključuje vse od standardnih

knjižnic C++ do orodij, kot je ndk-build.cmd, to je program, ki ga uporabljamo za grajenje

C++ modulov za našo Android aplikacijo.

Po prevajanju lahko zgrajeni modul vključimo v aplikacijo z ukazom

System.loadLibrary(»libraryName«) namesto standardnega ukaza import package.library,

ki ga uporabljamo za vključevanje običajnih knjižnic Java. Ukaz loadLibrary poišče

knjižnico v mapi jni/libs/EABI. Vmesnik EABI (angl. Embedded Application Binary

Interface) je drugačen za vsak procesor, za katerega je prevedena koda C++. Za naš

procesor je to armeabi-v7a, kar pomeni, da ima naša naprava procesor z arhitekturo ARM

različice 7a.

EABI [14] [15] je vmesnik med dvema moduloma na ravni strojne kode, v našem primeru

knjižnica C++ in operacijski sistem Android.

Page 14: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

4

Naložen modul uporablja Java ovojnica, ki ima definirane klice kode C++ na naslednji

način: private static native type methodName(arguments). Če je modul neuspešno

naložen ali nima metod, ki jih ovojnica kliče, to izvemo šele ob zagonu programa, ko se

sproži izjema.

V JNI delu aplikacije morajo biti metode pripravljene na klic iz Java ovojnice. To pomeni,

da mora imeti vsaka metoda posebno ime, da jo lahko Java ovojnica sploh definira.

Primer takega poimenovanja je JNIEXPORT jlong JNICALL Java_package_

name_JavaClassName_methodName(JNIEnv* jenv, jclass, jni parameters). Pri

poimenovanju je torej pomembno, da navedemo ime Java paketa in razreda, ki bo klical

metodo. Hkrati moramo dodati JNIEnv in jclass. Vse spremenljivke, ki jih uporabljamo v

klicu metod, morajo biti standardne za JNI, na primer jlong in jint. Prav tako ne moremo

podajati referenc na Java objekte, ampak moramo uporabiti njihovo reprezentacijo v

64-bitni celoštevilski (long) predstavitvi, ki jo dobimo s klicem metode

object.getNativeObjAddr() v Java ovojnici. Da lahko te objekte sploh uporabljamo, jim

moramo v JNI delu dodeliti tip (angl. casting), na primer, če delamo z matriko faces, v JNI

delu dobimo referenco na matriko v obliki jlong faces, da lahko dostopamo do lastnosti

matrike, ji dodelimo tip z ukazom ((Mat*)faces).

Za razhroščevanje kode C++ moramo zagnati orodje ndk-gdb ali pa si pomagamo z

beleženjem tako, da pošiljamo sporočila o delovanju aplikacije v beležko LogCat [16], ki je

del Android SDK (angl. Software Development Kit).

Ker NDK naredi našo kodo kompleksnejšo, uporaba tega ni priporočljiva zgolj zato, ker je

programiranje v C++ enostavneje, temveč je smiselna le takrat, ko imamo že obstoječe

C++ knjižnice ali ko izvajamo procesorsko intenzivne algoritme.

2.4. CMake

CMake je medplatformni odprtokodni sistem za izdelovanje opisnih datotek, ki se

uporabljajo pri grajenju strojne kode iz C++ kode (angl. makefile) [17]. V osnovi je orodje

narejeno za ukazno vrstico, v operacijskem sistemu Windows pa imamo na voljo še

grafični vmesnik CMake. Da lahko knjižnico OpenCV prevedemo v strojno kodo,

potrebujemo te opisne datoteke, ki jih izdelujemo s pomočjo CMake.

Cmake z uporabo nabora orodij za Android (angl. toolchain), ki jih priskrbi OpenCV v mapi

platforms/Android/android.toolchain.cmake, ustvari opisno datoteko za vse module, ki jih

Page 15: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

5

uporabljamo v naši knjižnici. Te datoteke potem uporabi program NDK make.exe, da

zgradi knjižnice, ki jih uporablja naša Android aplikacija.

2.5. Knjižnica OpenCV

OpenCV je odprtokodna knjižnica, v kateri so implementirani algoritmi za računalniški vid

[18] [19], njegovi številni moduli pa so napisani v optimiziranem programskem jeziku C++.

Izdan je pod licenco BSD (angl. Berkley Software Distribution), kar pomeni, da ga lahko

uporabljajo, spreminjajo in kopirajo tako podjetja kot posamezniki [20] za komercialne ali

nekomercialne namene. Uporablja se lahko na vseh napravah in infrastrukturah, ki

podpirajo izvajanje kode, napisane v programskem jeziku C++. Tako jo lahko uporabljamo

za manj zahtevne stvari, kot so lokalizacija obrazov na mobilnem telefonu, branje kode

QR (angl. quick response) na mobilnem telefonu in podobno. Lahko pa ga uporabljamo

tudi za bolj zahtevne aplikacije, na primer za videonadzor in kontrolo rudarske opreme

[21].

Knjižnica OpenCV ima implementiranih prek 2500 algoritmov [21], od osnovnih algoritmov

za računalniški vid do naprednih algoritmov za računalniški vid in strojno učenje. Ti

algoritmi se lahko uporabljajo za naloge, kot sta detekcija in identifikacija objektov, za

klasifikacijo človeškega gibanja, sledenje objektom, filtriranje in urejanje slik in podobno.

Ima vmesnike v programskih jezikih C, C++, Java in Python, obstajajo pa tudi ovojnice za

višje programske jezike, na primer EmguCV za .NET C# [22] in JavaCV za Javo [23].

Knjižnica OpenCV podpira operacijske sisteme Windows, Linux, Android in Mac OS.

Uporabna je predvsem za aplikacije v realnem času in uporablja nabore ukazov MMX [24]

in SSE [25], ko so ti na voljo.

2.6. Pregled algoritmov za zaznavanje obrazov

Obraze lahko zaznavamo s pomočjo različnih algoritmov za procesiranje slik, od naivnih

pristopov do sofisticiranih algoritmov s strojnim učenjem [26]. Nekateri izmed njih so:

s slike lahko odstranimo ozadje in ga nadomestimo z enobarvnim ozadjem, obraz

pa lahko za tem preprosto zaznamo z iskanjem robov. Slabost tega pristopa je, da

ga ne moremo uporabiti v realnih pogojih; uporabimo ga lahko na primer le, ko

imamo na voljo zeleni zaslon;

uporabimo lahko barvne značilnosti obrazov, torej zaznavamo, kje na sliki imamo

področja, ki vsebujejo barvo obraza. Slabost tega pristopa je, da ne moremo

Page 16: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

6

zaznati obrazov z različnimi kožnimi pigmenti, algoritem pa je občutljivejši na

nepravilno zaznane objekte;

na voljo imamo tudi zaznavanje gibanja, če predpostavljamo, da se v realnem

svetu obraz vedno vsaj malo premika. Slabost tega pristopa je, da zaznavamo še

vse druge premikajoče se objekte;

nevronske mreže so eden od pristopov s strojnim učenjem, ki se približujejo

naravnim sistemom, na primer človeškim možganom;

sledenje na osnovi modela uporablja zaznavanje robov in primerjanje šablon;

za nas najrelevantnejši so pristopi, ki uporabljajo šibke klasifikatorje, ki tvorijo

kaskade klasifikatorjev. Tudi ti pristopi uporabljajo strojno učenje, kaskade pa za

zaznavanje obrazov uporabljajo skupine značilk. Po obsežnem strojnem učenju z

velikimi množicami pozitivnih in negativnih primerkov lahko te kaskade dajejo zelo

točne rezultate. Algoritem, ki uporablja kaskado klasifikatorjev, smo uporabili v

našem projektu.

Page 17: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

7

3. Algoritmi za zaznavanje obrazov v knjižnici OpenCV

Knjižnica OpenCV za zaznavanje objektov poleg drugih algoritmov uporablja tudi kaskade

klasifikatorjev [27]. Kaskada klasifikatorjev je ansambelska metoda, kar pomeni, da

uporabljamo več klasifikatorjev naenkrat. Imamo vrsto (kaskado) močnih klasifikatorjev

oziroma stopenj (angl. stages), ki jih tvorijo šibki klasifikatorji. Šibki klasifikatorji

klasificirajo posamezne značilke kot pozitivne ali negativne in glede na svoje uteži

dodajajo ali odvzemajo vrednost seštevku stopnje. Ko stopnja dokonča klasifikacijo, se

seštevek primerja s pragovno vrednostjo (angl. threshold). Če je seštevek stopnje manjši

kot pragovna vrednost, se slika zavrne in klasifikacija se konča, če pa je večji ali enak, pa

se klasifikacija nadaljuje. Slika je klasificirana pozitivno, ko jo vsaka posamezna stopnja

klasificira kot pozitivno. S tem zagotovimo hitrejše izločanje napačnih klasifikacij in s tem

hitrejše izvajanje. Začetnik takih klasifikatorjev je Viola-Jones algoritem za zaznavanje

obrazov, ki za klasifikacijo uporablja Haarove značilke [28].

V OpenCV so implementirane tri kaskade klasifikatorjev z značilkami tipov HOG [29],

Haar [30] in LBP [31].

3.1. Haarove značilke

Haarove značilke so dobile ime po Haarovih impulzih [32] [33], ki so nezvezni impulzi,

zato njihovih funkcij ne moremo odvajati, kar je pri običajni analizi signalov pomanjkljivost.

Po drugi strani je ta lastnost prednost, ko zaznavamo signale, ki imajo hitre prehode

amplitud, ko na primer iščemo okvare v strojih. Pri obdelavi slik so taki prehodi pogosti pri

robovih ali ko imamo jasne prelive iz svetlega področja (ozadja) v temno področje (objekt,

ki ga zaznavamo).

Haarove značilke [34] izrabljajo dejstvo, da so področja okoli oči, ust in nosa temnejša od

preostalega obraza. Kot je prikazano na sliki 3.1, je značilka pravokotne oblike z dvema

ali s tremi notranjimi pravokotniki.

Page 18: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

8

Slika 3.1: Haarove značilke [35].

En klasifikator ima lahko n značilk. Pri uporabi značilke klasifikator odšteje seštevek

vrednosti pikslov v beli regiji od seštevka vrednosti pikslov v črni regiji [36]. Na sliki 3.2

vidimo značilke, postavljene na obraz, kjer primerjajo področje oči s področjem pod očmi,

ki mora biti svetlejše za pozitivno klasifikacijo.

Slika 3.2: Značilke, postavljene na obraz [37].

Kaskado klasifikatorjev lahko zgradimo s pomočjo strojnega učenja z algoritmom Gentle

AdaBoost [38], ki ga uporabimo tako za selekcijo značilk kot za učenje klasifikatorjev.

Značilk, ki jih ima na voljo učni algoritem, je običajno veliko več kot pikslov (Viola&Jones

[36] sta jih v izvirnem algoritmu uporabila 180.000), zato je pomembno, da učni algoritem

izbere najboljše značilke. Učni algoritem to doseže tako, da med učenjem kaskade za

vsako značilko ustvari svoj klasifikator, ki klasificira vse slike, nato učni algoritem izbere

klasifikatorje z najmanjšo napako.

Za primerjavo svetlosti regij uporabljajo kaskade s Haarovimi značilkami seštevke

svetlosti (vrednosti) pikslov. Seštevanje svetlosti vsakega piksla posebej za vsako regijo

bi bilo preveč procesorsko zahtevno, zato algoritmi uporabljajo še tehniko vmesne

integralne slike [39] [40]. Integralna slika oziroma tabela seštevkov je transformacija, kjer

je vsak piksel seštevek regije nad pikslom in levo od piksla, kot prikazuje slika 3.3.

Page 19: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

9

Slika 3.3: Računanje seštevka za piksel v integralni sliki [39].

Ko računamo regijo za nek piksel, si lahko pomagamo s predhodno izračunanimi regijami.

Novemu pikslu prištejemo gornjo in levo vrednost iz integralne slike in odštejemo vrednost

levo zgoraj, kot prikazuje enačba 3.1. Tako se izognemo seštevanju svetlosti vsakega

piksla posebej v vsaki regiji in opravimo izračun integralne slike v enem prehodu slike.

𝑠(𝑥, 𝑦) = 𝑖(𝑥, 𝑦) + 𝑠(𝑥 − 1, 𝑦) + 𝑠(𝑥, 𝑦 − 1) − 𝑠(𝑥 − 1, 𝑦 − 1) (3.1)

kjer je s seštevek in i intenziteta piksla.

Ko imamo integralno predstavitev naše slike, je seštevek regije veliko lažji, saj je vsaka

točka v integralni sliki seštevek regije od izhodišča (točke 0,0) do trenutne točke. Pri

značilkah imamo štiri točke, postavljene na sliko. Da pridemo do seštevka regije v

integralni sliki, od spodnje desne točke odštejemo gornjo desno in spodnjo levo ter

prištejemo gornjo levo. Kot je prikazano na sliki 3.4, če iščemo seštevek regije ABCD,

moramo od regije D odšteti regiji zgoraj in desno (B in C) in prišteti regijo zgoraj desno

(A), ker smo jo z odštevanjem B in C odšteli dvakrat.

Page 20: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

10

Slika 3.4: Računanje regije pravokotnika v integralni sliki [41].

Ta način je veliko manj procesorsko zahteven kot seštevanje vsakega piksla posebej,

hkrati pa lahko uporabimo isto integralno sliko za vse značilke, tako da izračunamo

integralno sliko samo enkrat za klasifikacijo ene slike.

Kot vidimo na sliki 3.5, kaskade klasifikatorjev delujejo tako, da stopnje ena za drugo

klasificirajo sliko. Da kaskada označi sliko kot pozitivno (torej da je v njej iskani objekt),

mora vsaka stopnja klasificirati sliko kot pozitivno. Takoj ko katera od stopenj zavrne sliko,

se klasifikacija konča in vrne se števec pozitivnih klasifikacij.

Slika 3.5: Delovanje kaskade klasifikatorjev.

Delovanje takih kaskad je precej hitro, vendar so Haarove kaskade zaradi svoje

obsežnosti (preko 100 stopenj) prezahtevne za našo Android napravo. Učenje kaskad pa

Page 21: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

11

je precej zahtevno, ker potrebujemo več tisoč pozitivnih in negativnih primerkov (slik z ali

brez obraza) ter več tisoč značilk. V našem projektu nismo obravnavali učenja kaskad,

ampak smo uporabljali kaskade z značilkami tipa LBP (angl. Local Binary Patterns), ki jih

ponuja knjižnica OpenCV skupaj z algoritmom in s primeri uporabe.

3.2. Histogrami HOG

Histogrami HOG (angl. Histogram of Oriented Gradients) so histogrami orientiranih

gradientov. Pri našem projektu tega tipa značilk nismo uporabljali, zato je v nadaljevanju

opisan samo okvirno.

Gradienti predstavljajo usmerjenost funkcije. V primeru sivinskih slik to pomeni, da

gradienti kažejo v smeri preliva barve iz svetlejše v temnejšo [42] [43] [44]. Tako dobimo

značilke, ki opisujejo nek objekt, kot je na primer oko, ki je sestavljeno iz več prelivov iz

svetlejše slike v temnejšo oziroma je sestavljeno iz več gradientov [45].

Sliko razdelimo na manjše segmente (Dalal in Triggs [46] sta uporabila 16 x 16 bloke s

štirimi 8 x 8 celicami) in izračunamo gradient za vsak blok. Tudi tu si pomagamo z

integralnimi slikami.

Gradiente obravnavamo podobno kot Haarove značilke in iz njih ustvarimo kaskado

klasifikatorjev. Dalal in Triggs [46] sta namesto Gentle AdaBoost uporabila stroje SVM

(angl. Support Vector Machine).

Imamo torej skupine značilk, ki opisujejo prelive med svetlejšimi in temnejšimi področji in s

tem razlikujejo med različnimi področji (na primer med usti in očmi), ki jih uporablja

kaskada klasifikatorjev. Ta kaskada klasifikatorjev pa deluje na isti način kot pri Haarovih

značilkah.

Slika 3.6 prikazuje praktično uporabo zaznavanja kotov z detektorjem HOG, na sliki 3.7 pa

lahko vidimo vhodno sliko, razdeljeno na celice in gradiente v posameznih celicah.

Page 22: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

12

Slika 3.6: Zaznavanje kotov z značilkami HOG [47].

Slika 3.7: Obraz z vrisanimi gradienti [47].

Hitrost kaskade klasifikatorjev z značilkami tipa HOG je podobna kaskadi klasifikatorjev z

značilkami tipa Haar, kaskada klasifikatorjev z značilkami tipa HOG pa je tudi bolj

natančna.

3.3. Značilke LBP

Značilke LBP (angl. Local Binary Patterns) oziroma lokalni binarni vzorci so lokalne

transformacije, kjer za vsak piksel v sliki ali njenem odseku izračunamo binarni vzorec s

pomočjo pikslov v njegovi okolici [48].

Za okolico vzamemo piksle okrog tistega, za katerega računamo vzorec LBP. Okolica je

krog, v katerem so enakomerno porazdeljene točke, s pomočjo katerih računamo vzorec

Page 23: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

13

LBP. Srednji piksel je tisti, za katerega računamo binarni vzorec, lahko imamo okolice z

različnimi premeri in različnim številom okoliških točk, kot prikazuje slika 3.8. Če točka ni

na sredini piksla, se njena vrednost ekstrapolira iz okolice točke.

Slika 3.8: Različne okolice za vzorec LBP [49].

Binarni vzorec je bitni niz, ki ga izračunamo za sredinski piksel tako, da z njegovo

vrednostjo primerjamo vsak piksel v dani okolici. Ta primerjava je pragovna operacija, ki

vrača 1, če je vrednost piksla v okolici večja od sredinskega piksla ali 0, če je vrednost

manjša ali enaka, kot ponazarja slika 3.9. Bitni niz sestavimo tako, da vrednosti beremo v

smeri urinega kazalca ali proti urinem kazalcu. Bitni niz nato pretvorimo v decimalno

vrednost [50]. Vzorci LBP niso odporni na skaliranje.

Slika 3.9: Računanje LBP za en piksel [51].

Page 24: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

14

Na sliki 3.10 je prikazana LBP pretvorba celotne slike. Algoritem je pri tej pretvorbi vsak

piksel v izvirni sliki zamenjal z njegovim vzorcem LBP. Vidimo, da so na pretvorjenih

slikah jasno vidni robovi in potemnitve, tudi ko je izvirna slika manj jasna zaradi slabe

osvetlitve.

Slika 3.10: Rezultat LBP transformacije [50].

Glede na karakteristike lokalnega vzorca lahko vzorec opišemo kot uniformen ali

neuniformen. Uniformni so tisti, ki imajo dva ali nič prehodov oziroma sprememb iz niza

enk v niz ničel, neuniformni pa so tisti, ki imajo enke in ničle razpršene, torej je med njimi

več prehodov. Iz uniformnih vzorcev lahko razločimo, ali je piksel na robu nekega objekta,

ali je na kotu, ali je na piki ali pa je na praznem področju. Uniformne vzorce LBP

ponazarja slika 3.11.

Slika 3.11: Uniformni LBP vzorci [31].

3.4. Kaskade klasifikatorjev

Algoritmi iz knjižnice OpenCV za klasifikacijo slik uporabljajo odločitvena drevesa. Teh

odločitvenih dreves ne učijo sproti, ampak uporabljajo odločitvena drevesa, ki so rezultat

predhodnega strojnega učenja. Za to učenje odločitvenih dreves potrebujemo veliko

število pozitivnih in negativnih vzorcev. Pozitivni vzorci so slike, ki vsebujejo iskani objekt

(v našem primeru obraz), negativni vzorci pa so slike, ki vsebujejo ozadja brez predmetov

Page 25: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

15

ali predmete, ki jih odločitveno drevo pogosto napačno klasificira kot iskani objekt.

Knjižnica OpenCV vsebuje algoritme za učenje odločitvenih dreves. Za to učenje

potrebujemo več tisoč pozitivnih in negativnih vzorcev, traja pa lahko tudi več dni. Pri

našem projektu kaskad klasifikatorjev nismo posebej učili, ampak smo uporabili kaskade

klasifikatorjev, ki so bile vključene poleg primerov uporabe knjižnice OpenCV.

Odločitveno drevo je shranjeno v datoteki XML, v obliki, ki jo prikazuje koda 3.1.

<?xml version="1.0"?> <!-- number of positive samples 3000 number of negative samples 1500 --> <opencv_storage> <cascade type_id="opencv-cascade-classifier"> <stageType>BOOST</stageType> <featureType>LBP</featureType> <height>24</height> <width>24</width> <stageParams> <boostType>GAB</boostType> <minHitRate>0.9950000047683716</minHitRate> <maxFalseAlarm>0.5000000000000000</maxFalseAlarm> <weightTrimRate>0.9500000000000000</weightTrimRate> <maxDepth>1</maxDepth> <maxWeakCount>100</maxWeakCount></stageParams> <featureParams> <maxCatCount>256</maxCatCount></featureParams> <stageNum>20</stageNum> <stages> <!-- stage 0 --> <_> <maxWeakCount>3</maxWeakCount> <stageThreshold>-0.7520892024040222</stageThreshold> <weakClassifiers> <!-- tree 0 --> <_> <internalNodes> 0 -1 46 -67130709 -21569 -1426120013 -1275125205 -21585 -16385 587145899 -24005</internalNodes> <leafValues> -0.6543210148811340 0.8888888955116272</leafValues></_> <!-- tree 1 -->

Koda 3.1: Kaskada klasifikatorjev v obliki XML.

V datoteki XML imamo na vrhu osnovne informacije: tip stopenj, tip značilk, višino in širino

osnovne slike za zaznavanje, parametre stopenj, parametre značilk in število stopenj.

Kaskada je nato razdeljena na stopnje, ki so sestavljene iz šibkih klasifikatorjev. Vrednost

StageThreshold je prag, ki ga morajo doseči šibki klasifikatorji, da je stopnja klasificirana

kot pozitivna.

Page 26: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

16

Znotraj šibkega klasifikatorja imamo vrednosti internalNodes, ki je vektor enajstih števil, ki

predstavljajo po vrsti:

levo in desno, ki sta vrednosti, ki jih za zaznavanje z značilkami tipa LBP ne

uporabljamo,

indeks značilke, ki jo uporablja šibki klasifikator, in

osem vrednosti, ki jih algoritem uporablja za ocenjevanje značilke [52].

Teh osem vrednosti imenujemo iskalna tabela (angl. Look Up Table ali LUT) in na osnovi

te iskalne tabele se algoritem odloča, ali bo k seštevku stopnje prištel levo ali desno

vrednost iz para vrednosti leafValues. Seštevek stopnje primerjamo s pragom stopnje, da

ugotovimo, ali je stopnja sliko klasificirala pozitivno.

Na dnu datoteke so opisane še značilke. Vsaka značilka ima svoje koordinate, širino in

višino.

3.5. Razred DetectionBasedTracker

Razred DetectionBasedTracker je razred na najvišji ravni v C++ delu naše aplikacije. Ima

vse lastnosti in metode, ki jih uporabljamo v JNI in ovojnicah Java. Razred

DetectionBasedTracker implementira splošne algoritme za predpripravo slike in

prikazovanje zaznanih objektov in uporablja nižje nivojske razrede za izvajanje detekcije.

Razred DetectionBasedTracker ima tudi nabor parametrov, s katerimi lahko uporabniki

razreda glede na omejitve svojih aplikacij prilagajajo delovanje algoritmov za zaznavanje

objektov.

Na sliki 3.12 lahko vidimo, kako z najvišje ravni (aplikacije Android) dostopamo do metode

process() v razredu DetectionBasedTracker prek vmesnika JNI.

Page 27: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

17

Slika 3.12: Diagram klicev metod za DetectionBasedTracker.

Metoda process() vzame podano matriko sivinske slike, na njej izvede detekcijo in shrani

zaznane objekte. Te objekte (pravokotnike) lahko dobimo s pomočjo metode getObjects,

ki jih lahko v aplikaciji prikažemo na izvirni sliki.

Metoda process() komunicira z ločeno nitjo iz razreda SeparateDetectionWork, ki izvaja

detekcijo na vhodni sliki. Razred DetectionBasedTracker tako ne pregleduje celotne slike,

ampak zaznava samo v regijah objektov, ki jim sledi. Ko razred SeparateDetectionWork

konča s pregledovanjem slike, se nastavijo zastavice, ki glavni niti iz razreda

DetectionBasedTracker povedo, da je detekcija končana. Te zastavice se preverjajo ob

vsakem klicu metode process(&Mat). Ko razred DetectionBasedTracker ugotovi, da je

detekcija na celotni sliki končana, vzame novi seznam objektov in posreduje novo sliko

razredu SeparateDetectionWork.

Za zaznavanje uporabljata razreda DetectionBasedTracker in SeparateDetectionWork

metodo DetectMultiScale() iz razreda CascadeClassifier, ki ji posredujeta sliko. Po

zaznavanju se kliče še metoda updateTrackedObjects(), ki preverja, če se kateri od na

Page 28: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

18

novo zaznanih objektov prekriva s katerim od shranjenih objektov, ki jim sledimo. Če se

na novo zaznani objekti prekrivajo s katerim od shranjenih objektov, se shranjenemu

objektu dodajo njihove pozicije, drugače se na novo zaznane objekte doda v seznam

objektov, ki jim sledimo.

Vsak objekt ima shranjenih več pozicij, ki jim sledimo, zato mora metoda getObjects()

pred vračanjem objektov najprej izračunati, kaj naj sploh pokaže. To stori s pomočjo

metode calcTrackedObjectsPositionToShow(), ki iz vseh pozicij objektov izračuna

povprečno vrednost, da izboljša estetiko prikaza. Algoritem uporablja to metodo, da se

pravokotnik okrog zaznanega objekta manj premika (pravokotnik okrog zaznanega

objekta se namreč zaradi šuma v sliki premika, tudi če se objekt ne).

Razred CascadeClassifier opravlja klasifikacijo s pomočjo kaskad klasifikatorjev in

njihovih značilk. Implementirane ima algoritme, ki uporabljajo značilke tipa Haar, HOG in

LBP.

Na sliki 3.13 lahko vidimo hierarhijo klicev metod od najvišje ravni v razredu

CascadeClassifier do najnižje ravni v razredu FeatureEvaluator.

Slika 3.13: Diagram klicev metod za CascadeClassifier.

Glavna metoda, ki jo uporabljamo v razredu DetectionBasedTracker, je metoda

detectMultiScale(), ki skalira sliko od večje proti manjši glede na parameter scaleFactor.

Istočasno metoda detectMultiScale() veča regijo za detekcijo, ki se imenuje

Page 29: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

19

processingRectSize, znotraj katere algoritem izvaja klasifikacijo na osnovi značilk LBP. Po

skaliranju kličemo metodo detectSingleScale(), ki ji podamo skalirano sliko skupaj s

pripadajočimi parametri. Metoda detectSingleScale() zažene klasifikacijo za podano sliko

in v seznam kandidatov zapiše pravokotnike regij, ki jih je klasifikator pozitivno klasificiral.

Algoritem zaključi z izvajanjem, ko je slika manjša kot parameter originalWindowSize , ki

ga algoritem pridobi iz datoteke XML, ki opisuje kaskado in njene parametre. Parameter

originalWindowSize nam pove, kolikšna je izvirna velikost slik, iz katerih se je kaskada

klasifikatorjev učila, zato slike ne smemo skalirati na velikost, ki je manjša od originalne.

V kodi 3.2 vidimo pomembnejše dele metode detectMultiScale(). Sliko v obliki matrike

metodi podamo s pomočjo referenčne spremenljivke image. Referenca na vektor

pravokotnikov objects je namenjena pravokotnikom, ki predstavljajo zaznane objekte.

Prek reference na objects lahko zunaj metode detectMultiScale() dostopamo do zaznanih

objektov, metoda detectMultiScale() pa ne vrača ničesar. Vektorja rejectLevels in

rejectWeights sta namenjena testiranju zmogljivosti kaskade klasifikatorjev, česar v

našem projektu nismo uporabljali. Spremenljivka scaleFactor nam pove, kako hitro naj se

skalirata slika in velikost regije za zaznavanje processingRectSize. Spremenljivka

minNeighbors nam pove, koliko sosedov mora imeti kandidat, da ga vključimo med

zaznane objekte. Spremenljivko minNeighbors potrebujemo zato, da se znebimo

napačnih pozitivnih (angl. false positive) klasifikacij. Spremenljivki minObjectSize in

maxobjectSize pa povesta, kakšna je najmanjša in največja velikost objektov.

Po inicializaciji spremenljivk se začne zanka FOR, ki inicializira spremenljivko factor in jo

po vsakem zaključku zanke FOR pomnoži s spremenljivko scaleFactor. Zanko FOR

algoritem prekine, ko je zadoščeno kateremu od pogojev v stavkih IF znotraj zanke FOR.

Ti stavki IF se ovrednotijo po skaliranju in prekinejo zanko FOR ali ko je spremenljivka

windowSize večja kot maksimalna velikost objekta, ko je spremenljivka

processingRectSize manjša od nič ali ko metoda detectSingleScale() vrne FALSE. Na

začetku zanke FOR algoritem skalira izvirno sliko, nastavi velikost okna za zaznavanje,

nastavi velikost segmentov (angl. strips) za večnitenje in kliče metodo

detectSingleScale(). Po izhodu iz zanke FOR metoda kopira zaznane objekte iz vektorja

candidates v vektor objects in zažene metodo groupRectangles(), ki skupine objektov, ki

so si dovolj podobni glede na njihovo pozicijo in njihovo velikost, združi v en objekt.

void CascadeClassifier::detectMultiScale( const Mat& image, vector<Rect>& objects, vector<int>& rejectLevels, vector<double>& levelWeights, double scaleFactor, int minNeighbors,

Page 30: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

20

int flags, Size minObjectSize, Size maxObjectSize, bool outputRejectLevels ) { {inicializacija} for( double factor = 1; ; factor *= scaleFactor ) { Size originalWindowSize = getOriginalWindowSize(); Size windowSize( cvRound(originalWindowSize.width*factor), cvRound(originalWindowSize.height*factor) ); Size scaledImageSize( cvRound( grayImage.cols/factor ), cvRound( grayImage.rows/factor ) ); Size processingRectSize( scaledImageSize.width - originalWindowSize.width, scaledImageSize.height - originalWindowSize.height ); if( processingRectSize.width <= 0 || processingRectSize.height <= 0 ) break; if( windowSize.width > maxObjectSize.width || windowSize.height > maxObjectSize.height ) break; if( windowSize.width < minObjectSize.width || windowSize.height < minObjectSize.height ) continue; {skaliranje slike} {nastavljanje yStep glede na tip evaluatorja} int stripCount, stripSize; const int PTS_PER_THREAD = 1000; stripCount = ((processingRectSize.width/yStep)*(processingRectSize.height + yStep-1)/yStep + PTS_PER_THREAD/2)/PTS_PER_THREAD; stripCount = std::min(std::max(stripCount, 1), 100); stripSize = (((processingRectSize.height + stripCount - 1)/stripCount + yStep-1)/yStep)*yStep; if( !detectSingleScale( scaledImage, stripCount, processingRectSize, stripSize, yStep, factor, candidates, rejectLevels, levelWeights, outputRejectLevels ) ) break; } objects.resize(candidates.size()); std::copy(candidates.begin(), candidates.end(), objects.begin()); if( outputRejectLevels ) { groupRectangles( objects, rejectLevels, levelWeights, minNeighbors, GROUP_EPS ); } else{ groupRectangles( objects, minNeighbors, GROUP_EPS ); } }

Koda 3.2: Metoda detectMultiScale().

Koda 3.3 prikazuje metodo detectSingleScale(), ki izvaja zaznavanje v skalirani sliki, ki jo

priskrbi metoda detectMultiScale(). Metoda detectSingleScale() najprej kliče metodo

setImage() iz razreda FeatureEvaluator, ki algoritmu nastavi skalirano sliko. Metoda

setImage() vrne FALSE, ko je slika premajhna za obdelavo (ko sta širina in višina manjša

kot širina in višina spremenljivke originalWindowSize). Če metoda setImage() vrne

FALSE, se izvajanje metode detectSingleScale() konča.

Page 31: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

21

Po tem, ko metoda detectSingleScale() evaluatorju nastavi sliko, kliče še metodo

parallel_for_(), ki skrbi za večnitenje. Metodi parallel_for_() se posreduje sliko, razdeljeno

na segmente in objekt razreda CascadeClassifierInvoker. Metoda parallel_for_() je

namenjena temu, da razdeli izvajanje zaznavanja slike na več niti tako, da za vsak podan

segment slike ustvari svojo nit. V ta namen metoda parallel_for_() uporablja algoritme za

večnitenje, ki jih podpira operacijski sistem, na katerem se algoritem za zaznavanje izvaja.

Na operacijskem sistemu Android noben od ponujenih algoritmov ni podprt, zato se

zaznavanje izvaja v eni niti.

bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, int stripSize, int yStep, double factor, vector<Rect>& candidates, vector<int>& levels, vector<double>& weights, bool outputRejectLevels ) { if( !featureEvaluator->setImage( image, data.origWinSize ) ) return false; {…} parallel_for_(Range(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor, candidatesVector, rejectLevels, levelWeights, false, currentMask, &mtx)); } candidates.insert( candidates.end(), candidatesVector.begin(), candidatesVector.end() ); #if defined (LOG_CASCADE_STATISTIC) logger.write(); #endif return true;

}

Koda 3.3: Metoda detectSingleScale().

Metoda parallel_for_() kliče metodo operator() iz razreda CascadeClassifierInvoker. Koda

3.4 prikazuje metodo operator(). Metodi operator() metoda parallel_for_() poda

spremenljivko range, ki je razpon segmentov slike, ki jih metoda operator() obdeluje. Slika

se obdeluje znotraj gnezdene zanke FOR s pomočjo spremenljivk y1 in y2, ki določata,

kje na osi Y se obdelava začne in konča. Notranja zanka FOR je namenjena obdelavi po

osi X in poteka od nič do širine spremenljivke processingRectSize. Spremenljivka x se po

vsakem izvajanju notranje zanke FOR poveča za vrednost yStep. To pomeni, da glede na

vrednost spremenljivke yStep preskakujemo stolpce, ki jih obdelujemo v sliki. Vrednost

spremenljivke yStep se s skaliranjem slike v metodi detectMultiScale() zmanjšuje, kar

pomeni, da pri večjih slikah preskočimo več vrstic, da prihranimo čas, pri manjših pa tega

ne delamo, da je klasifikacija bolj natančna. Notranja zanka FOR kliče metodo runAt() iz

razreda CascadeClassifier, ki poda tudi spremenljivki x in y v spremenljivki tipa Point, ki

določi, na kateri točki v sliki bo algoritem zagnal klasifikacijo. Metoda runAt() vrne

Page 32: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

22

celoštevilski rezultat, ki je večji kot nič, kadar je klasifikacija pozitivna, in manjši ali enak

nič, kadar je negativna. Če je klasifikacija pozitivna, metoda operator() zaklene semafor

(angl. mutex) in na seznam pravokotnikov doda nov pravokotnik. Pozicijo pravokotnika

izračuna s pomočjo spremenljivk x, y in scalingFactor, širina in višina pravokotnika pa sta

širina in višina spremenljivke winSize.

void operator()(const Range& range) const { Ptr<FeatureEvaluator> evaluator = classifier->featureEvaluator->clone(); Size winSize(cvRound(classifier->data.origWinSize.width * scalingFactor), cvRound(classifier->data.origWinSize.height * scalingFactor)); int y1 = range.start * stripSize; int y2 = min(range.end * stripSize, processingRectSize.height); for( int y = y1; y < y2; y += yStep ) { for( int x = 0; x < processingRectSize.width; x += yStep ) { {…} int result = classifier->runAt(evaluator, Point(x, y), gypWeight); {…} else if( result > 0 ) { mtx->lock(); rectangles->push_back(Rect(cvRound(x*scalingFactor), cvRound(y*scalingFactor), winSize.width, winSize.height)); mtx->unlock(); } if( result == 0 ) x += yStep; }

Koda 3.4: Metoda operator() iz razreda CascadeClassifierInvoker.

Metoda runAt() najprej preveri, ali je kaskada enoravenska (angl. stump based). Kaskada

LBP, ki smo jo uporabljali pri našem projektu, je enoravenska, zato metoda runAt() kliče

metodo predictCategoricalStump().

Metoda predictCategoricalStump(), ki jo prikazuje koda 3.5, opravlja klasifikacijo slike s

pomočjo kaskade klasifikatorjev. Klasifikacija poteka znotraj gnezdenih zank FOR, kjer

notranja zanka FOR izvaja klasifikacijo šibkih klasifikatorjev in prišteva vrednosti listov

odločitvenega drevesa (levi list je negativen, desni pa pozitiven) k seštevku stopnje,

zunanja zanka FOR pa primerja seštevek stopnje s pragom stopnje. Če je seštevek

katere od stopenj manjši od praga stopnje, se klasifikacija konča in metoda

predictCategoricalStump() vrne negativno vrednost spremenljivke si. Spremenljivka si je

iterator stopnje, kar pomeni, da predictCategoricalStump() ob negativni klasifikaciji vrne

število vseh stopenj, ki so sliko klasificirale pozitivno, pomnoženo z -1. Negativen rezultat

Page 33: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

23

nam tako pove hkrati, da je bila klasifikacija negativna in koliko stopenj je označilo

klasifikacijo za pozitivno.

Metoda predictCategoricalStump() je ena od najbolj procesorsko zahtevnih metod v

algoritmu. Napisana je v nizkoravenskem jeziku C++ in ima vse podatkovne strukture in

izračune optimizirane za hitrost. Stopnje, listi dreves in iskalne tabele za šibke

klasifikatorje so zapisani v obliki enodimenzionalnih tabel in do podatkov dostopamo s

pomočjo iteratorjev. Podobno je deljenje in množenje izvedeno s pomočjo bitnih premikov,

bitni nizi pa se primerjajo s pomočjo bitnega IN.

Spremenljivka c določa, kateri list bo metoda predictCategoricalStump() prištela k

seštevku stopnje. Spremenljivko c izračuna metoda operator() iz razreda

FeatureEvaluator. Ta metoda s pomočjo indeksa značilke izračuna vrednost LBP v regiji

te značilke in vrne vrednost med 0 in 255. Indeks lista metoda predictCategoricalStump()

izračuna s stavkom cascadeLeaves[subset[c>>5] & (1 << (c & 31)) ? leafOfs : leafOfs+1].

Razložimo zgoraj zapisan stavek:

subset[c>>5] c>>5 pomeni c/32. Algoritem uporablja bitni premik namesto

deljenja, ker je bitni premik hitrejša operacija. Ta operacija vrne vrednost med 0 in

7, algoritem to vrednost uporabi kot indeks, da si izbere eno od vrednosti iz iskalne

tabele (LUT), ki smo jo dobili iz kaskade;

(1 << (c & 31)) je bitni IN za spremenljivko c in 31, ki je v binarni predstavitvi

11111. To pomeni, da vzamemo prvih pet bitov iz spremenljivke c in na njih

izvedemo bitni premik enke v levo. Ekvivalent tej operaciji je 1 × 2𝑐&31.

Subset [c>>5] & (1 << (c & 31)) algoritem vzame prvih pet bitov iz c, na vrednosti

1 izvede bitni premik v levo za teh prvih pet bitov, izračunano vrednost nato z

bitnim IN primerja z vrednostjo iz iskalne tabele. Ta primerjava je ocenjena z 0,

kadar obe vrednosti nimata isto ležečih bitov, in z 1, kadar jih imata. Če je

vrednost primerjave 0, se izbere desni (pozitivni) list, drugače se izbere levi

(negativni) list.

template<class FEval> inline int predictCategoricalStump( CascadeClassifier& cascade, Ptr<FeatureEvaluator> &_featureEvaluator, double& sum ) { int nstages = (int)cascade.data.stages.size(); int nodeOfs = 0, leafOfs = 0; FEval& featureEvaluator = (FEval&)*_featureEvaluator;

Page 34: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

24

size_t subsetSize = (cascade.data.ncategories + 31)/32; int* cascadeSubsets = &cascade.data.subsets[0]; float* cascadeLeaves = &cascade.data.leaves[0]; CascadeClassifier::Data::DTreeNode* cascadeNodes = &cascade.data.nodes[0]; CascadeClassifier::Data::Stage* cascadeStages = &cascade.data.stages[0]; for( int si = 0; si < nstages; si++ ) { CascadeClassifier::Data::Stage& stage = cascadeStages[si]; int wi, ntrees = stage.ntrees; sum = 0; for( wi = 0; wi < ntrees; wi++ ) { CascadeClassifier::Data::DTreeNode& node = cascadeNodes[nodeOfs]; int c = featureEvaluator(node.featureIdx); const int* subset = &cascadeSubsets[nodeOfs*subsetSize]; sum += cascadeLeaves[ subset[c>>5] & (1 << (c & 31)) ? leafOfs : leafOfs+1]; nodeOfs++; leafOfs += 2; } if( sum < stage.threshold ) return -si; } return 1;}

Koda 3.5: Metoda predictCategoricalStump().

Metoda operator() iz razreda FeatureEvaluator je prikazana v kodi 3.6. Ta metoda dobi

značilko iz vektorja značilk in zanjo kliče metodo calc(). Spremenljivka offset v tej metodi

je pretvorba koordinat x in y v odmik (angl. offset), ki se uporablja kot iterator v

enodimenzionalni predstavitvi slike. Spremenljivka offset je del razreda FeatureEvaluator

in se izračuna ob klicu metode setImage().

int operator()(int featureIdx) const { return featuresPtr[featureIdx].calc(offset); }

Koda 3.6: Metoda operator() iz razreda FeatureEvaluator.

Metoda calc(), ki je prikazana v kodi 3.7, uporablja metodo CALC_SUM_, da izračuna

vrednost LBP in jo vrne kot celo število. Namesto posameznih pikslov algoritem

obravnava devet regij v regiji značilke, kot kaže slika 3.14. Algoritem računa seštevke

vrednosti pikslov znotraj posameznih regij s pomočjo integralne slike. V sliki 3.14 vidimo

točke v integralni sliki in regije, ki jih te točke opisujejo.

Metoda calc() vzorec LBP računa s pomočjo bitnega ALI, kot prikazuje slika 3.15. Bitni ALI

nam vrne unijo dveh vrednosti (oziroma dveh bitnih nizov). Ta unija je bitni niz, kjer je na

ena nastavljen vsak bit, ki je nastavljen na ena v prvem ali v drugem nizu. Spremenljivka

cval predstavlja seštevek pikslov regije v sredini (angl. center value). Algoritem seštevek

regije v sredini primerja s seštevki regij okrog sredinske regije, če je seštevek okoliške

Page 35: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

25

regije večji ali enak seštevku sredinske regije, v bitni niz vstavi 1, drugače vstavi 0. Če

pogledamo kodo 3.7, lahko vidimo, da metoda vrača bitni niz, v katerega vstavlja

posamezne bite, s pomočjo njihovih desetiških vrednosti. 128 je na primer 10000000. To

pomeni, da če dodajamo 128 v bitni niz z bitnim ALI, na ena nastavimo prvi bit z leve. 64

uporabimo za drugi bit, 32 za tretji bit in tako naprej.

V datoteki XML, ki opisuje kaskado klasifikatorjev, so značilke opisane s koordinatami x in

y in s širino in višino. Kot vidimo v sliki 3.14, širina in višina v datoteki XML ne opisujeta

širine in višine celotne značilke, ampak širino in višino ene regije v značilki.

inline int LBPEvaluator::Feature :: calc( int _offset ) const { int cval = CALC_SUM_( p[5], p[6], p[9], p[10], _offset ); return (CALC_SUM_( p[0], p[1], p[4], p[5], _offset ) >= cval ? 128 : 0) | // 0 (CALC_SUM_( p[1], p[2], p[5], p[6], _offset ) >= cval ? 64 : 0) | // 1 (CALC_SUM_( p[2], p[3], p[6], p[7], _offset ) >= cval ? 32 : 0) | // 2 (CALC_SUM_( p[6], p[7], p[10], p[11], _offset ) >= cval ? 16 : 0) | // 5 (CALC_SUM_( p[10], p[11], p[14], p[15], _offset ) >= cval ? 8 : 0)| // 8 (CALC_SUM_( p[9], p[10], p[13], p[14], _offset ) >= cval ? 4 : 0) | // 7 (CALC_SUM_( p[8], p[9], p[12], p[13], _offset ) >= cval ? 2 : 0) | // 6 (CALC_SUM_( p[4], p[5], p[8], p[9], _offset ) >= cval ? 1 : 0); }

Koda 3.7: Metoda calc().

Page 36: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

26

Slika 3.14: Integralne slike v kaskadi LBP [53].

Page 37: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

27

Slika 3.15: Ustvarjanje LBP s pomočjo binarnega ALI.

Metoda CALC_SUM_, ki jo lahko vidimo v kodi 3.8, za računanje seštevka regije

uporablja integralne slike. Spremenljivka p je kazalec na piksel v integralni sliki. Ta

kazalec se nastavi za vsako značilko posebej, v metodi setImage().

Metoda CALC_SUM_ uporablja točke v integralni sliki, da dobi seštevke vrednosti pikslov

v regijah, na isti način kot pri Haarovih značilkah.

#define CALC_SUM_(p0, p1, p2, p3, offset) ((p0)[offset] - (p1)[offset] - (p2)[offset] + (p3)[offset])

Koda 3.8: Metoda CALC_SUM_.

Page 38: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

28

4. Pohitritve algoritma za zaznavanje obrazov

V tem diplomskem delu smo se ukvarjali s pohitritvijo postopkov za lokaliziranje obrazov,

ki so vključeni v knjižnico OpenCV. Detektorji obrazov, ki so implementirani v knjižnici

OpenCV, so hitri že sami po sebi. Na nižjih ravneh, v razredu CascadeClassifier, lahko

vidimo, da so se razvijalci posluževali nizkoravenskih, procesorsko manj zahtevnih metod

za obdelovanje slik. Algoritem sliko obravnava kot enodimenzionalni vektor, deljenje

izvaja s pomočjo bitnega IN, bite v LBP nastavlja s pomočjo bitnega ALI in vse podatke

prenaša po referenci. Na višjih ravneh, v razredu DetectionBasedTracker, pa že lahko

najdemo stvari, ki jih lahko spremenimo.

Vsaka pohitritev je v osnovi odvzem funkcionalnosti algoritmu. Za hitrost žrtvujemo

natančnost, estetiko ali katero od manj pomembnih funkcionalnosti. Za hitrost lahko

žrtvujemo tudi splošnost algoritma, ga priredimo specifično za operacijski sistem in

procesor, na katerih se izvaja.

V našem projektu smo za hitrost žrtvovali natančnost, estetiko in splošnost algoritma. V

nadaljevanju so opisane pohitritve, ki smo jih implementirali v algoritem ter jih tudi

preizkusili.

4.1. Odstranitev večnitenja v razredu DetectionBasedTracker

Razred DetectionBasedTracker je v izvirnem algoritmu zaznaval s pomočjo večnitenja. Za

večnitenje in sinhronizacijo niti je skrbel razred SeparateDetectionWork. Razred

SeparateDetectionWork je v ozadju pregledoval celotno sliko, medtem ko je metoda

process() v glavni niti pregledovala samo regije objektov, ki jim je algoritem že sledil. Ko je

ločena nit končala z detekcijo na celotni sliki, je algoritem nastavil zastavice, ki so metodi

process() povedale, naj vzame nove objekte in poda novo sliko za ločeno nit.

Naprava, na kateri smo testirali algoritem, je imela vgrajen procesor ARM Cortex v8, ki je

enojedrni procesor. To pomeni, da je večnitenje manj učinkovito zaradi dodatnega

procesiranja, ki ga potrebujemo za mednitno sinhronizacijo, kot sta zaklepanje in

odklepanje semaforjev (angl. mutex).

Algoritem smo pohitrili tako, da smo vzeli metodo workCycleObjectDetector() iz razreda

SepearateDetectionWork, jo spremenili v metodo runLargeDetector(), odstranili vse

mehanizme za mednitno sinhronizacijo in uporabili metodo runLargeDetector() v metodi

Page 39: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

29

process() tako, da je metoda process() izvajala metodo runLargeDetector() v glavni niti.

Metodo runLargeDetector() prikazuje koda 4.1.

Rezultat take implementacije sta bila veliko počasnejše izvajanje algoritma in boljše

sledenje objektu – algoritem namreč ne preneha zaznavati obraza ob hitrem gibanju. Tak

rezultat smo dobili, ker je metoda process() po naši spremembi pregledovala celotno sliko

veliko bolj pogosto, kot jo je ločena nit v izvirnem algoritmu. Razred

SeparateDetectionWork je celotno sliko obdelal za približno vsakih devet klicev metode

process(). Da smo pohitrili izvajanje prilagojene metode process(), smo ji dodali

spremenljivko iterationCount, ki šteje klice metode process(). V razred

DetectionBasedTracker smo dodali še celoštevilski parameter

bigDetectorIterationWaitCount (privzeto nastavljen na 10), ki določa, kolikokrat naj

algoritem kliče metodo process(), preden z metodo runLargeDetector() obdela celotno

sliko. Dodano kodo v metodi process() prikazuje koda 4.2.

Končni rezultat pohitritve, po dodajanju parametra bigDetectorIterationWaitCount, je bila

povečana hitrost detekcije s 14 ms na 8 ms in znižana natančnost z 92 % na 85 %, na

našem vzorčnem videu. Natančnost se je znižala, ker je prilagojen algoritem obdelal

celotno sliko manj pogosto kot ločena nit. Stranski učinek pohitritve je bilo povečanje

hitrosti vzorčenja (angl. Frames Per Second ali FPS) za 2, kar je bila posledica tega, da

operacijskemu sistemu ni bilo več treba skrbeti za večnitenje. Končni FPS je bil 5 sličic na

sekundo.

//This method runs the detector on the whole image, in the same thread as the tracking thread is in //As opposed to the separateDetectionWork, it doesn't need any thread synchronization void DetectionBasedTracker::runLargeDetector(const Mat& imageGray, vector<Rect>& objects){ int minObjectSize=parameters.minObjectSize; //Size is width X height Size min_objectSize = Size(minObjectSize, minObjectSize); int maxObjectSize=parameters.maxObjectSize; Size max_objectSize(maxObjectSize, maxObjectSize); //CascadeInThread is of type CascadeClassifier, origin: objectdetect/cascadedetect //This is the call that does the actual detection work using a CascadeClassifier cascadeForTracking.detectMultiScale( imageGray, objects, parameters.scaleFactor, parameters.minNeighbors, 0 |CV_HAAR_SCALE_IMAGE, min_objectSize, max_objectSize );}

Koda 4.1: Metoda runLargeDetector().

Page 40: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

30

//We only run the detector on the whole image every so often, so that we gain on performance //However: the tracker is more likely to lose a tracked object due to fast movement if(iterationCount>=parameters.bigDetectorIterationWaitCount){ runLargeDetector(imageGray,rectsWhereRegions); shouldHandleResult=true; iterationCount=0;}

Koda 4.2: Dodana koda v metodi process().

4.2. Sprememba prikaza zaznanih objektov

Za prikaz zaznanih objektov razred DetectionBasedTracker uporablja metodo

calcTrackedObjectPositionToShow(), prikazano v kodi 4.3, ki jo kliče metoda getObjects().

Za vsak zaznan objekt algoritem shranjuje več kot eno pozicijo, zato uporabimo metodo

calcTrackedObjectsPositionToShow(), ki vrne pravokotnik, ki predstavlja srednjo vrednost

vseh shranjenih pozicij za posamezen objekt.

Rect DetectionBasedTracker::calcTrackedObjectPositionToShow(int i) const { if ( (i < 0) || (i >= (int)trackedObjects.size()) ) { return Rect(); } if (trackedObjects[i].numDetectedFrames <= innerParameters.numStepsToWaitBeforeFirstShow){ return Rect(); } if (trackedObjects[i].numFramesNotDetected > innerParameters.numStepsToShowWithoutDetecting) { return Rect();} const TrackedObject::PositionsVector& lastPositions=trackedObjects[i].lastPositions; int N=lastPositions.size(); if (N<=0) { return Rect(); } int Nsize=std::min(N, (int)weightsSizesSmoothing.size()); int Ncenter= std::min(N, (int)weightsPositionsSmoothing.size()); Point2f center; double w=0, h=0; if (Nsize > 0) { double sum=0; for(int j=0; j < Nsize; j++) { int k=N-j-1; w+= lastPositions[k].width * weightsSizesSmoothing[j]; h+= lastPositions[k].height * weightsSizesSmoothing[j]; sum+=weightsSizesSmoothing[j]; } w /= sum; h /= sum; } else { w=lastPositions[N-1].width; h=lastPositions[N-1].height; } if (Ncenter > 0) { double sum=0;

Page 41: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

31

for(int j=0; j < Ncenter; j++) { int k=N-j-1; Point tl(lastPositions[k].tl()); Point br(lastPositions[k].br()); Point2f c1; c1=tl; c1=c1* 0.5f; Point2f c2; c2=br; c2=c2*0.5f; c1=c1+c2; center=center+ (c1 * weightsPositionsSmoothing[j]); sum+=weightsPositionsSmoothing[j]; } center *= (float)(1 / sum); } else { int k=N-1; Point tl(lastPositions[k].tl()); Point br(lastPositions[k].br()); Point2f c1; c1=tl; c1=c1* 0.5f; Point2f c2; c2=br; c2=c2*0.5f; center=c1+c2; } Point2f tl=center-(Point2f(w,h)*0.5); Rect res(cvRound(tl.x), cvRound(tl.y), cvRound(w), cvRound(h)); return res; }

Koda 4.3: Metoda calcTrackedObjectsPositionToShow().

Naša pohitritev metode je bila odstranitev računanja srednje vrednosti pravokotnika in

prilagojena metoda je preprosto vračala zadnjo zaznano pozicijo. Prilagojena metoda

calcTrackedObjectsToShow() je prikazana v kodi 4.4.

Rect DetectionBasedTracker::calcTrackedObjectPositionToShow(int i) const { //A segmentation fault checker if ( (i < 0) || (i >= (int)trackedObjects.size()) ) { return Rect(); //We don't want to show rectangles, unless we're sure, that there's an object there, //meaning we have to detect an object more than once to show it, otherwise the screen would be full of rectangles if (trackedObjects[i].numDetectedFrames <= innerParameters.numStepsToWaitBeforeFirstShow){ return Rect(); } //Similarly, we don't show an object, once the non-detection threshold has been reached if (trackedObjects[i].numFramesNotDetected > innerParameters.numStepsToShowWithoutDetecting) { return Rect(); return trackedObjects[i].lastPositions.back();}

Koda 4.4: Prilagojena metoda calcTrackedObjectsPositionToShow().

Page 42: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

32

Algoritem je bil po pohitritvi nezaznavno hitrejši – pridobili smo manj kot 1 ms. Pohitritev ni

imela učinka na natančnost, imela pa je učinek na estetiko prikaza, kvadrat okrog

zaznanega obraza se je namreč premikal bolj kot v izvirni različici algoritma.

4.3. Sprememba metode detectMultiScale()

Metoda detectMultiScale() poleg velikosti slike skalira tudi okno za zaznavanje od

manjšega proti večjemu. Ko je vhodna slika premajhna za zaznavanje, pa se metoda

zaključi.

S tem, da okno za zaznavanje s časom večamo, zagotovimo, da okrog zaznanega obraza

prikazujemo pravokotnik, ki zajame celoten obraz. Algoritem smo spremenili tako, da je

metoda detectMultiScale() vračala prvega zaznanega kandidata, namesto da bi naprej

skalirala sliko. S tem smo žrtvovali estetiko, ker zaznani pravokotnik ni več zajemal

celotnega obraza. Vrstico, s katero smo spremenili izvajanje metode detectMultiScale(),

prikazuje koda 4.5.

for( double factor = 1; ; factor *= scaleFactor ) { {…} if(candidates.size() > 0) break; {…}}

Koda 4.5: Dodana koda v metodi detectMultiScale().

Rezultat pohitritve sta bila zmanjšan čas izvajanja na 1 ms in zmanjšana stopnja

zaznavanja na 0 %. Razlog za tako slabo stopnjo zaznavanja je bil, da algoritem po

izhodu iz zanke FOR kliče metodo groupRectangles(), ki grupira pravokotnike glede na

podobnost [54]. Metoda groupRectangles() uporablja parameter minNeighbors, ki je

privzeto nastavljen na 2. Ker smo prekinili zanko FOR s samo enim kandidatom, je

metoda groupRectangles() zaznavanje obravnavala kot napačen pozitiven (angl. false

positive) zadetek in zavrgla objekt.

Da smo prišli nazaj na sprejemljivo raven zaznavanja, smo nastavili prag za število

zaznanih kandidatov s spremenljivko exitThreshold, ki smo jo nastavili na vrednost

minNeighbors*2. Prilagojeno vrstico prikazuje koda 4.6.

Page 43: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

33

//exitThreshold is the threshold we'll be using to exit the for loop unsigned int exitThreshold=minNeighbors*2; if(candidates.size()>=exitThreshold) break;

Koda 4.6: Prilagojena koda v metodi detectMultiScale().

Poskusili smo še odstraniti klic metode groupRectangles(), ampak nam ta sprememba ni

prinesla nobene pohitritve, je pa znižala natančnost algoritma, ki je padla na 66 %.

Končni rezultat naše pohitritve je zmanjšan čas izvajanja za 2 ms (iz 8 ms na 6 ms),

natančnost pa je ostala pri 85 % za naš vzorčni video.

4.4. Odstranitev klicev metode parallel_for_()

Metoda detectSingleScale() kliče metodo parallel_for_(), ki je del ogrodja za paralelizacijo

iz knjižnice OpenCV. Ta najprej preveri, če je paralelizacijsko ogrodje knjižnice OpenCV

omogočeno. Po nekaj poskusih s pomočjo konzole LogCat za razhroščevanje smo

ugotovili, da v naši aplikaciji Android to ogrodje ni podprto, zato je klic metode

parallel_for_() nesmiseln.

Metoda parallel_for_() uporablja metodo operator() iz razreda CascadeClassifierInvoker.

Kodo iz metode operator() smo prestavili v metodo detectSingleScale() in se s tem izognili

uporabi metode parallel_for_(), ogrodja za paralelizacijo iz knjižnice OpenCV in njegove

logike za mednitno sinhronizacijo.

Koda 4.7 prikazuje izvirno metodo detectSingleScale(), ki vsebuje klic metode

parallel_for_(), skupaj z vsemi parametri in objektom razreda CascadeClassifierInvoker,

prek katerega paralelizacijsko ogrodje dobi vse potrebne podatke za večnitenje in

zaznavanje. Koda 4.8 pa prikazuje prilagojeno metodo detectSingleScale, ki vsebuje

logiko za zaznavanje, preneseno iz metode operator() iz razreda

CascadeClassifierInvoker.

Rezultat pohitritve je bil nezaznavno hitrejši algoritem (izvajanje je bilo hitrejše za manj kot

1 ms), kar pomeni, da uporaba ogrodja za paralelizacijo iz knjižnice OpenCV ne pomeni

velike obremenitve procesorja, še posebej, ko to ogrodje ni omogočeno.

bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, int stripSize, int yStep, double factor, vector<Rect>& candidates, vector<int>& levels, vector<double>& weights, bool outputRejectLevels ) { {…}

Page 44: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

34

else { parallel_for_(Range(0, stripCount), CascadeClassifierInvoker( *this, processingRectSize, stripSize, yStep, factor, candidatesVector, rejectLevels, levelWeights, false, currentMask, &mtx)); } {…} }

Koda 4.7: Izvirna metoda detectSingleScale().

bool CascadeClassifier::detectSingleScale( const Mat& image, int stripCount, Size processingRectSize, int stripSize, int yStep, double factor, vector<Rect>& candidates, vector<int>& levels, vector<double>& weights, bool outputRejectLevels ) { {…} else { Size winSize(cvRound(data.origWinSize.width * factor), cvRound(data.origWinSize.height * factor)); Range range(0,stripCount); int y1 = range.start * stripSize; int y2 = min(range.end * stripSize, processingRectSize.height); for( int y = y1; y < y2; y += yStep ) { for( int x = 0; x < processingRectSize.width; x += yStep ) { double gypWeight; //runAT gives us the result of LBP classification at the current point int result = runAt(featureEvaluator, Point(x, y), gypWeight); if( result > 0 ) { candidatesVector.push_back(Rect(cvRound(x*factor), cvRound(y*factor), winSize.width, winSize.height)); } if( result == 0 ) x += yStep; } } } {…} }

Koda 4.8: Prilagojena metoda detectSingleScale().

4.5. Prilagajanje parametrov

Razred DetectionBasedTracker ima nabor parametrov, ki jih lahko spremenimo, da

prilagodimo delovanje algoritma naši aplikaciji.

Page 45: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

35

Parametri, ki jih imamo na voljo (in njihove privzete vrednosti), so:

minObjectSize (96), ki določa minimalno velikost objekta, ki mu bomo še sledili,

maxObjectSize (INT_MAX),

scaleFactor (1,1) določa, kako hitro se bodo skalirali objekti v metodi

detectMultiScale(),

maxTrackLifetime (5) določa, koliko detekcij lahko preteče, brez da bi zaznali

objekt, preden ga označimo za izgubljenega,

minNeighbors (2) določa, koliko objektov mora biti zaznanih na eni poziciji, da jo

sprejmemo kot zaznan objekt. S tem parametrom se znebimo napačnih pozitivnih

(angl. false pozitive) klasifikacij,

minDetectionPeriod (20) določa, koliko časa naj počaka ločena nit iz razreda

SeparateDetectionWork, preden začne detekcijo z novo sliko.

Te glavne parametre lahko nastavljamo zunaj razreda DetectionBasedTracker, na primer

v ovojnici JNI. Poleg glavnih parametrov pa ima razred DetectionBasedTracker še

notranje parametre v razredu InnerParameters. Ti parametri (in njihove privzete vrednosti)

so:

numLastPositionsToTrack (4) določa, koliko pozicij shranjujemo za vsak objekt, ki

mu sledimo,

numStepsToWaitBeforeFirstShow (6) določa, koliko zaznav hočemo za vsak

objekt, preden ga sploh začnemo prikazovati,

numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown (3) podobno kot

parameter maxTrackLifetime, s tem da ga uporabljamo, ko objekta še nismo

prikazali,

numStepsToShowWithoutDetecting (3) podobno kot parameter maxTrackLifetime,

s tem da algoritem parameter maxTrackLifetime uporablja, ko se odloča, ali bo

izbrisal objekt, parameter numStepsToShowWithoutDetecting pa uporablja samo

pri prikazovanju,

Page 46: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

36

coeffTrackingWindowSize (2,0) je koeficient za nastavljanje velikosti sledilnega

okna,

coeffObjectSizeToTrack (0,85) je koeficient za nastavljanje velikost objekta za

sledenje,

coeffObjectSpeedUsingInPrediction (0,8) je koeficient, ki ga algoritem uporablja za

nastavljanje novega položaja objekta, ki mu sledi. Tukaj algoritem uporablja

predvidevanje glede na prejšnje pozicije objekta.

Da bi algoritem pohitrili, smo eksperimentirali s parametri. Vsakega posebej smo večali in

manjšali ter opazovali učinke na hitrost in natančnost algoritma ter prikazovanje zaznanih

objektov. Tiste spremembe parametrov, ki so zmanjšale čas izvajanja, smo obdržali v

končni različici pohitritve, parametre, ki niso vplivali na hitrost, pa smo nastavili nazaj na

privzeto vrednost. V nadaljevanju so opisani rezultati teh eksperimentiranj.

Ko smo povečali vrednost parametra minObjectSize, se je natančnost algoritma neznatno

povečala, hitrost pa se ni izboljševala. V končni različici pohitritve smo parameter

minObjectSize nastavili na privzeto vrednost.

Ko smo povečali vrednost parametra scaleFactor, se je hitrost sicer povečevala, ampak je

algoritem izgubljal natančnost (do 20 % manjša natančnost), hkrati je bil algoritem veliko

slabši pri zaznavanju obrazov, ki so bili bližje kameri. V končni različici pohitritve smo

parameter scaleFactor povečali z 1,1 na 1,4. Ta sprememba nam je dala hitrejši algoritem

z manjšo izgubo natančnosti.

Ko smo zmanjšali vrednost parametra maxtrackLifetime na 1, smo izgubili nekaj

natančnosti ob hitrem gibanju, na hitrost izvajanja algoritma pa ni bilo vpliva. V končni

različici pohitritve smo parameter maxTrackLifetime nastavili nazaj na privzeto vrednost.

Ko smo zmanjšali vrednost parametra minNeighbors na 1, je bilo izvajanje algoritma malo

hitrejše, brez posledic za natančnost. V končni različici pohitritve smo parameter

minNeighbors zmanjšali z 2 na 1.

Ko smo povečali vrednost parametra minDetectionPeriod, se je hitrost izvajanja algoritma

povečala, ampak smo izgubili natančnost pri hitrem gibanju. Razlog za to je, da je

algoritem dlje časa ignoriral vhodne slike in obdeloval samo objekte, ki jim je sledil,

medtem ko je ločena nit čakala (nastavljanje parametra minDetectionPeriod smo testirali,

Page 47: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

37

preden smo odstranili večnitenje). V končni različici pohitritve smo parameter

minDetectionPeriod nastavili nazaj na privzeto vrednost.

Ko smo zmanjšali vrednost parametra numLastPositionsToTrack, algoritem ni deloval

znatno hitreje, bil pa je negativni učinek na prikazani pravokotnik okrog zaznanega

objekta, ki se je premikal bolj kot v izvirni različici algoritma. V končni različici pohitritve

smo vrednost parametra numLastPositionsToTrack nastavili nazaj na privzeto vrednost.

Ko smo zmanjšali vrednost parametra numStepsToWaitBeforeFirstShow, izvajanje ni bilo

hitrejše, povečala pa se je natančnost, ker je algoritem zaznani objekt prikazal takoj.

Negativna posledica te spremembe je, da tvegamo več napačnih pozitivnih (angl. false

positive) zadetkov. V končni različici pohitritve smo vrednost parametra

numStepsToWaitBeforeFirstShow zmanjšali s 6 na 3.

Ko smo manjšali vrednosti parametrov numStepsToTrackWithoutDetectingIfObjectHasNot

BeenShown in numStepstoShowWithoutDetecting, algoritem ni deloval hitreje, izgubili pa

smo natančnost, ker je bil algoritem bolj občutljiv na negativne klasifikacije in je hitreje

zavrgel objekte. V končni različici pohitritve smo vrednosti teh dveh parametrov nastavili

nazaj na privzeti vrednosti.

Ko smo zmanjšali vrednost parametra coeffTrackingWindowSize, se je algoritem izvajal

za 1 ms hitreje. V končni različici algoritma smo vrednost tega parametra zmanjšali z 2 na

1,5.

Ko smo povečali parameter coeffTrackingObjectSizeToTrack z 0,85 na 1,1, je bil

algoritem hitrejši, natančnost pa je bila prenizka. Ko smo ga zmanjšali na 0,5, smo

algoritem upočasnili. Ko smo ga povečali za manjšo vrednost (z 0,85 na 0,95), pa je bil

algoritem za eno milisekundo hitrejši in za 2 % manj natančen. Hkrati je postal manj

odziven ob približevanju objekta proti kameri in oddaljevanju objekta od kamere. V končni

različice pohitritve smo nastavili vrednost parametra coeffTrackingObjectSizeToTrack na

0,95.

Ko smo spreminjali vrednost parametra coeffObjectSpeedUsingInPrediction, pa nismo

vplivali na hitrost ali natančnost algoritma. V končni različici pohitritve smo vrednost tega

parametra nastavili nazaj na privzeto vrednost.

Končni nabor parametrov in njihovih vrednosti je prikazan v kodi 4.9.

Page 48: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

38

minObjectSize = 96; maxObjectSize = INT_MAX; scaleFactor = 1.4; maxTrackLifetime = 5; minNeighbors = 1; minDetectionPeriod = 20; numLastPositionsToTrack = 4; numStepsToWaitBeforeFirstShow = 3; numStepsToTrackWithoutDetectingIfObjectHasNotBeenShown = 3; numStepsToShowWithoutDetecting = 3; coeffTrackingWindowSize = 1.5; coeffObjectSizeToTrack = 0.95; coeffObjectSpeedUsingInPrediction = 0.8;

Koda 4.9: Parametri razreda DetectionBasedTracker.

Končni rezultat prilagajanja parametrov so bili znatna pohitritev, izguba natančnosti in

opazne spremembe pri prikazovanju zaznanih objektov.

4.6. Trivialne pohitritve

Izvirni algoritem v razredih DetectionBasedTracker in CascadeClassifier ima veliko kode,

ki je naša implementacija ne uporablja. Primer take kode so vsi stavki IF, kjer se preverja

vrednost spremenljivke outputRejectLevels. Spremenljivka outputRejectLevels je v našem

primeru vedno FALSE, ker je namenjena testiranju učinkovitosti kaskade, kar pa nas ne

zanima, ker kaskade nismo trenirali sami, ampak smo uporabili že preizkušeno kaskado.

Drugi primer take kode so deklaracije skupaj z inicializacijami znotraj zank FOR. Ker se

deklaracija izvaja vsakič, ko se zažene zanka FOR, je hitreje, če je deklaracija zunaj

zanke in se znotraj zanke nastavlja le njena vrednost.

Za našo pohitritev smo odstranili neuporabljeno kodo in prestavili deklaracije izven zank

FOR. Rezultat te pohitritve je bil nezaznavno hitrejši algoritem (manj kot 1 ms hitrejše

izvajanje) brez vpliva na natančnost zaznave ali prikaz zaznanih objektov.

Page 49: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

39

5. Rezultati

V tem poglavju so opisani rezultati naših pohitritev algoritma za zaznavanje obrazov iz

knjižnice OpenCV. Opisali smo eksperimentalno okolje, definirali, kako merimo

učinkovitost pohitritev, in prikazali rezultate naših testov.

5.1. Opis eksperimentalnega okolja

Pri testiranju hitrosti algoritma je pomembno, da ima odvzemanje testnih vzorcev čim

manj vpliva na izvajanje algoritma. Iz tega razloga naših vzorcev nismo prikazovali in

analizirali na tablici, ampak smo jih pošiljali prek internetne povezave na strežnik v obliki

niza. Strežnik je bila namizna aplikacija, napisana v programskem jeziku C#, ki je hranila

podatke v tekstovni obliki. Strežnik je imel naslednje funkcionalnosti:

funkcionalnost za prevajanje podatkov iz nizov v spremenljivke (angl. parsing),

funkcionalnost za prikaz podatkov,

funkcionalnost za izvoz podatkov v datoteko CSV (angl. Comma Separated

Values),

funkcionalnost za računanje povprečnega časa izvajanja za več izbranih

elementov v seznamu in

funkcionalnost za sledenje različici.

Zaslonsko sliko strežnika prikazuje slika 5.1.

Page 50: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

40

Slika 5.1: Testni strežnik.

Različica je bila sestavljena iz spremenljivk release, major, minor in build, uporabljali pa

smo samo spremenljivki minor in build. Vrednost spremenljivke build se je povečevala s

pomočjo programa VersionIncrementer.exe, ki je bila konzolna aplikacija, napisana v

programskem jeziku C#. Ko smo zagnali aplikacijo VersionIncrementer.exe, je ta strežniku

poslala ukaz, da naj poveča vrednost spremenljivke build. To aplikacijo je zagnalo

razvojno okolje Eclipse vsakič, ko se je zgradila naša aplikacija za operacijski sistem

Android. Spremenljivka build je bila namenjena za grobo sledenje različici, da smo lahko

ločevali med zgodnejšimi in poznejšimi različicami naše aplikacije. Spremenljivko minor

pa smo spreminjali s pomočjo številčnice vsakič, ko smo implementirali ali odstranili

katero od pohitritev. Vrednost različice se je shranjevala in posodabljala v datoteki

version.txt.

Testni strežnik je imel tudi funkcionalnost, ki nam je omogočala, da smo shranjevali

številko različice in opis spremembe (angl. changelog) v datoteko HTML. Slika 5.2

prikazuje to datoteko, odprto v brskalniku Internet Explorer.

Page 51: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

41

Slika 5.2: Spremembe različic.

Za pošiljanje podatkov smo v Android kodo implementirali razred Tester. Podatki o

posameznem testu so se shranjevali v seznamu, ki je vseboval objekte razreda Test.

Razred Test je imel spremenljivke za shranjevanje časa začetka in konca, seznam

detekcij in spremenljivko type, ki nam je povedala, ali gre za zaznavanje na sliki ali na

videu. Seznam detekcij je vseboval objekte razreda Detection, ki je vseboval spremenljivki

hit in duration. Spremenljivka hit nam je povedala, ali je bil pri tej detekciji zaznan obraz ali

ne, spremenljivka duration pa je bila celoštevilska in je predstavljala trajanje detekcije v

milisekundah.

Detekcija se je izvajala v ovojnici Java. Kot vidimo v kodi 5.1, smo za merjenje trajanja

detekcije izmerili trenutni čas (v milisekundah) pred in po klicu metode detect(). Metoda

detect() iz ovojnice JNI kliče metodo process() iz razreda DetectionBasedTracker v kodi

C++. Trajanje detekcije smo izračunali tako, da smo čas začetka detekcije odšteli od časa

konca detekcije. Razred Tester je zapisoval podatke zunaj ovojnice JNI znotraj aplikacije

Android.

long startTime=System.currentTimeMillis(); detectionBasedTracker.detect(grayscale, faces); long stopTime=System.currentTimeMillis();

Koda 5.1: Merjenje trajanja metode detect().

Pri videu smo test začeli takrat, ko je algoritem začel z obdelavo prve slike iz videa, in ga

končali takrat, ko je algoritem končal z obdelavo zadnje slike iz videa. Vmes so se

Page 52: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

42

zapisovali rezultati obdelave posameznih slik v objekt razreda Test. Pri sliki s kamere

izbira začetka in konca testa ni tako preprosta. Problem nastane, ko se odločamo, kdaj

končati test. Ne moremo se namreč popolnoma zanašati na natančnost algoritma, ker če

ta ne zaznava obraza, še ne pomeni, da ni obraza, hkrati pa lahko ima napačne pozitivne

(angl. false positive) zadetke. Problem se pokaže, ko algoritem ob gibanju obraza tega

začasno izgubi. Če bi test prekinili takoj, ko obraza ni, bi bili rezultati testa nerealni. Za ta

namen smo dodali toleranco za detekcije brez zadetkov, ki test prekine šele, ko je 10

zaporednih detekcij praznih.

Po tem, ko se detekcija konča, razred Tester izračuna povprečno trajanje, povprečne

zadetke detekcije, prevede podatke v niz in pošlje niz testnemu strežniku.

Naša Android aplikacija je imela preprost uporabniški vmesnik z dvema zavihkoma. Eden

od zavihkov je namenjen sliki s kamere, drugi pa predvajanju videa. Ob zagonu aplikacije

se najprej naloži video, šele po tem se naložijo zavihki in preostanek uporabniškega

vmesnika. Zaslonsko sliko aplikacije lahko vidimo na sliki 5.3.

Slika 5.3: Android aplikacija.

Pri branju videa so nastajali problemi, ker smo morali brati vsako sliko posebej, da smo na

njej iskali obraze. Ker je video zakodiran, je nepraktično prebrati določen okvir, ga najprej

pretvoriti v format BMP in nato še v spremenljivko tipa Mat ter izvajati detekcijo na njem.

Page 53: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

43

Poskusili smo pridobivanje posameznih okvirov z različnimi metodami, ki so nam bile na

voljo. Uporabili smo razred VideoCapture [55] iz knjižnice OpenCV, razred

MediaMetaDataRetriever [56] ki je del platforme Android, razred MediaExtractor [57], ki je

bil nedavno implementiran v platformo Android, in razred FFMPEGMediaMetadata

Retriever, ki ga je naredil William Seemann [58].

Razred MediaMetadataRetriever ni vračal ničesar, zato smo poskusili razred

VideoCapture, zanj naredili ovojnice v JNI in Java, ampak je vračal FALSE in v podano

matriko zapisoval prazno sliko. Ob uporabi razreda MediaExtractor pa je strojni kodek

javljal napako in zaradi pomanjkljive dokumentacije (implementacija razreda je bila takrat

še sveža) nismo našli rešitve za ta problem.

Edino delujoče orodje za naš namen je bil razred FFMPEGMediaMetadataRetriever, ki ga

je uporabljala tudi končna različica aplikacije. Ker je porabil veliko časa za pridobivanje

ene slike, smo zmanjšali ločljivost videa. Posledica manjše ločljivosti so bile hitrejše

detekcije na videu v primerjavi z detekcijami na slikah s kamere. Tudi z nižjo ločljivostjo pa

nismo predvajali videa z izvirno hitrostjo vzorčenja (12 slik na sekundo), ampak je bilo

predvajanje počasnejše, in sicer 4 slike na sekundo.

Razred FFMPEGMediaMetadataRetriever pa je imel poleg počasnega izvajanja še eno

napako. Po nekaj časa (video je bil običajno v svojem četrtem ciklu predvajanja) se je

naša aplikacija zrušila, brez da bi konzola LogCat zabeležila izjemo. Aplikacijo smo zato

spremenili tako, da se je video naložil pred začetkom izvajanja programa v seznam slik

formata BMP. To je bila pomnilniško zelo zahtevna implementacija, nalaganje pa je trajalo

skoraj dve minuti. S to implementacijo pa smo rešili problema počasnega predvajanja

(video ima spet izvornih 12 slik na sekundo) in nenadnega prenehanja delovanja

aplikacije.

5.2. Metrike učinkovitosti

Vsaka pohitritev je bila kombinacija pridobitve hitrosti in izgube natančnosti. Hitrost smo

merili v povprečnem času (milisekundah), ki je bil potreben za izvedbo ene detekcije,

natančnost pa v odstotku zaznanih obrazov. Učinkovitost pohitritev smo merili predvsem

na videu, tam smo imeli enak nabor slik za vsak test, na vseh slikah je bil obraz in v

vsakem testu je bilo enako število slik. Na kameri smo testirali predvsem zato, da smo

preverili, kako je algoritem deloval ob hitrem gibanju obraza, kako se je spreminjal prikaz

zaznanih obrazov in kako je algoritem deloval pri zaznavanju več obrazov.

Page 54: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

44

5.3. Rezultati testiranj na tablici

Tablični računalnik, na katerem smo testirali našo Android aplikacijo, je bil Prestigio

MultiPad 7.0 Ultra + [9]. Imel je vgrajen procesor ARM Cortex A8, ki je enojedrni procesor,

ki je deloval s taktom 1 GHz. Tablični računalnik je imel na voljo še 512 MB delovnega

pomnilnika. Za zajem slike smo uporabljali sprednjo kamero, ki je imela 0,3 milijona

pikslov in je snemala video dimenzij 640 pikslov (širina) in 480 pikslov (višina).

V tabeli 5.1 lahko vidimo posamezne pohitritve, ki smo jih implementirali, in njihov vpliv na

hitrost in natančnost algoritma. Tabela vključuje podatke testov detekcije na videu. Pri

vsakem testu imamo 112 klasifikacij, ker imamo 112 slik v videu, rezultat testa pomeni

povprečno trajanje vseh 112 klasifikacij. V tabeli pa imamo povprečno trajanje vseh testov

za vsako pohitritev posebej. Pri pohitritvi, kjer smo odstranili večnitenje, lahko vidimo, da

večji kot je parameter bigDetectorWaitCount, hitreje se je izvajal algoritem. Pri pohitritvi,

kjer smo spremenili skaliranje, pa vidimo, da je prehiter izhod iz zanke FOR negativno

vplival na natančnost algoritma.

Graf hitrosti algoritma za video na sliki Slika 5.4 nam okvirno prikazuje, kako se je hitrost

algoritma spreminjala. Ta graf ni bil izdelan z uporabo podatkov iz tabele 5.1, ampak iz

filtriranih rezultatov vseh testov. Številke na vrhu predstavljajo zaporedne številke

pohitritev, kot so zapisane v tabeli 5.1, vrednosti na x osi predstavljajo zaporedno številko

testa (se ne sovpadajo s tabelo 5.1), vrednosti na y osi pa pomenijo povprečno trajanje

enega zaznavanja za vsak test (vsak test ima 112 ločenih klasifikacij, zato vzamemo za

trajanje njihovo povprečje). Ker smo imeli veliko število testov (preko 1800), so v podatkih

za graf vključeni samo tisti testi, ki so predstavljali končne različice pohitritev. Med njimi je

bilo namreč veliko rezultatov, ki smo jih dobili med popravljanjem napak v aplikaciji.

Tabela 5.1: Pohitritve algoritma.

Zaporedna številka

pohitritve

Povprečno trajanje

testa [ms]

Pohitritev izvajanja

[ms]

Povprečje zadetkov

[%]

Hitrost vzorčenja [slike na sekundo]

Opis spremembe

0 13,714 0 92,857 4,335 Izvirna različica algoritma.

1 56,125 -42,411 94,642 4,224 Odstranitev večnitenja, namesto tega smo uporabljali detektor na celotni sliki vsakič, ko kličemo metodo process().

2 12,571 43,554 90,178 5,270 Dodajanje parametra bigDetectorIterationWaitCoun

Page 55: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

45

Zaporedna številka

pohitritve

Povprečno trajanje

testa [ms]

Pohitritev izvajanja

[ms]

Povprečje zadetkov

[%]

Hitrost vzorčenja [slike na sekundo]

Opis spremembe

t s privzeto vrednostjo 5, ki pove programu, koliko iteracij naj preteče, preden zažene detektor na celotni sliki.

3 8,285 4,286 85,714 5,308 Povečanje vrednosti parametra bigDetectorIterationWaitCount s 5 na 10.

4 7,826 0,459 86,157 5,564 Sprememba prikaza zaznanih pravokotnikov, namesto normaliziranega zdaj prikazujemo samo zadnjega.

5 1 6,826 0 5,781 Sprememba skaliranja v metodi detectMultiScale(), zdaj se vrne že prvi najdeni kandidat.

6 6,857 -5,857 86,734 5,527 Algoritem za skaliranje, spremenjen nazaj v izvirnega, ker detekcije niso delovale.

7 3 3,857 10,714 5,717 Dodana vrstica, ki konča zanko FOR za detekcijo v metodi detectMultiScale() takrat, ko najdemo vsaj enega kandidata.

8 4,5 -1,5 18,75 5,199 Sprememba prej dodane vrstice, da prekine zanko FOR takrat, ko sta najdena vsaj dva kandidata.

9 6 -1,5 85,714 5,412 Sprememba prej dodane vrstice, da prekine zanko FOR takrat, ko je najdenih vsaj dvakrat toliko kandidatov, kot je vrednost parametra minNeighbors.

10 6,066 -0,66 85,714 5,524 Odstranitev klicev metode parallel_for_(), učinkovite metode smo preselili v zanko FOR v metodi detectSingleScale().

11 1 5,066 76,785 12,735 Pohitritev s spremembo parametrov.

Page 56: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

46

Slika 5.4: Graf hitrosti za video.

Iz naših podatkov pa ne vidimo sprememb pri prikazovanju zaznanih objektov. Po

implementaciji pohitritev je bil prikaz pravokotnika okrog zaznanega obraza opazno

drugačen od prikazovanja pri izvirni implementaciji algoritma. Pravokotnik se je veliko bolj

premikal, tudi ko se obraz ni premikal. Ena od posledic spremembe skaliranja je bila

razlika pri prilagajanju pravokotnika, ko se obraz približuje kameri ali oddaljuje od kamere.

Druga posledica spremembe skaliranja je bila ta, da pravokotnik ni več zajemal celotnega

obraza. Občutljivost na premikanje obraza pa je bila podobna izvirni implementaciji

algoritma, ker je ločena nit delala na podobnem intervalu kot je interval pri naši

implementaciji. Še ena funkcionalnost, za katero nimamo statističnih testov, je zaznavanje

več obrazov. Po nekaj preizkusih s pomočjo slike, ki vsebuje več obrazov [59], smo

ugotovili, da je algoritem sicer še sposoben zaznati več obrazov, ampak je pri tem manj

uspešen. Veliko obrazov namreč izpusti, kar je posledica spremenjenega skalirnega

faktorja. Na sliki 5.5 vidimo zaznavanje več obrazov z izvirnim algoritmom, na sliki 5.6 pa

zaznavanje več obrazov z našo implementacijo algoritma. Vidimo lahko, da je prilagojen

algoritem slabši pri zaznavanju več obrazov, vidimo pa lahko tudi, kako naše pohitritve

povzročijo manjši pravokotnik okrog zaznanega obraza.

Page 57: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

47

Slika 5.5: Zaznavanje več obrazov – izvirni algoritem.

Slika 5.6: Zaznavanje več obrazov – pospešeni algoritem.

V končni pohitritvi smo implementirali odstranitev večnitenja (glej vrstico 3 v tabeli 5.1),

spremembo skaliranja v metodi detectMultiScale() (glej vrstico 9 v tabeli 5.1) in

Page 58: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

48

prilagoditve parametrov (glej vrstico 11 v tabeli 5.1). Dosegli smo pohitritev za 13 ms, pri

čemer je natančnost padla za 18 %.

Page 59: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

49

6. Diskusija in zaključek

V diplomskem delu smo proučili enega od algoritmov za zaznavanje obrazov iz knjižnice

OpenCV. Ugotovili smo, da je algoritem že sam po sebi precej hiter in zmogljiv. Algoritem

smo implementirali v Android aplikacijo, ki je delovala na tablici z enojedrnim procesorjem

in 512 MB delovnega pomnilnika. Algoritem smo še prilagodili, ga pohitrili in testirali

časovno zahtevnost na video vzorcu.

Rezultati so pokazali, da moramo za vsako pohitritev nekaj žrtvovati; natančnost,

funkcionalnost ali estetiko. Glede na namen aplikacije, ki ta algoritem uporablja, se

moramo odločiti, ali je smiselno uporabljati posamezne pohitritve.

Po testih lahko vidimo, da je algoritem možno znatno pohitriti s tem, da ga prilagajamo za

naše ciljno okolje, in s tem, da nižamo natančnost v zameno za hitrost. Hkrati pa se

moramo zavedati teorema NFL (angl. no free lunch) [60], ki v grobem pravi, da če

optimiziramo en vidik algoritma, drugi trpijo. Tako smo za naše pohitritve plačali z

natančnostjo, ki je se je zmanjšala za 18 % z 92 % na 74 %. Hkrati je trpela estetika

prikaza, kjer je bil zaznani pravokotnik vidno manjši in se je počasneje prilagajal

približevanju obraza h kameri in oddaljevanju obraza od kamere. Poslabšalo se je tudi

zaznavanje več obrazov hkrati; še vedno smo lahko zaznavali več kot enega, ampak je

imel algoritem težave pri zaznavanju velikega števila obrazov v eni sliki.

Vprašati se moramo, ali sploh še imamo vse funkcionalnosti, ki jih zahteva naša

aplikacija. Algoritma na primer ne moremo več uporabljati za fotografiranje, ker pri večjih

skupinah ljudi ne bi deloval. Za biometriko ali klasifikacijo izrazov bi potrebovali nadaljnje

prilagoditve algoritma, kot je večanje višine in širine okvirja za 10 %, da bi okvir zajel

celoten obraz in ga podal v nadaljnjo analizo. Za analiziranje množic, na primer pri

marketinških aplikacijah, ki merijo odzive ljudi na izdelek ali oglas, je algoritem

neprimeren.

Pri implementaciji algoritma bi morali torej pretehtati pozitivne in negativne lastnosti

posameznih pohitritev in dobro premisliti, ali je sploh smiselno uporabljati algoritem za

zaznavanje obrazov na prenosni opremi s tako slabo zmogljivostjo.

Za nadaljnje delo bi bilo treba osnovati način za testiranje na vzorcu z več obrazi,

pregledati možnosti prilagoditve algoritma LBP in se poglobiti v učenje kaskade

klasifikatorjev z uporabo evolucije ali metaevolucije, kjer dajemo večji poudarek na hitrost

in manjši poudarek na natančnost algoritma.

Page 60: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

50

Viri

[1] „Android (operating system),“ Dostopno na:

http://en.wikipedia.org/wiki/Android_(operating_system) [12. 9. 2014].

[2] „Which android runs which linux kernel,“ Android Stack Exchange, Dostopno na:

http://android.stackexchange.com/questions/51651/which-android-runs-which-linux-

kernel [12. 9. 2014].

[3] „Android Kernel Versions,“ Elinux, Dostopno na:

http://elinux.org/Android_Kernel_Versions [12. 9. 2014].

[4] „Open Binder,“ Wikipedia, Dostopno na: http://en.wikipedia.org/wiki/OpenBinder [12.

9. 2014].

[5] „Dalvik technical information,“ Android, Dostopno na:

https://source.android.com/devices/tech/dalvik/ [12. 9. 2014].

[6] „Dalvik (software),“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Dalvik_(software) [12. 9. 2014].

[7] „Arm architecture,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/ARM_architecture [12. 9. 2014].

[8] „About ARM holdings,“ ARM holdings, Dostopno na:

http://ir.arm.com/phoenix.zhtml?c=197211&p=irol-homeprofile [12. 9. 2014].

[9] „Prestigio Multipad 7.0 ultra+ specs,“ Prestigio, Dostopno na:

http://www.prestigio.com/catalogue/MultiPads/NEW_MultiPad_7.0_ULTRA_Plus_#/pr

oduct-specs?article=PMP3670B_WH [12. 9. 2014].

[10] „Cortex a8,“ ARM, Dostopno na: http://www.arm.com/products/processors/cortex-

a/cortex-a8.php [12. 9. 2014].

[11] „Java Native Interface,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Java_Native_Interface [12. 9. 2014].

[12] „JDK 6 Java Native Interface,“ Oracle, Dostopno na:

http://docs.oracle.com/javase/6/docs/technotes/guides/jni/ [12. 9. 2014].

[13] „Android NDK,“ Android, Dostopno na:

https://developer.android.com/tools/sdk/ndk/index.html [12. 9. 2014].

[14] „Power PC Embedded ApplicationBinary Interface,“ Freescale, Dostopno na:

http://www.freescale.com/files/32bit/doc/app_note/PPCEABI.pdf [12. 9. 2014].

Page 61: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

51

[15] „Application binary interface,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Application_binary_interface [12. 9. 2014].

[16] „LogCat,“ Android, Dostopno na: http://developer.android.com/tools/help/logcat.html

[12. 9. 2014].

[17] „Cmake,“ Kitware, Dostopno na: http://www.cmake.org/ [15. 9. 2014].

[18] „OpenCV,“ OpenCV, Dostopno na: http://opencv.org/ [13. 9. 2014].

[19] „OpenCV,“ Wikipedia, Dostopno na: http://en.wikipedia.org/wiki/OpenCV [13. 9.

2014].

[20] „BSD licences,“ Wikipedia, Dostopno na: http://en.wikipedia.org/wiki/BSD_licenses

[15. 9. 2014].

[21] „Open CV About,“ Itseez, Dostopno na: http://opencv.org/about.html [15. 9. 2014].

[22] „EmguCV,“ Emgu, Dostopno na: http://www.emgu.com/wiki/index.php/Emgu_CV [15.

9. 2014].

[23] „JavaCV,“ GitHub, Dostopno na: https://github.com/bytedeco/javacv [15. 9. 2014].

[24] „MMX instruction set,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/MMX_%28instruction_set%29 [15. 9. 2014].

[25] „Streaming SIMD Extensions (SSE),“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Streaming_SIMD_Extensions [15. 9. 2014].

[26] „Facedetection Techniques,“ Dostopno na:

http://www.facedetection.com/facedetection/techniques.htm [15. 9. 2014].

[27] „Cascading classifiers,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Cascading_classifiers [15. 9. 2014].

[28] „Viole-Jones object detect framework,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Viola%E2%80%93Jones_object_detection_framework

[15. 9. 2014].

[29] Dalal, N., Triggs, B. „Histograms of Oriented Gradients for Human Detection,“ INRIA

Rhone-Alps, ˆ 655 avenue de l’Europe, Montbonnot 38334, France, 2005 Dostopno

na: http://lear.inrialpes.fr/people/triggs/pubs/Dalal-cvpr05.pdf [15. 9. 2014].

[30] „OpenCV documentation - Cascade Classification,“ Itseez, Dostopno na:

http://docs.opencv.org/modules/objdetect/doc/cascade_classification.htm [15. 9.

2014].

Page 62: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

52

[31] „OpenCV face recognition with Local Binary Patterns Histogram,“ Itseez, Dostopno

na: http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html#local-

binary-patterns-histograms [15. 9. 2014].

[32] „Haar wavelets,“ UCF, Dostopno na: http://www.cs.ucf.edu/~mali/haar/ [16. 9. 2014].

[33] „Haar wavelets Wikipedia,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Haar_wavelet [16. 9. 2014].

[34] „Object Detection Using Haar-like Features,“ Intel, Dostopno na:

https://software.intel.com/sites/products/documentation/hpc/ipp/ippi/ippi_ch14/ch14_o

bject_detection_using_haar_like_features.html [15. 9. 2014].

[35] „Object Detection Using Haar-like features,“ Intel, Dostopno na:

https://software.intel.com/en-us/node/504530 [28. 11. 2014].

[36] Viola, P., Jones, M. „Rapid Object Detection using a Boosted Cascade of Simple

Features,“ Accepted Conference On Computer Vision And Pattern Recognition, 2001

Dostopno na: https://www.cs.cmu.edu/~efros/courses/LBMV07/Papers/viola-cvpr-

01.pdf [16. 9. 2014].

[37] „Face Detection Using Haar cascades OpenCV Documentation,“ Itseez, Dostopno

na:

http://docs.opencv.org/trunk/doc/py_tutorials/py_objdetect/py_face_detection/py_face

_detection.html [28. 11. 2014].

[38] „GentleAdaBoost wiki,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/AdaBoost#Gentle_AdaBoost [16. 9. 2014].

[39] „Integral image,“ Wordpress, Dostopno na:

http://computersciencesource.wordpress.com/2010/09/03/computer-vision-the-

integral-image/ [16. 9. 2014].

[40] „Integral images for block matching,“ Ipol, Dostopno na:

http://www.ipol.im/pub/pre/57/preprint.pdf [16. 9. 2014].

[41] „Summed Area Table,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Summed_area_table [9. 12. 2014].

[42] „Gradient wikipedija,“ Wikipedia, Dostopno na: http://en.wikipedia.org/wiki/Gradient

[18. 9. 2014].

[43] „Histogram of Oriented Gradients,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Histogram_of_oriented_gradients [15. 9. 2014].

[44] Yu-Jin Zhang, Hui-Xing Jia, „Fast Human Detection by Boosting Histograms of

Oriented Gradients,“ Fourth International Conference on Image and Graphics, (2007),

Page 63: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

53

str. 1–6.

[45] Deniz, O., Bueno, G., Salido, J., De la Torre, F. „Face recognition using Histograms

of Oriented Gradients,“ Pattern Recognition Letters, 32, (2011), str. 1–6.

[46] Dalal, N., Triggs, B. „Histograms of Oriented Gradients for Human Detection,“ INRIA

Rhone-Alps, ˆ 655 avenue de l’Europe, Montbonnot 38334, France, 2005 Dostopno

na: http://lear.inrialpes.fr/people/triggs/pubs/Dalal-cvpr05.pdf [18. 9. 2014].

[47] „HOG with ofxCv,“ Flickr, Dostopno na:

https://www.flickr.com/photos/unavoidablegrain/8123343395/ [28. 11. 2014].

[48] „Local Binary Patterns,“ Scholarpedia, Dostopno na:

http://www.scholarpedia.org/article/Local_Binary_Patterns [24. 9. 2014].

[49] „Local Binary Patterns Wikipedia,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/Local_binary_patterns [28. 11. 2014].

[50] „Face Recognition with OpenCV,“ Itseez, Dostopno na:

http://docs.opencv.org/modules/contrib/doc/facerec/facerec_tutorial.html#local-

binary-patterns-histograms [24. 9. 2014].

[51] Bangyou, D., Nong, S. „SPIE Optical Engineering Local binary pattern based face

recognition by estimation of facial distinctive information distribution,“ SPIE 2009,

Dostopno na:

http://opticalengineering.spiedigitallibrary.org/article.aspx?articleid=1089401 [28. 11.

2014].

[52] „Understanding OpenCV LBP implementation,“ Stack Overflow, Dostopno na:

http://stackoverflow.com/questions/22565531/understanding-opencv-lbp-

implementation [30. 9. 2014].

[53] „ALgorithm - Understanding OpenCV LBP Implementation,“ StackOverflow, Dostopno

na: http://stackoverflow.com/questions/22565531/understanding-opencv-lbp-

implementation [6. 10. 2014].

[54] „CascadeClassifier documentation: GroupRectangles,“ Itseez, Dostopno na:

http://docs.opencv.org/modules/objdetect/doc/cascade_classification.html#grouprecta

ngles [9. 10. 2014].

[55] „OpenCV VideoCapture documentation,“ Itseez, Dostopno na:

http://docs.opencv.org/java/org/opencv/highgui/VideoCapture.html [15. 10. 2014].

[56] „Android Media Metadata Retriever documentation,“ Itseez, Dostopno na:

http://developer.android.com/reference/android/media/MediaMetadataRetriever.html

[15. 10. 2014].

Page 64: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

54

[57] „Android Media Extractor documentation,“ Itseez, Dostopno na:

http://developer.android.com/reference/android/media/MediaExtractor.html [15. 10.

2014].

[58] „FFMPEG Media Metadata Retriever,“ GitHub, Dostopno na:

https://github.com/wseemann/FFmpegMediaMetadataRetriever [15. 10. 2014].

[59] „What the average human face looks like in every country,“ Dostopno na:

http://nedhardy.com/2014/05/30/average-human-face-looks-like-every-country/ [15.

10. 2014].

[60] „No Free Lunch Theorem,“ Wikipedia, Dostopno na:

http://en.wikipedia.org/wiki/No_free_lunch_theorem [17. 10. 2014].

[61] „Face Recognition with Local Binary Patterns, Spatial Pyramid Histograms and Naive

Bayes Nearest Neighbor classification,“ Asoto, Dostopno na:

http://asoto.ing.puc.cl/papers/Maturana-09.pdf [24. 10. 2014].

[62] Yann, R. „Face Detection and Verification using Local Binary Patterns,“ Á La Faculté

Des Sciences Et Techniques De L’ingénieur, 2006, Dostopno na:

http://infoscience.epfl.ch/record/146275/files/rodrig-idiap-rr-06-79.pdf [24. 9. 2014].

[63] „Videocapture From File Always Returns null,“ StackOverflow, Dostopno na:

http://answers.opencv.org/question/30146/android-videocapture-from-video-file-

always-return/ [15. 10. 2014].

[64] „Image Processing And Computer Vision Group,“ Dostopno na: http://www-

2.dc.uba.ar/grupinv/imagenes/objectdetection.php [28. 11. 2014].

Page 65: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

55

Page 66: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

56

Page 67: operacijskem sistemu Android · 2017-11-28 · Android NDK je zbirka orodij in algoritmov, ki uporablja JNI [11] [12], da omogoča izvajanje C++ kode na operacijskem sistemu Android

57