Professionele Bachelor Toegepaste Informatica Applicatieontwikkeling
Virtuele Revalidatie met Microsoft Kinect PXL IT-Research Simon Verbeke
Promotoren: Marijke Willems Steven Palmaers Lode Vanhout
Hogeschool PXL PXL IT-Research PXL IT-Research
Stagerapport Academiejaar 2014 - 2015
Professionele Bachelor Toegepaste Informatica Applicatieontwikkeling
Virtuele Revalidatie met Microsoft Kinect PXL IT-Research Simon Verbeke
Promotoren: Marijke Willems Steven Palmaers Lode Vanhout
Hogeschool PXL PXL IT-Research PXL IT-Research
Stagerapport Academiejaar 2014 - 2015
Voorwoord
Bij deze wil ik mijn promotor, Steven Palmaers, bedanken voor de uitzonderlijke kans mij te verdiepen in de academische wereld. Voor de toegang tot interessante nieuwe technologieën. En voor zelfs midden in de nacht nog vragen te beantwoorden of documenten na te kijken. Daarnaast mijn mentoren, Frederik Smolders en Lode Van Hout, voor de ondersteuning en het vertrouwen in mijn oordeel. Marijke Willems, mijn hogeschoolpromotor, voor de onmisbare feedback; de andere kijk op dingen. Tenslotte mijn collega-stagiairs voor de snedige humor, de diepgaande gesprekken en de hechte band. En in het bijzonder Tom Quareme voor de wiskundige ondersteuning.
Inhoudsopgave
Voorwoord
Abstract
1 Bedrijfsvoorstelling
1
2 Onderzoeksthema
3
3 Technologieën
5
3.1
Microsoft Kinect . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
5
3.2
Unity3D . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
7
3.3
Mono . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
8
3.4
Git . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
9
4 Stageopdracht
11
5 Onderzoeksfinanciering in België
13
5.1
IWT . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 13
5.2
FWO . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 14
6 Onderzoeksthema: filters
15
6.1
Geïmplementeerde filters . . . . . . . . . . . . . . . . . . . . . . . . . . . . 17
6.2
Niet-geïmplementeerde filters . . . . . . . . . . . . . . . . . . . . . . . . . 20
7 Dataflow applicatie
23
7.1
Body . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 23
7.2
Audio . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
7.3
Color . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 25
8 Oefeningen vergelijken
27
8.1
Het bestandsformaat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 27
8.2
Posities vergelijken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 28
8.3
Rotaties vergelijken . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8.4
Eindresultaat . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 29
8.5
Visualisaties . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 30
9 Audio
33
9.1
De data . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 33
9.2
Opnemen . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 34
10 Video
37
11 Stemherkenning
39
12 Besluit
41
13 Reflectie
43
Bibliografie
43
Abstract
Mijn stageproject is gelinkt aan een onderzoeksproject dat wordt uitgevoerd door Healthcare-Research en IT-Research, namelijk “een Open Intelligent RevalidatieFramework” (kortweg OpenIRF). Binnen dit onderzoeksproject is er enorme interesse voor tools die het werk van healthcare professionals kan vereenvoudigen. Er wordt onderzocht hoe software kan helpen bij de revalidatie na, bijvoorbeeld, een auto-ongeluk, bij MS, of na een beroerte. In de huidige situatie moet een cliënt altijd vergezeld worden van een therapeut, omdat deze persoon de enige is die de kwaliteit van de oefening kan vaststellen. Bovendien is revalidatie vaak generiek, met geen of te weinig focus op datgene dat de cliënt wenst te trainen. Met de tool die in dit project ontwikkeld wordt, zal het mogelijk worden cliënten deels zelfstandig te laten revalideren. Het te ontwikkelen systeem zal bestaan uit twee grote modules, gemaakt aan de hand van Unity 3D met de programmeertaal C#. De eerste module wordt gebruikt door de therapeut om oefeningen aan te maken (op te nemen) voor de cliënt. Hierbij bestaat de mogelijkheid om een aantal parameters in te stellen voor de oefening. Bijvoorbeeld: voor een oefening moet een cliënt zijn arm bewegen. Maar eigenlijk is het alleen belangrijk dat de cliënt de rug recht houdt. De tweede module wordt gebruikt door de cliënt. Deze kan oefeningen inladen die de therapeut heeft opgenomen, de oefening uitvoeren en feedback krijgen (in real-time of na afloop). Het project bestaat uit een aantal fases. In deze fases moeten problemen voorkomen worden met de data die de Kinect beschikbaar stelt. Er wordt gewerkt met een relatief goedkope camera, bedoeld voor het spelen van computergames, waardoor de kwaliteit van de data niet optimaal is. Het eerste probleem is de ruis en de uitschieters op de data. Het ontwikkelen van een goede set filters is belangrijk om de data bruikbaar te maken voor de rest van het systeem. Op dit moment zijn er een viertal filters ontwikkeld. Deze filters kunnen apart gebruikt worden of gemengd worden met elkaar. Het is ook eenvoudig om nieuwe filters toe te voegen door een mathematisch model om te zetten naar een script.
De tweede fase bestaat uit het ontwikkelen van het systeem dat oefeningen aanbiedt aan een cliënt en het analyseren van de bewegingen van de cliënt. Om vervolgens hier een score aan toe te kennen. Hier zijn verschillende benaderingen mogelijk die zullen geanalyseerd en uitgewerkt worden Een naïeve benadering is het vergelijken van de posities van de ledematen van de cliënt en de therapeut. Een andere benadering is een bepaalde foutenmarge toelaten. Tenslotte moet er ook de nodige aandacht worden besteed aan gebruiksvriendelijkheid en User Experience (UX). Het systeem gaat gebruikt worden door mensen met een fysieke beperking, en moet bijgevolg uitermate gemakkelijk te bedienen zijn. Om deze reden onderzoeken we ook of we een spraakbesturingssysteem kunnen integreren.
1. Bedrijfsvoorstelling
PXL-Research bundelt het onderzoek en de dienstverlening binnen Hogeschool PXL, en functioneert als centraal aanspreekpunt voor ondernemers, bedrijven en organisaties die op zoek zijn naar specifieke onderzoeksexpertise om innovatie te realiseren. PXL-Research is de springplank om specifieke vragen, ideeën en businessprojecten te vertalen naar concrete projecten met studenten, docenten/lectoren, onderzoekers, partnerbedrijven, subsidiëringsinstanties, enz. Via PXL-Research kan men beroep doen op de knowhow en ervaring in de expertisecellen die Hogeschool PXL heeft uitgebouwd op terreinen zoals toegepaste informatica, elektronica, elektromechanica, bouw, logistiek, marketing, media, toerisme, sociaal agogisch werk, gezondheidszorg, voedselveiligheid, beeldende kunst, grafisch ontwerp, ... IT-Research is de expertisecel die focust op de boeiende wereld van (mobiele) applicaties, 3D op het web, ontwikkeling van games en mechatronica. IT-Research werkt sterk multidisciplinair in diverse domeinen. Enkele voorbeelden hiervan zijn de zorgsector, de logistieke en de educatieve sector.
1
2. Onderzoeksthema
Binnen mijn stage heb ik meerdere onderzoeksthema’s behandeld. In dit eindwerk bespreek ik het onderzoeksthema "filters". Met de specifieke vraag: kan de data van de Microsoft Kinect gefilterd worden zodat gebruikers weinig of geen last hebben van ruis en jitter? De methodes die beschreven worden in dat hoofdstuk zijn zo opgesteld dat de methodes ook bruikbaar zijn met andere apparaten. Deze techniek is essentieel om bruikbare data te verkrijgen van de Kinect. In de eerste versie was dit zelfs ingebouwd in de API. Om een nog onbekende reden is deze functionaliteit niet meer beschikbaar in de tweede versie. Dit was een goede opportuniteit om me te kunnen verdiepen in een vakgebied binnen de wiskunde dat erg veel praktische toepassingen heeft. Elk apparaat dat data verkrijgt op basis van fysieke metingen zal last hebben van inaccurate data die gefilterd moet worden. Dit is des te meer van toepassing op goedkope elektronica gericht op de consumentenmarkt.
3
3. Technologieën
3.1
Microsoft Kinect
Het belangrijkste stuk technologie binnen het project is de Microsoft Kinect. Dit is een camerasysteem dat origineel ontwikkeld is als metgezel van de Microsoft Xbox, om games mee te spelen. Sinds het begin wordt het ook ingezet in allerlei projecten die eigenlijk niets met games te maken hebben. In 2014 werd de tweede generatie Kinect camera’s gelanceerd, met veel verbeteringen ten opzichte van de eerste generatie. De specificaties zijn als volgt:
Kleurencamera: 1920 x 1080, 30 fps Infraroodcamera: 512 x 424, 30 fps Waarnemingsafstand: 0.5 m - 4.5 m Gewrichten per skelet: 25 gewrichten Gevolgde skeletten: 6 skeletten Aantal microfoons: 4 microfoons
Deze hardware wordt gebruikt om via een API verschillende datastreams beschikbaar te stellen aan programmeurs: Nota: tenzij anders vermeld, werken de streams aan 30 frames per seconde Color stream Dit is de stream van de kleurencamera. Deze levert een byte-array met daarin een full HD afbeelding. Omdat de video stream beschikbaar wordt gesteld als afzonderlijke afbeeldingen, neemt het erg veel geheugen in beslag. Een full-HD afbeelding in 24-bit RGB is 6MB groot. Dat is bijna 180MB per seconde. 5
Infrared stream Dit is de ruwe data van de IR camera. Het wordt voorgesteld met een grayscale afbeelding van IR data. Depth stream Deze stream bevat bewerkte data van de IR camera. Dit is een byte-array die voor elke pixel de afstand tot de camera weergeeft. Body stream Deze stream bevat bewerkte data van de IR camera. Het is een lijst van alle lichamen die de Kinect op dat moment herkent. Per lichaam zijn er 25 gewrichten, die elk een positie, een rotatie en een trackingstatus hebben. Bovendien is er ook data beschikbaar over de handstate. Dit dient om aan te geven of de hand open of gesloten is. Dit is voor onze applicatie de belangrijkste stream. Body Index stream Dit is bewerkte data van de IR camera. Deze stream bevat een afbeelding die de herkende lichamen allemaal in een aparte kleur invult. Audio stream Deze stream bevat 60 keer per seconde een byte-array met ruwe audio. De data bevat 256 samples in 32-bit float PCM met een samplerate van 16 kHz. Er zijn nog een aantal streams in andere delen van de API. Hier ben ik niet mee in contact gekomen. Deze streams zijn een interface voor Face Tracking, Gestures, Fusion en Voice Recognition. Face Tracking laat toe om verschillende features te herkennen in het gezicht. Hier kan een gemoedstoestand uit worden afgeleid. Gestures is een manier om bewegingen van een gebruiker te herkennen als een gebaar. Bijvoorbeeld een zwaaiende hand. Om gestures te herkennen moet er een machinelearning-algoritme getraind worden met video’s waarin het gesture voor komt. Fusion is een systeem dat toe laat om een 3D-voxel model op te bouwen van de scene die de Kienct ziet. Voice Recognition zit standaard in Windows, maar er is een aangepaste versie van beschikbaar die is afgestemd op de Kinect. Dit laat toe om stemherkenning in real time te doen.
6
3.2
Unity3D
Unity3D is een game-engine, ontwikkeld door Unity Technologies. Het is een engine gericht op indie studio’s. Ondertussen is de vijfde versie al op de markt, waarin ze beslist hebben een groot aantal betalende features gratis te maken. Een aantal opmerkelijke features van de engine zijn:
• Cross-platform met 21 ondersteunde platformen. Waaronder: – Windows – Linux – Mac – Web plug in – WebGL – Playstation – Xbox – ... • Physically Based Shading. • Real-time Global Illumination. • Een geïntegreerde editor. • Scripting in C# en Javascript. • Een uitgebreid animatieframework. • Box2D en NVIDIA PhysX voor game physics.
Door de uitgebreide mogelijkheden wordt Unity niet langer gebruikt voor enkel games. Architectuur, healtchare en militaire training zijn een aantal vakgebieden waar Unity ook gebruikt wordt. Door de flexibiliteit van Unity hebben ook wij gekozen om de engine te gebruiken. Interessant aan Unity en andere game-engines is het programmeermodel. In een standaard GUI programma wordt code alleen uitgevoerd bij het opstarten en als reactie op een event (hier zijn natuurlijk uitzonderingen op). Binnen Unity werkt men echter met een 7
gameloop. Er is intern een stuk code dat in essentie neerkomt op een eeuwige whileloop. Hierin worden entities geüpdatet en vervolgens gerenderd. Een entity is een object in de spelwereld. Voor de samenstelling van een entity wordt het Entity-Componentmodel gebruikt. Dit is een antwoord op de complexiteit van het traditionele model van overerving. Een entity beschikt over de mogelijkheid om componenten toe te voegen aan zichzelf. Dit kan gaan over een mesh (het 3D-model), een script (code die wordt uitgevoerd door de entity), een Transform (de positie, rotatie en schaling van een entity) en nog veel meer. Unity heeft ook een ingebouwde world editor. Hier kunnen artiesten en level designers de werelden ontwerpen. Dit gebeurt door een terrein aan te maken, dit is een mesh. Daarna kunnen niet interactieve objecten worden toegevoegd. Bijvoorbeeld een aantal huizen in een dorpje die dienen als decoratie maar eigenlijk geen functie hebben. Vervolgens worden interactieve objecten toegevoegd. Dit zijn entities met scripts. Dit kan gaan van spelers, tot vijanden, tot deuren die open en dicht gaan. Een nadeel aan Unity, ten opzichte van andere populaire engines zoals Unreal Engine, is dat de code van de engine niet beschikbaar is voor developers (of ze moeten veel geld betalen). In Unreal Engine kan je er wel aan, en wordt het mogelijk de engine zelf aan te passen. Dit is vooral nodig als je een type game wilt maken waarvoor de engine niet geoptimaliseerd is. Ook wordt het mogelijk om bijvoorbeeld interacties met het internet op een veel lager niveau te implementeren. Dit is handig als je een Massively Mutiplayer Online Game (MMOG) wilt maken. Omdat een MMOG altijd online is en hoge performantie nodig heeft voor het grote aantal spelers dat tegelijk moet kunnen spelen, kunnen er bepaalde assumpties worden gemaakt. Deze assumpties leiden dan tot bepaalde beperkingen in features (altijd online zijn in dit geval) die het gemakkelijker maken het spel te optimaliseren. Een andere use case voor het aanpassen van de engine is voor het optimaliseren van code die in het spel intensief wordt gebruikt. Het is mogelijk dat je een vrij obscure feature (bijvoorbeeld renderen naar een RenderTexture) veel gebruikt. Maar omdat deze feature obscuur is, is deze slecht geoptimaliseerd door de programmeurs van de engine.
3.3
Mono
Mono is een open-source alternatief voor het .NET Framework en de Common Language Runtime. Door het open-source karakter van het project hebben ze het mogelijk gemaakt .NET code te schrijven voor zowel Windows, Linux als Mac OS X. Ze bieden hun eigen 8
versie aan van de compiler, de Common Language Runtime en de standard library van .NET. Hoewel de mogelijkheden van Mono erg interessant zijn, wordt er binnen Unity nog een oude versie gebruikt. Er is toegang tot het equivalent van .NET 3.5. Daardoor mist Unity ondersteuning voor constructies als async (het asynchroon uitvoeren van code. De eerste thread kan dan verder code uitvoeren totdat we met await het resultaat van de andere thread gaan opvragen). Ook delen van de standard library die later zijn toegevoegd missen in deze versie van Mono, zoals bijvoorbeeld Tuple
. Externe libraries die gecompileerd zijn voor .NET 4 en hoger zijn ook niet bruikbaar binnen Unity. Unity is van plan over te schakelen op een eigen compiler, IL2Cpp, die Intermediate Language (gecompileerde .NET) kan omzetten naar C++ code om dit dan te compileren met een C++ compiler. Ze zullen dus niet meer afhangen van Mono om cross-platform support te leveren. Sinds het .NET framework open source is geworden, is de Mono Foundation gestart met het vervangen van hun code. Bepaalde delen stemmen nu dus volledig overeen met de referentie-implementatie van Microsoft. Onder andere de RegularExpressions-, Linq-, Threading- en Xml-namespaces zijn al gemigreerd.
3.4
Git
Git is een distributed version control system (DVCS). Distributed betekent dat het niet het traditionele client-server model gebruikt, waar de server de plaats is waar de “echte” toestand van de code te vinden is. Bij git is elke client zowel client als server; de code bij de client is de “echte” toestand voor die client. Code kan ook uitgewisseld worden tussen verschillende clients, zonder dat er een centrale server aan te pas komt. Omdat het een distributed model gebruikt blijft code beschikbaar bij andere clients wanneer een client offline gaat. Version control system slaat op een systeem dat door middel van commits een geschiedenis opbouwt van de code. Een commit is een eenheid van werk die een logisch geheel vormt. Wanneer men een commit aanmaakt zegt men “ik heb nu dit deel afgemaakt, en dit is de code die erbij hoort”. Git maakt ook gebruik van branching. Hierbij kan men een commit aanduiden en zeggen “vanaf hier start ik een nieuwe geschiedenis”. Dit maakt het mogelijk om aan een stuk code te werken, zonder dat dit terecht komt in andere branches en het werk van developers 9
daar verstoort. Op het moment dat de branch afgewerkt is kan het gemerged worden in een andere branch. Dit kan op meerdere manieren gebeuren, maar komt altijd neer op het afspelen van de veranderingen in de ene branch op de andere branch. Tijdens dit proces kan men conflicts tegen komen. Dat betekent dat er in twee commits hetzelfde stuk code is aangepast. Er is dan de mogelijkheid om te kiezen welke (stukken van de) commits de juiste zijn.
10
4. Stageopdracht
Het stageproject is gelinkt aan een onderzoeksproject van Healthcare-Research en ITResearch, namelijk een “Open Intelligent Framework” (kortweg OpenIRF). Er is binnen dit project een grote interesse voor tools die het werk van Healthcare professionals kan versimpelen. Er wordt onderzocht hoe software kan helpen bij de revalidatie na, bijvoorbeeld, een auto-ongeluk, bij ziektes zoals Multiple Sclerosis, of na een beroerte. Momenteel moeten patiënt en therapeut altijd fysiek samen werken om oefeningen uit te voeren, omdat de therapeut de enige persoon is die de kwaliteit van een oefening kan opmeten. Bovendien is er vaak te weinig focus op de specifieke noden van een patiënt. De oefeningen zijn vaak erg generiek. Met de tool die we nu ontwikkelen zal het mogelijk worden voor patiënten om (deels) zelfstandig te revalideren. Een andere stagiair, Tom Quareme, heeft ook binnen het OpenIRF project gewerkt. Hij heeft onderzoek gedaan naar kleine sensoren die via bluetooth te verbinden zijn met de PC. Deze sensoren hebben accelerometers en gyroscopen waardoor ze gebruikt kunnen worden om bewegingen te herkennen. Dit gaat vooral gebruikt worden voor situaties waar de Kinect niet goed mee overweg kan. Een voorbeeld is een oefening die vaak gebruikt wordt als revalidatie: het bewegen van een koffiekop. De sensor zou dan in een koffiekop bevestigd kunnen worden om zo de beweging van de patiënt te analyseren.
11
5. Onderzoeksfinanciering in België
Omdat OpenIRF een TETRA-project is, is het wel gepast om de belangrijkste financieringsmethodes voor onderzoek in België aan te halen. Onderzoeksprojecten binnen de IT krijgen waarschijnlijk te maken met het IWT of met het FWO. Het IWT focust op toegepast onderzoek en het FWO op fundamenteel onderzoek
5.1
IWT
Het IWT, het agentschap voor Innovatie door Wetenschap en Techniek, is een overheidsagentschap dat elk jaar ongeveer 300 miljoen euro verdeelt aan subsidies voor zowel bedrijven als hogescholen en universiteiten. Naast financiële steun levert het IWT ook advies aan onderzoeksprojecten. OpenIRF is een TETRA-project, en krijgt dus steun van het IWT. TETRA ondersteunt praktijkgericht onderzoek door hogescholen en universiteiten voor ondernemingen. Het doel van TETRA is het ondersteunen van onderzoek dat bijdraagt aan maatschappelijke uitdagingen zoals duurzame mobiliteit, duurzame energie, zorginnovatie, ... De onderwijsinstelling die het onderzoek uitvoert binnen een TETRA-project moet de vergaarde kennis over de technologie op een begrijpelijke wijze overdragen aan de leden van de “gebruikersgroep”. Dit is de groep van bedrijven die het project cofinancieren. Om steun te krijgen als TETRA project moet er ook aan een paar voorwaarden worden voldaan:
• De begroting bedraagt minimaal 100.000 en maximaal 480.000 euro. • Het project heeft een looptijd van 2 jaar. 13
• Voor projecten van onderzoeksgroepen van professionele bacheloropleidingen is het mogelijk om een voorbereidingsproject van één jaar in te dienen. • De steun voor de projecten bedraagt maximaal 92.5%. Ondernemingen uit de doelgroep financieren voor 7.5% • Indien het project binnen het CONERT project past is een verlenging tot drie jaar mogelijk. Indien dat nodig is voor coördinatie met buitenlandse partners
5.2
FWO
Het FWO focust zich op fundamenteel onderzoek. Dit is onderzoek dat niet noodzakelijk een rechtstreekse praktische toepassing heeft. Denk bijvoorbeeld aan theoretische fysica en theoretische wiskunde. Omdat ons project geen fundamenteel onderzoek is kunnen we dus ook geen beroep doen op het FWO. Voor andere projecten in het verleden heeft IT Research wel al op steun kunnen rekenen van het FWO. In de tijd dat het FWO nog het NFWO was, heeft het 4 nobelprijswinnaars afgeleverd. Drie maal voor de geneeskunde en één maal voor de scheikunde.
14
6. Onderzoeksthema: filters
De Microsoft Kinect is een goedkope camera. Bijgevolg is de data die hij genereert niet heel accuraat: het bevat veel uitschieters en jitter. Uitschieters krijg je wanneer de Kinect denkt dat een lichaamsdeel ergens anders is dan waar het eigenlijk is. Jitter is een kleine, willekeurige afwijking die zich zeer kort bij de echte waarde bevindt. Typisch aan jitter is dat de afwijking steeds varieert. y
y
fysiek
fysiek
gemeten
gemeten
x Jitter
x Uitschieters
Figuur 6.1: Een illustratie van jitter en uitschieters
Beide problemen kunnen voorkomen worden met filters die de data analyseren en bewerken. Op dit moment zijn er vier filters geïmplementeerd. Drie hiervan zijn gebaseerd op een maximale delta (waar we met delta het verschil in afstand tussen twee tijdseenheden bedoelen) per frame. De vierde is gebaseerd op het Exponential Moving Average (Holt, 2004). Er zijn nog een aantal bruikbare filters die niet zijn geïmplementeerd. Dit om verscheidene redenen: sommige methodes zijn te complex, voor anderen was er geen tijd, enz. Deze worden besproken in sectie 6.2. Het is echter wel makkelijk genoeg een nieuwe filter toe te voegen, er moet alleen iemand het wiskundige model omzetten naar code. Nota: In de beschrijvingen van de filters wordt er gerefereerd naar vectoren. Dit slaat op zowel positievectoren (3 dimensies) als rotatievectoren (4 dimensies, ook wel Quaternions genoemd). Wanneer er verschillen zijn in de methode tussen 3 en 4 dimensies, dan wordt 15
dit expliciet vermeld. Wanneer een filter bedacht wordt, zijn er een aantal gevolgen waar rekening mee moet worden gehouden. Deze gevolgen kunnen we groeperen onder vertraging en afvlakking. De meeste filters zullen data van één of meer vorige frames analyseren en op basis hiervan de data van het nieuwe frame aanpassen. Hierdoor heeft de bewerkte data een vertraging ten opzichte van de originele data: origineel gefilterd
y
x
Figuur 6.2: Een voorbeeld van vertraging
Deze vertraging is inherent, maar kan gelimiteerd worden zodat een gebruiker het niet merkt. De maximale vertraging die een gebruiker niet opmerkt – zoals beschreven in The psychology of human-computer interaction (Card, Moran, Newell e.a., 1981) – bedraagt 100ms. Wanneer we spreken over afvlakking (of zelfs versterking bij voorspellende modellen) dan bedoelen we dat de gefilterde data niet dezelfde minima en maxima behaalt als de ruwe data: origineel gefilterd
y
x
Figuur 6.3: Een voorbeeld van afvlakking
Het is belangrijk om ervoor te zorgen dat het verschil met de originele data niet te groot wordt. Wanneer dit wel gebeurt is het zeer desoriënterend voor de gebruiker. 16
6.1 6.1.1
Geïmplementeerde filters Maximale delta
Het principe van een filter gebaseerd op een maximale delta per frame (vanaf hier MaxDelta) is het limiteren van de afstand (∆) waarmee een variabele mag veranderen per tijdseenheid tot ∆max . Op dit principe zijn drie filters gebaseerd.
MaxDelta filter
In de MaxDelta filter gebruiken we steeds het vorige frame om het huidige frame mee te vergelijken. Voor posities en rotaties berekenen we dan de richting van de vector die zich vormt tussen de twee frames en limiteren de afstand van die vector tot ∆max :
∆ = v1 − v0 v = min(k∆k, ∆max )
∆ k∆k
Waar: v0 is de vector van het vorige frame v1 is de vector van het huidige frame
Deze filter is goed geschikt voor het opvangen van uitschieters. Deze kunnen een delta hebben van meerdere malen ∆max . Een uitschieter moet dan al meerdere frames na elkaar worden geregistreerd voor de gefilterde data de uitschieter bereikt. Jitter wordt hier niet mee gefilterd.
MaxDeltaRatio filter
Dit is een uitbreiding op MaxDelta. Bovenop de berekening die daar beschreven wordt gaan we delta’s kleiner dan ∆max limiteren tot een bepaald ratio van de delta. Bijvoorbeeld: ∆max = 5cm, ratio = 10%. Een delta van 3 cm wordt dan gelimiteerd tot 0.3cm. 17
Het nut van ratio is – naast de uitschieters die MaxDelta opvangt – het opvangen van jitter. Jitter gaat natuurlijk nooit helemaal weg, omdat we niet kunnen weten wat de correcte waarde van de variabele hoort te zijn. Maar de ratio die we instellen reduceert de delta van een jitter tot een bepaald percentage van de originele delta.
MaxDeltaMultiplier filter
Deze filter is ook een uitbreiding op MaxDelta. In plaats van één enkele ∆max te hebben voor alle variabelen, krijgt elk gewricht een eigen ∆max . Het is eventueel ook mogelijk ratio hier aan toe te voegen, maar dit is voor het project niet gedaan. De verschillende ∆max per variabele kunnen gebruikt worden omdat bepaalde gewrichten inherent een andere maximumsnelheid hebben. Met een enkele ∆max kan dit niet opgevangen worden.
6.1.2
Exponential Moving Average filter
Exponential Moving Average (EMA) is een filter die vooral in de financiële wereld wordt gebruikt om trends van aandelen te voorspellen. Het heeft echter ook al zijn nut bewezen in filteren van data. De filter houdt een geschiedenis bij van de x laatste waarden van een variabele. Hier wordt een gewogen gemiddelde van genomen, waarbij oude data een lager gewicht heeft dan nieuwe data. Dit gedrag kan men beschrijven met de vergelijking:
EMA(v1 ) = v1 , EMA(vn ) = αvn + (1 − α) · EMA(vn − 1)
Waar:
v is lijst van vectoren n is huidige index α is het gewicht 18
Nota: Deze methode is niet correct voor het filteren van de quaternions die gebruikt worden voor rotaties. Refereer hiervoor naar vergelijking 12 en 13 in Quaternion Averaging (Markley, Cheng, Crassidis & Oshman, 2007). Ze definiëren het gewogen gemiddelde van n quaternions qi met gewichten wi als:
¯ = argmax qT M q q M,
q∈S3 n X
wi qi qiT
i=1
6.1.3
Analyse
MaxDelta
MaxDelta werkt verrassend goed, ondanks dat het algoritme heel erg simpel is. Met een ∆max van 2cm per frame (60cm per seconde) worden er genoeg uitschieters opgevangen, zonder teveel vertraging te creëren. Ook op rotaties werkt dit goed, met een ∆max van 5°. Wat wel opvalt is dat filtering op rotaties minder goed werkt dan op posities. De hypothese is dat dit komt omdat rotatiedata meer ruis en uitschieters bevat dan positiedata. Dit is waarschijnlijk omdat de data veel moeilijker accuraat te berekenen is. Helaas zijn de interne details van de Kinect API niet bekend voor developers, wat het onmogelijk maakt om te bepalen waarom deze data minder accuraat is. Wanneer we de gewone MaxDelta filter gebruiken valt het op dat er veel ruis is wanneer de persoon heel traag beweegt. Dit is niet onverwacht, en wordt opgelost door de MaxDeltaRatio filter te gebruiken.
Exponential Moving Average
Door de voorgenoemde inaccuraatheid van rotatiedata werkt EMA niet zo goed op rotaties. Het systeem geraakt soms verward, wanneer het de richting van de interpolatie wilt bepalen. Dan zie je dat een gewricht ineens een volledige draai maakt in de omgekeerde richting. 19
Voor posities werkt EMA wel zeer goed. Met een geschiedenis van 10 frames en een α van 0.2 wordt er een goede middenweg gevonden tussen accuraatheid en vertraging. Hoe groter de geschiedenis, hoe meer vertraging, maar hoe meer accuraat het resultaat.
6.2
Niet-geïmplementeerde filters
Refereer hiervoor naar het paper Skeletal Joint Smoothing (Azimi, 2014) van Microsoft. Hier zijn nog een aantal interessante methodes te vinden om de data mee te filteren. Twee filters uit dat paper worden hier toegelicht. Deze zijn niet geïmplementeerd vanwege een gebrek aan wiskundige achtergrond die nodig is voor deze materie.
6.2.1
Double Exponential Moving Average
Deze filter is een uitbreiding op EMA. Het past een tweede functie toe op de data die EMA genereert en probeert zo rekening te houden met een bepaalde trend in de data. Er zijn meerdere versies van de filter, die allemaal kleine verschillen tonen ten opzichte van elkaar. Een versie:
s1 = v1 b1 = v1 − v0
sn = αvn + (1 − α)(sn−1 + bn−1 ) bn = β(sn − sn−1 ) + (1 − β)bt−1
Waar: st is de gefilterde data v is lijst van vectoren n is huidige index α is de data smoothing factor β is de trend smoothing factor 20
Het voordeel van deze filter is dat ze sneller reageert op een nieuwe trend dan EMA. Een nadeel is dat ze sneller last heeft van overshoot: wanneer de filter een hoger maximum weergeeft dan de ruwe data.
6.2.2
Savitzky-Golay Smoothing filter
Een Savitzky-Golay Smoothing filter neemt een aantal waardes uit het verleden en zoekt een polynoom die door al deze waardes gaat. Deze polynoom minimaliseert de leastsquares fout in de gefilterde data.
21
7. Dataflow applicatie
Hoewel het voor een groot deel irrelevant is buiten de applicatie, is het toch belangrijk een schets te geven van de dataflow die in deze applicatie is toegepast. Het is in geen enkele manier indicatief voor hoe het probleem moet worden aangepakt in andere applicaties. Daarnaast is deze applicatie ook een prototype voor de software die uiteindelijk door andere leden van IT-Research wordt geprogrammeerd, en is het dus ook niet indicatief voor de dataflow tijdens het eindstadium van dit project. De verschillende secties behandelen stukken van de dataflow die gebaseerd zijn op data van een bepaalde Kinect data-stream. Op veel plaatsen is geopteerd voor een model dat wat lijkt op het Blackboard pattern. In het blackboard pattern schrijven alle subsystemen data weg naar een centraal subsysteem dat deze data beheert. De subsystemen kunnen zo aan data die niet in hun subsysteem wordt gegenereerd, om deze dan te analyseren en verwerken. Dit is vooral handig als de systemen erg verweven zijn, maar toch apart moeten kunnen opereren. Dit blackboard continu up-to-date houden met de juiste velden is wat omslachtig binnen deze applicatie. Daarom fungeert elke entity als een blackboard. Ze stellen data publiekelijk beschikbaar die door andere entities gebruikt zou kunnen worden. Andere entities verkrijgen referenties naar de data die ze nodig hebben, en kunnen zo altijd up-to-date data gebruiken. Op deze manier voorkomen we de complexiteit die ontstaat wanneer elke entity moet bijhouden welke andere entities zijn data nodig hebben.
7.1
Body
Het belangrijkste gedeelte van de applicatie is het verwerken en interpreteren van de body stream. Deze data wordt gebruikt om een 3D-model te renderen dat de bewegingen van de gebruiker toont. De data moet gefilterd worden alvorens deze te tonen aan de gebruiker. Er is daarnaast ook functionaliteit om body-data op te nemen en af te spelen. Tenslotte is er de mogelijkheid live-data te vergelijken met opgenomen data. 23
KinectManager vraagt frames op van de Body stream of, wanneer een opname wordt ingeladen, van een FakeKinect. Dit frame wordt omgevormd naar een generiek frame, want het frame dat de Kinect teruggeeft bevat niet-serialiseerbare data zoals native pointers. Deze data wordt tenslotte beschikbaar gesteld voor andere scripts. Dit model maakt het mogelijk om op een gemakkelijke manier meerdere lichamen te tonen. Deze operatie was in eerdere versies van de applicatie een groot struikelblok, omdat er een model werd gebruikt dat data doorstuurde naar scripts die het nodig hadden. FakeKinect wordt gebruikt door KinectManager om data uit een bestand te laden. Scripts kunnen een aanvraag doen aan een FakeKinect voor het volgende frame. Dit wordt teruggegeven nadat er genoeg tijd is verstreken sinds het vorige frame. Dit is mogelijk omdat we een timestamp opslaan tijdens het wegschrijven van frames. Het wachten zorgt ervoor dat het terugspelen van frames vloeiend verloopt. BodyManager staat in voor het renderen van Bodies. BodyManager verkrijgt frames van KinectManager. Deze frames worden gebruikt om, afhankelijk van de RenderMode, de posities of de rotaties van botten in het 3D-model aan te passen. Er zijn twee RenderModes: Lines of Blocks. Bij RenderMode.Lines wordt het model gerenderd als kubussen die de positie van gewrichten voorstellen, met hiertussen lijnen die de botten voorstellen. RenderMode.Blocks daarentegen, gebruikt de rotaties van gewrichten om blokken te draaien. Positionering van de botten kan dan afgeleid worden door het beginpunt van een bot gelijk te stellen aan het eindepunt van een ander bot. KinectData is verantwoordelijk voor het filteren van body data. Het ontvangt frames van BodyManager en stuurt deze door naar de juiste filters. De gefilterde data wordt dan teruggestuurd naar BodyManager. De details van het filteren worden verder besproken in hoofdstuk 6. KinectRecorder wordt gebruikt door KinectManager om data mee op te nemen. Dit gebeurt via een Circulaire buffer die wordt leeggemaakt wanneer de limiet van deze buffer bereikt is. Frames worden dan omgezet naar JSON en weggeschreven naar de harde schijf. De details hiervan zijn te vinden in hoofdstuk 8.1. ExcerciseComparer, tenslotte, staat in voor het vergelijken van live frames en opgenomen frames. Dit gebeurt aan de hand van een Compare functie, welke in detail besproken worden vanaf hoofdstuk 8.2. Afhankelijk van het resultaat van Compare, gaat ExcerciseComparer besluiten of de KinectManager nieuwe opgenomen frames mag inladen.
24
7.2
Audio
Audio wordt gebruikt om audioclips, met daarin uitleg over een oefening, op te nemen. De audio wordt ook gebruikt om tijdens het opnemen aan de gebruiker te tonen hoe luid de audio is via een visualisatie. Elk frame vraagt AudioManager een frame op van de audio stream. Dit frame bestaat uit maximaal vier SubFrames (waarvan het nut tot dusver onduidelijk is. Dit deel van de API is zeer slecht gedocumenteerd). Deze worden omgezet van byte[] naar float[] en daarna ter beschikking gesteld voor andere scripts. Vervolgens wordt de geluidsintensiteit berekend door middel van Root-Mean-Square. Deze waarde wordt ook beschikbaar gesteld voor andere scripts. AudioVisualizer vraagt, tijdens een opname, elk frame de intensiteit van het geluid op aan AudioManager en vult dan een rechthoek in voor een gedeelte dat overeenkomt met de intensiteit. Deze rechthoek wordt ook gekleurd volgens een kleurengradiënt tussen groen en rood, waar groen de laagste intensiteit is. AudioRecorder vraagt tijdens een opname de ruwe data op van AudioManager en slaat deze op via oggenc2.exe. Dit wordt verder uitgelegd in hoofdstuk 9.
7.3
Color
Deze stream wordt voornamelijk gebruikt om mee te debuggen, en is bijna verbatim overgenomen van een voorbeeld van Microsoft (Microsoft, 2014). ColorSourceManager vraagt elk frame een frame op van de color stream. Dit wordt gekopieerd naar een texture. Zowel de ruwe data als de texture worden beschikbaar gesteld voor andere scripts. ColorSourceView vraagt vervolgens elk frame de texture op van ColorSourceManager en weergeeft deze in de spelwereld. Dit is het script dat gebruikers toelaat een live videobeeld te zien.
25
8. Oefeningen vergelijken
Om bruikbaar te zijn voor therapeuten, moet het mogelijk zijn om uitgevoerde oefeningen in real-time en automatisch te vergelijken met de opname. Hier zijn verschillende benaderingen mogelijk. Eerst zijn een aantal naïeve methodes getest. Deze zijn daarna verbeterd om tot onze uiteindelijke methode te komen. Uit preliminaire testen blijkt deze methode goed te werken. Uit verdere testen moet blijken hoe patiënten met een fysieke beperking deze methode ervaren. Voor we de methodes bespreken is er een beschrijving nodig van het bestandsformaat waarin we de oefeningen opslaan.
8.1
Het bestandsformaat
Om oefeningen gemakkelijk te delen met patiënten is het belangrijk dat ze gemakkelijk een oefening kunnen downloaden en openen in het programma. Er is geopteerd voor JSON omdat dit een relatief klein formaat is (vergelijk met XML, waar elke tag twee keer moet worden geschreven) dat toch gemakkelijk te lezen is. Een opname van een oefening is vrij complex en komt overeen met volgende hiërarchie:
• Posities – Naam joint – ID joint – Positie ∗ X ∗ Y ∗ Z – Tracking state 27
• Orientaties – Naam joint – ID joint – Orientatie ∗ X ∗ Y ∗ Z ∗ W • Is body getracked • Timestamp
Tenslotte is er ook de mogelijkheid om een audio-opname toe te voegen. Dit is in het Ogg Vorbis-formaat, een open-source lossy codec. Dit vermijdt licentiekosten voor het gebruik van MP3. Meer uitleg over het gebruik van audio is terug te vinden in hoofdstuk 9. Er is discussie geweest over het toevoegen van een video om de oefening mee voor te doen. Hier was maar weinig interesse in en is bijgevolg (nog) niet toegevoegd. Er is wel wat onderzoek naar gedaan. Meer uitleg hierover is terug te vinden in hoofdstuk 10.
8.2
Posities vergelijken
Dit is het eerste naïeve algoritme. We nemen de posities van de joints van de opname en het live-beeld en controleren of deze binnen een bepaalde marge vallen. Dit algoritme is praktisch onbruikbaar. Een persoon moet dan op exact dezelfde positie staan als waar de therapeut stond tijdens de opname. Dit is binnen onze applicatie heel moeilijk. Dit algoritme is in andere situaties wel bruikbaar. NeuMimic (NeuMimic, 2013) toont op de achtergrond een videofeed met een overlay van het skelet. Dit maakt het wel gemakkelijk de originele positie aan te nemen. Als we posities vergelijken, is er natuurlijk ook een probleem met afmetingen van het lichaam. Als een klein persoon de oefening van een groot persoon na doet, komen de posities totaal niet overeen. Een mogelijkheid hier is de oefening niet laten opnemen door de therapeut, maar door de patiënt, geassisteerd door de therapeut. 28
8.3
Rotaties vergelijken
Dit is het tweede naïeve algoritme. In plaats van posities gaan we hier rotaties vergelijken. Dit algoritme is beter bruikbaar dan hetgeen waar we posities vergelijken. Het neemt een lijst van gewrichten die vergeleken moeten worden. Dan gaat het kijken of het verschil in rotaties van de gewrichten binnen een bepaalde marge valt. Een belangrijk punt wanneer de afstand tussen rotaties berekend wordt is dat men in twee richtingen de afstand moet berekenen en hier de kortste afstand moet nemen. Bijvoorbeeld: als men op de naïeve manier de afstand tussen twee hoeken, 350° en 10°, berekent. Dan is het resultaat een verschil van 340°. Terwijl de eigenlijk afstand 20° is. Dit probleem is op te lossen zonder if-else: alvorens de afstand te berekenen, trek 360° af van de tweede hoek. De tweede hoek wordt dan van het bereik [0, 360] verplaatst naar het bereik [−180, 180]. Als we dan het verschil berekenen en hier de absolute waarde van nemen is het resultaat altijd de kortste afstand. Het vermijden van de if-else kan de performantie sterk verbeteren. Moderne CPU’s maken gebruik van het concept pipelining. Hiermee kunnen ze meerdere instructies tegelijk uitvoeren. Tenminste, wanneer de CPU kan afleiden wat de volgende instructie hoort te zijn. Bij een if-else moet de CPU wachten tot de beslissing genomen is om te bepalen wat de volgende instructie gaat worden. Dit kan heel wat performantie kosten. Tegenwoordig maken CPU’s ook gebruik van branch prediction. Dit is een methode om op basis van vorige resultaten de uitkomst van een if-else te voorspellen. Maar ook dit is niet perfect, want het hangt af van patroonherkenning. De kost van een foute voorspelling hangt af van de lengte van een pipeline.
8.4
Eindresultaat
Voor de uiteindelijke methode van vergelijken zijn we vertrokken van het algoritme dat rotaties vergelijkt. Dan hebben we besloten om de kwaliteitsmeting te baseren op het eerste frame. We geven de gebruiker een aantal seconden na het starten van de oefening om de beginpose aan te nemen. Op dat moment wordt er een "foto"genomen en gaan we er van uit dat dit de juiste pose is. Dit maakt het gemakkelijk voor de gebruiker om de oefening vlot te starten. Deze beslissing is genomen omdat er de beperking is opgelegd dat het moet gaan om vrij stationaire oefeningen. Een voorbeeld is een oefening waar de armen bewogen dienen te worden, terwijl dat de rug zich stationair houdt. Dit is geen zware beperking omdat de focus bij dit type revalidatie ligt op het rechthouden van de 29
rug tijdens de uitvoering. Als de foto genomen is, wordt elk volgende frame vergeleken met die startpositie. De therapeut zal dan instellen dat, bijvoorbeeld, alleen de rug dient gevolgd te worden. Om de eigenlijke voortgang van de oefening te volgen zijn er een aantal visualisaties die in de volgende sectie besproken worden. Door deze twee te combineren kan dan de oefening beoordeeld worden.
8.5
Visualisaties
Dit prototype bevat een aantal visualisaties om te bepalen tot op welk punt de patiënt de oefening voltooid heeft. Ze dienen ook als indicator voor de patiënt, zodat deze kan zien hoe goed of hoe slecht deze de oefening uit voert. Uit verder onderzoek moet blijken welke visualisatie het beste informatie overdraagt aan de gebruiker. Op dit moment worden de visualisaties ook gebruikt door ons om het systeem te debuggen. Er is in sommige schermen bijgevolg te veel informatie aanwezig voor de patiënt. Ten eerste is er een simpele indicator die aan de hand van gekleurde bolletjes aangeeft of de huidige posities binnen alle marges vallen. Op dit moment is er een rode en een groene bol, maar dit moet eventueel nog aangepast worden om mensen met kleurenblindheid te helpen. Mogelijk werkt dit systeem wel voor kleurenblinde mensen omdat de posities van de bollen ook verschillen. Uit preliminaire testen blijkt deze vooral handig om de andere indicatoren samen te vatten. Het geeft in één blik weer of alle posities binnen de marges vallen of niet. Het biedt echter te weinig informatie om alleenstaand gebruikt te worden. Ten tweede is er een indicator die een simpel lichaam voorstelt. Dit bestaat uit een 15-tal botten die elk apart verkleuren aan de hand van de ingestelde marges. Wanneer een bot binnen de marge valt wordt deze groen gekleurd. Vanaf het moment dat deze buiten de marge valt wordt het geel. Dan is er een gradiënt van geel naar rood dat aangeeft hoe ver de marge overschreden wordt. Bij één maal de marge is de kleur geel, bij twee maal de marge oranje en bij drie maal de marge rood. Deze indicator is handig om te zien welke botten buiten de marges vallen en hoe ver er buiten. Het is waarschijnlijk het beste compromis tussen informatiedichtheid en gebruiksgemak. In combinatie met de vorige indicator vormt het een krachtig systeem waarbij de gebruiker voornamelijk kijkt naar de bollen. Wanneer de bol dan rood wordt, wordt de aandacht verplaatst naar het lichaam, waar het snel duidelijk wordt welk bot buiten de marge valt. 30
Een derde scherm is er een die vooral gebruikt wordt door de developers. Het informatiedichtheid is zeer groot, en om die reden niet geschikt voor gebruikers. Dit scherm toont per bot wat de afwijking is per as (x, y en z). Daarbij hoort eenzelfde gradiënt als beschreven bij de vorige visualisatie.
31
9. Audio
Er is de mogelijkheid om geluid op te nemen, om bijvoorbeeld extra uitleg te geven bij een oefening. Dit gebeurt via de tool oggenc2.exe. oggenc2.exe is een commandlinetool voor de populaire open-source, lossy audio codec Ogg Vorbis (http://www.vorbis. com). Initieel is er ook een poging geweest om een MP3 encoder te gebruiken. Deze interpreteerde de data van de Kinect fout en produceerde alleen ruis. Zelfs indien MP3 werkte, mocht het nog niet gratis gebruikt worden in software; het is een gepatenteerd formaat.
9.1
De data
Audio-data komt binnen via een audio-stream. Deze is helaas heel slecht gedocumenteerd, waardoor we aan de hand van trial and error het formaat moesten proberen te achterhalen. Uiteindelijk hebben we volgende eigenschappen kunnen afleiden:
• Elke 16 ms is een audioframe beschikbaar • Een frame bestaat uit maximaal vier subframes • Een subframe bevat een array van samples: byte[1024] • Deze data is in 32-bit signed float PCM. Dus moet de data eerst worden omgezet van byte[1024] naar float[256]. • De sample rate is 16 kHz • De endianness is little endian 33
9.2
Opnemen
Om audio op te nemen met oggenc2.exe, gebruiken we volgende command-line-opdracht: oggenc2 −−raw−format=3 −−raw−chan=1 −−raw−r a t e =16000 − −−output=
De betekenis van deze command-line switches is:
--raw-fomat=3 De data bestaat uit IEEE floats (32-bit, signed). --raw-chan=1 De input bevat 1 audiokanaal. --raw-rate=16000 De data is gesampled aan 16kHz. De input is geen bestand, maar ruwe data. --output= Sla het bestand op als .
Daarna sturen we elk audioframe naar oggenc2.exe via een BinaryWriter. Deze neemt dan de taak op zich om data te encoderen en weg te schrijven naar de harde schijf. Omdat we oggenc2.exe gebruiken hiervoor, gebeurt het encoderen tegelijk op een andere thread. Dit bespaart heel wat processorkracht op onze thread. Deze code werkt, maar waarschijnlijk zal er overgeschakeld moeten worden naar een andere library. De geluidskwaliteit is slecht. Door de ondermaatse documentatie hebben we niet kunnen achterhalen waarom. Een goede opname is wel mogelijk met Audacity, dus moeten we proberen te achterhalen of er iets mis is met onze assumpties over het formaat of met de library zelf. Mogelijk moeten we overschakelen op een lower-level library zoals WASAPI (Windows Audio Session API). Dit is de meest recente audio API voor Windows en biedt lagere latency aan dan de WaveOut Audio API, terwijl deze een stuk gemakkelijker is om mee te werken dan ASIO. ASIO is het laagste niveau waarmee de Audio pipeline geprogrammeerd 34
kan worden, en biedt dus de grootste flexibiliteit aan. Hiertegenover staat wel dat je met veel meer low-level dingen rekening moet houden. Zo is het bijvoorbeeld moeilijk audio devices te delen met andere processen. WaveOut daarentegen is heel gemakkelijk te programmeren, maar is veel minder flexibel dan WASAPI of ASIO.
35
10. Video
Hoewel video opnemen een heel lage prioriteit heeft binnen het project is er toch wat tijd gespendeerd om te zoeken naar mogelijke manieren om video op te nemen. De meest uitgebreide library is ffmpeg. Hier bestaan C# bindings voor (SharpFFmpeg, Aforge.NET ) maar deze hangen af van klassen die niet beschikbaar zijn in Mono binnen Unity3D. De enige optie is dus om zelf een wrapper rond ffmpeg te schrijven, of de commandline client van ffmpeg te gebruiken. Het probleem met die laatste optie is dat de hoeveelheid data te groot is. De video-stream van de Kinect bestaat uit afzonderlijke frames in full HD (1920px x 1080px). Deze data neemt enorm veel ruimte in beslag:
30f rames/sec × (1920px × 1080px × 3B/px) = 177M B/sec
Een mogelijkheid is de data downscalen met een factor 1:2. Dit is significant minder, maar kan nog problemen opleveren op een trage of oude computer:
30f rames/sec × (960px × 540px × 3B/px) = 44M B/sec
Omdat er geen kant-en-klare methode is om video op te nemen van de Kinect binnen Unity3D, is dit niet opgenomen in de applicatie.
37
11. Stemherkenning
Omdat de applicatie gebruikt gaat worden door mensen met een fysieke beperking, is het bijna een vereiste dat de applicatie stemherkenning heeft. Dit zou patiënten toelaten om, nadat ze fysiek de applicatie hebben opgestart, het gehele programma te besturen met hun stem. Dan hoeven ze niet steeds van en naar de computer te lopen om oefeningen te starten, te stoppen en uit te voeren. Initieel is er gekeken naar Microsoft.Speech en System.Speech. Dit omdat ze beiden libraries zijn die kunnen werken met een simpele grammar. Dat is een lijst met termen die het programma moet herkennen. Omdat er gewerkt wordt met een vooraf gedefinieerde grammar, is de performance hoog genoeg om real-time aan stemherkenning te doen. Een nadeel is dat het programma alleen de woorden in de grammar begrijpt. Grammars worden gedefinieerd in ofwel de code, ofwel een XML bestand dat het programma inleest. Het verschil tussen Microsoft.Speech en System.Speech is dat System.Speech geoptimaliseerd is voor de Kinect. Zo gaat deze er standaard van uit dat de audio in het formaat 32-bit float met een sampling rate van 16kHz is. Ook houdt deze library rekening met het akoestische model van de Kinect. Daardoor kan de detectie beter verlopen. Naast libraries gebaseerd op grammars, zijn er ook libraries die proberen alle woorden te herkennen. Microsoft.Speech kan dit, wanneer deze zo wordt ingesteld. Dit is veel minder performant dan het herkennen van een voorgedefinieerde grammar. Maar hiertegenover staat dat je in theorie elk woord zal kunnen herkennen. Met dit soort stemherkenning is het niet mogelijk om accurate stemherkenning te doen in real-time. Om die reden is deze optie niet gekozen. Een derde klasse van stemherkenningssoftware zijn diegene die gebaseerd zijn op een web API, zoals bijvoorbeeld de API van AT&T. Deze libraries werken ook zonder grammars en kunnen alle woorden herkennen. Maar in plaats van dit lokaal – op de gebruiker zijn PC – te doen, wordt een audioclip verstuurd naar de API. Deze gaat de audioclip verwerken en het antwoord terugsturen als tekst. Deze klasse van stemherkenning is wel snel genoeg om real-time stemherkenning van een volledige taal te doen, omdat er toegang 39
is tot een aantal snelle servers. Maar ook dit is geen optie voor ons, omdat er dan altijd een internetverbinding nodig is. Zelfs wanneer een internetverbinding gegarandeerd is moet je nog rekening houden met gevallen waar het internet ineens wegvalt, of wanneer er slechte verbinding is. Daarnaast wordt je ook afhankelijk van het bedrijf dat de API aanbiedt. Als dit bedrijf beslist te stoppen met de API, heb je pech. Hoewel zoiets niet vaak voorkomt is het toch een belangrijk tegenargument. Zelfs als we er van uit gaan dat voorgaande argumenten geen probleem zijn, dan nog is er het probleem van ping. Als je ver van de server woont (en dit is niet uitzonderlijk als het bedrijf dat de API aanbiedt in Amerika gevestigd is), dan kan je al snel een ping hebben van 500ms. Dit is lang genoeg om een gebruiker te laten twijfelen of het commando dat ze net gaven geslaagd was. Helaas krijgen we ook hier weer te maken met de beperkingen van Unity en Mono. De versie van Mono die Unity gebruikt is outdated en heeft geen ondersteuning voor de stemherkenning-libraries in .NET (Microsoft.Speech en System.Speech). Als die ondersteuning er wel zou zijn is er een tweede probleem. Deze libraries verwachten een audiostream die ze zelf kunnen decoden. Om een tot nog toe onbekende reden heeft Microsoft deze stream niet beschikbaar gesteld in de Unity library voor de Kinect. In de gewone library voor Kinect (die niet kan samenwerken met Mono) is de stream wel beschikbaar.
40
12. Besluit
De Kinect is een knap staaltje techniek van Microsoft. Voor een zeer lage prijs leveren ze een apparaat met een groot aantal sensoren. Deze zijn ook verrassend nauwkeurig voor die prijs. Helaas is de kwaliteit niet optimaal voor het doel van dit project. Om effectief therapie te leveren moet het systeem zeer nauwkeurig zijn. Er moet een afwijking van minder dan 5° gemeten kunnen worden. Om een heel sterk systeem te maken is een nauwkeurigheid van 1° gewenst. De Kinect kan voor sommige lichaamsdelen data van deze kwaliteit voorzien (bijvoorbeeld voor de botten in de rug). Voor andere moeten we blij zijn met 5 − 10° nauwkeurigheid. Dit zijn gelukkig ook de botten waar sterke data niet zo noodzakelijk is (bijvoorbeeld de benen). Met meer werk is het misschien mogelijk de gewenste nauwkeurigheid te behalen. Aan de andere kant is dit een meerjarig project, dus er is nog genoeg tijd om dit prototype te verbeteren. Het is ook mogelijk dat de API in de tussentijd verbeterd wordt om nauwkeurigere data te verzamelen.
41
13. Reflectie
Tijdens mijn stage zijn een aantal dingen duidelijk geworden: Ten eerste is het meer dan ooit duidelijk geworden dat ik weinig achtergrond heb in wiskunde. Een aantal van de eerder beschreven filters heb ik gevonden in wiskundige papers. Om deze te implementeren moest ik eerst de formules begrijpen (waar Tom Quareme mij uitstekend mee heeft geholpen). Wanneer deze werden toegepast op positievectoren kon ik alles nog redelijk snel begrijpen. Ze toepassen op quaternions was een heel ander verhaal. Het concept begrijp ik nog altijd niet heel goed, dus hier wiskunde op toepassen is niet simpel. Ik heb wel heel veel bijgeleerd op het vlak van wiskunde. Daarnaast ben ik er ook achter gekomen dat ik over het analytisch vermogen beschik dat nodig is om meer geavanceerde onderwerpen aan te leren. Ten tweede heb ik ondervonden dat ik me heel snel bekend kan maken met nieuwe technologieën. Na een dag of twee was ik al volop aan het programmeren met de Kinect, een apparaat dat ik zelfs nog nooit van dichtbij had gezien. Al bij al ben ik trots op wat ik bereikt heb. De nieuwe versie van de Kinect is lang niet zo goed gedocumenteerd als de eerste versie en Unity heeft een aantal geplande features niet toegelaten. Desondanks heb ik toch veel werk kunnen verrichten dat de toekomst van dit project zeker zal helpen.
43
Bibliografie
Azimi, M. (2014). Skeletal joint smoothing white paper. Microsoft Developer Network. At URL: http://msdn.microsoft.com/en-us/library/jj131429.aspx. Card, S. K., Moran, T. P., Newell, A. e.a. (1981). The psychology of human-computer interaction. Holt, C. C. (2004). Forecasting seasonals and trends by exponentially weighted moving averages. International Journal of Forecasting, 20 (1), 5–10. Markley, F. L., Cheng, Y., Crassidis, J. L. & Oshman, Y. (2007). Averaging quaternions. Journal of Guidance, Control, and Dynamics, 30 (4), 1193–1197. Microsoft. (2014). Microsoft unity plug in. Verkregen 10 maart 2015, van go.microsoft. com/fwlink/?LinkID=513177 NeuMimic. (2013). Microsoft kinect physical therapy - neumimic demo. Verkregen 25 februari 2015, van https://www.youtube.com/watch?v=UPJkFVIdjWk
45