Teknisk rapport David Sandberg, Tobias Lundqvist, Rasmus Dewoon, Marcus Wirebrand Version 0.3 Status Granskad Godkänd
Projektidentitet Grupp 2, 2010/HT Linköpings Tekniska Högskola, ISY 1 Namn Ansvar Telefon E-mail David Sandberg Projektledare 073-9504672 davsa746@student.liu.se Marcus Wirebrand Test- och kvalitetsansvarig 070-2778625 marwi908@student.liu.se Rasmus Dewoon Designansvarig 070-2326302 rasde529@student.liu.se Tobias Lundqvist Dokumentansvarig 070-7124429 toblu024@student.liu.se E-postlista för hela gruppen: tsbb11mt@googlegroups.com Hemsida: Kund: Datorseende/ISY, LiU Kontaktperson hos kund: Michael Felsberg, mfe@isy.liu.se, 013-282460. Kursansvarig: Michael Felsberg, mfe@isy.liu.se, 013-282460. Handledare: Fredrik Larsson, larsson@isy.liu.se.
Innehåll 1 Inledning 5 1.1 Bakgrund................................... 5 1.2 Parter..................................... 5 1.3 Användarhandledning............................. 5 2 Översikt av produkten 5 2.1 Grov beskrivning av produkten....................... 6 2.2 Gester..................................... 6 3 Delsystem 1 - Hårdvara 7 3.1 Inledande beskrivning av delsystem 1.................... 7 3.2 Komponenter................................. 8 3.2.1 Dator................................. 8 3.2.2 Projektor............................... 8 3.2.3 Kamera................................ 8 3.2.4 Diod.................................. 9 3.2.5 Nätaggregat.............................. 9 3.2.6 Högtalare............................... 10 3.2.7 Labbkort................................ 10 3.2.8 Glasskiva............................... 10 3.3 Lådkonstruktion................................ 11 3.4 IR-diodernas kretsschema.......................... 12 3.5 Kopplingsschema............................... 13 4 Delsystem 2 - Mjukvara 13 4.1 MultiTouch.................................. 14 4.2 CaptureVideo................................. 14 4.3 ImageProcessing............................... 14 4.4 Calibrate.................................... 15 4.5 Analyse.................................... 16 4.5.1 TrackBlobs.............................. 16 4.5.2 FilterPositions............................. 17 4.5.3 Analys av rörelser........................... 17 4.6 Controller................................... 21 5 Kända begränsningar 21 6 Förbättringar 21 7 Referenser 22 2
A Tillståndsscheman 23 B h-ler 27 B.1 CaptureVideo................................. 27 B.2 ImageProcessing............................... 29 B.3 Calibrate.................................... 33 B.4 Analyse.................................... 36 B.5 Controller................................... 43 3
Dokumenthistorik 4 Version Datum Utförda förändringar Utförd av Granskad 0.1 2010-11-23 Skapande av dokument. tl alla 0.2 2010-12-06 Alla delar är ihopbyggda. tl 0.3 2010-12-09 Småjustering tl
1 Inledning Syftet med projektet var att tillverka ett system med inbyggd multi-touch och ritplatta, samt att utveckla ett gränssnitt mot operativsystemet. Målet är att kunna ersätta tavlan i undervisning och diskussioner med multi-touch-skärmen. I projektet utvecklades både hård- och mjukvaran. 1.1 Bakgrund Beställaren har ett intresse att kunna byta ut normal tavelundervisning med en mer interaktiv undervisning på en multi-touch-skärm. 1.2 Parter Projektets beställare är Michael Felsberg, projektmedlemmar David Sandberg, Marcus Wirebrand, Rasmus Dewoon och Tobias Lundqvist. Fredrik Larsson är handledare. 1.3 Användarhandledning Se separat användarhandledning. 2 Översikt av produkten Systemet består av två separata delar: en hårdvarudel samt en mjukvarudel. Mjukvarudelens uppgift är att tolka hårdvarudelens data för att styra operativsystemet. Hårdvarudelen projicerar bilden från operativsystemet på skärmen. IR-dioder belyser skärmen så att tryck på skärmen reekterar ner IR-ljus mot kameran som detekterar IR-ljus. Mjukvarudelen i systemet analyserar tryck på skärmen med hjälp av bilden från kameran. När tryck på skärmen identierats och lokaliserats tolkas användarens gester och motsvarande händelse skickas till operativsystemet. 5
6 Figur 1: Ramkonstruktionen med hårdvaran inuti Figur 2: Lådans utsida och glas 2.1 Grov beskrivning av produkten Systemets hårdvarukomponenter är en dator, en projektor, en kamera och en skärm som projektorn projicerar bilden på. IR-dioder sitter i kluster som lyser parallellt med skärmen och när användaren trycker på skärmen re ekteras ljuset ner mot kameran. Den fångade kamerabilden skickas sedan till mjukvarudelen för analys. Resultat från mjukvarudelens analys styr sedan operativsystemet. 2.2 Gester Användaren kan utföra olika typer av gester med ngrarna för att styra operativsystemet. I tabell 1 åter nns gesternas olika funktioner.
7 Antalet Gest Händelse ngrar 1 Nudda Vänsterklick 1 Drag Makera/ytta 2 Nudda först med Högerklick vänster ngret, sätt sedan ned högerngret till höger om det första ngret och släpp sedan båda två för att utföra högerklick 2 Dra uppåt Scrolla up 2 Dra nedåt Scrolla ner 2 Nypa inåt Zooma ut 2 Nypa utåt Zooma in 2 Rotera Öppna tangentbordslayouten 3 Dra åt vänster Skift + Alt + Tab 3 Dra åt höger Skift + Alt + Tab 4 Dra uppåt Dölj alla fönster 4 Dra nednåt Visa alla fönster Tabell 1: Möjliga gester 3 Delsystem 1 - Hårdvara Hårdvarudelen ger ett gränssnitt för användaren mot mjukvarudelen av systemet. 3.1 Inledande beskrivning av delsystem 1 Hårdvarudelen projicerar bilden från Ubuntu på skärmen med en LED-projektor. Anledningen till att en LED-projektor används är för att hålla nere temperaturen i lådan. IR-dioder lyser parallellt med skärmen på undersidan så att tryck på skärmens ovansida reekterar ner IR-ljus mot kameran. Kamera detekterar IR-ljuset och skickar den resulterande bilden vidare till mjukvarudelen för analys. Kameran är en Point Grey-kamera med IR-lter.
3.2 Komponenter Hårdvarudelen innehåller ertalet komponenter listade enligt nedan. 8 3.2.1 Dator Datorn är en Mac Mini med 1,6 MHz Intel Core processor och 2 GB RAM-minne. Grakkortet är ett Intel GMA950. En Y-kabel för VGA är inköpt så att det är möjligt att visa bild på två skärmar samtidigt. 3.2.2 Projektor Figur 3: Mac Mini Projektorn är LG:s LED-projektor HX300G som lyser med 300 ANSI och har XGAupplösning 1024x768. 3.2.3 Kamera Figur 4: Projektor Kameran är en Point Grey FL2G kamera med maximal upplösning 1296x964 i 30 FPS. I vår implementation använder kameran upplösningen 640x480 i 58 FPS.
9 3.2.4 Diod Figur 5: Kamera Dioder är SFH484-L av LED-typ med våglängd 880 nm och har intensiteten 80 mw/sr. Dioderna är monterade i fyra kluster vardera innehållande 35 dioder på labbkort enligt nedan. 3.2.5 Nätaggregat Figur 6: Diod Deltacos nätaggregat ATX12V som genererar 350 W. Figur 7: Nätaggregat
3.2.6 Högtalare Högtalarelementen tas från Deltacos minihögtalare på 2 W som strömmatas via USB. Dessa har monterats på ovansidan av lådan där passande hål har borrats för högtalarna. 10 3.2.7 Labbkort Figur 8: Högtalare Två stycken av ELFA:s förtennade laboratoriekort 48-313-84 som är 100x160 mm stora har använts och båda är delade på mitten för lagom storlek på klustrena. 3.2.8 Glasskiva Figur 9: Labbkort 6 mm tjock glasskiva med ena sidan blästrad. Figur 10: Glasskiva
3.3 Lådkonstruktion Lådan består av ett ramverk av trälister med måtten 22x45 mm. I era av hörnen har vinkeljärn skruvats fast för att förstärka stabiliteten hos ramverket. Kring ramverket har plywoodskivor med tjockleken 12 mm monterats. Detta skyddar komponenterna på lådans insida samt minimerar störande IR-strålning som kan påverka eektiviteten hos systemet. På ena kortsidan av lådan nns en dörr för lätt åtkomst av systemets komponenter. På undersidan av lådan sitter fyra stycken hjul fastsatta. Detta ger den nödvändiga mobilitet som krävs. Två av dessa hjul är låsbara så att lådan inte yttas allt för lätt när den används. På ovansidan av lådan ligger en glasskiva med måtten 77,4x58,0x0,6 cm vars ena sida är blästrad. Runt kanten där glasskivan möter trälådan sitter en tunn metallist. Gångjärn, dörrhandtag, metallister samt transporthandtaget är enhetligt målade. 11 Figur 11: Lådans dimensioner
12 Figur 12: Ramverkets dimensioner 3.4 IR-diodernas kretsschema Nätaggregatet ger 12 V vilket diodkretsarna använder. En krets består av 7 st dioder och ett 15 ohms motstånd i serie. En kretsplatta innehåller 5 st sådana serier parallellkopplade, och lådan innehåller 4 st likadana enheter. Figur 13: Kretsschema
3.5 Kopplingsschema Hårdvarukomponenterna monteras enligt nedan. För att förenkla för slutanvändaren installeras även en förgreningssladd i lådan som då enbart behöver koppla in en strömsladd vid användning. 13 Figur 14: Hårdvarans kopplingar 4 Delsystem 2 - Mjukvara Mjukvarudelen i systemet hanterar tryck på skärmen genom att analysera bilder tagna med kameran. När ett eller era tryck på skärmen identierats och lokaliserats förmedlas denna information till operativsystemet. Mjukvaran tillåter förbättringar av homogran mellan bild- och skärmkoordinter genom kalibrering. All mjukvara är skriven i C++ och utnyttjar ertalet API:er. Nedan nns en mer ingående beskrivning av varje modul i systemet. Figur 15: Flödesschema för mjukvara
4.1 MultiTouch MultiTouch är den klass som styr hela programmet. Varje iteration börjar med att de senaste blobbarna hämtas från ImageProcessing som behandlar den senaste kamerabilden från CaptureVideo. Blobbarna skickas sedan vidare till Analyse som behandlar datan och använder Controller-funktionerna för att styra operativsystemet. MultiTouchklassen har även möjlighet att visa en meny med ertalet program. Bland de programmen kan man bland annat kalibrera homogran som görs med klassen Calibrate. Mer information om de olika programmen som nns i menyn är beskrivet i användarhandledningen. 4.2 CaptureVideo Klassen CaptureVideo läser in bilder från kameran. Systemet använder sig av Point Grey-kamerans SDK FlyCapture 2.0 [4], men det nns även möjlighet att läsa in bilder från andra typer av kameror med OpenCV [1]. Bilderna hämtas sedan av klassen ImageProcessing. Systemet klarar XGA-upplösning men kör i 640x480 för att kameran annars klipper bilden till 720x480 pixlar eftersom den inte har någon egen interpolering implementerad. 4.3 ImageProcessing För att lokalisera var på skärmen det trycks behövs en del bildbehandling utföras. Först plockas en bakgrundsmodell när programmet startas, detta för att kunna ta fram en dieransbild. Dieransbilden är absolutskillnaden mellan den aktuella bilden från videoströmmen och bakgrundsbilden. Det är i denna bild ngertoppar ska lokaliseras. För att stabilisera analysen så ltreras dieransbilden med ett medelvärdeslter, och sedan körs en adaptiv tröskling på bilden. Den adaptiva trösklingen tar fram ett medelvärde (µ(x, y)) för omgivningen av varje pixel och om insensiteten i pixeln är större än detta medelvärde plus ett givet tröskelvärde anses pixeln vara en del av en ngertopp. Den adaptiva trösklingen returnerar en binärbild som sedan används för att bestämma position och storlek av trycken på skärmen. Ekvationer för adaptiv tröskling kan ses nedan. µ(x, y) = 1 (2dx + 1) (2dy + 1) x+dx y+dy i=x dx j=y dy Image(i, j) { 255 if Image(x, y) > µ(x, y) + T threshimage(x, y) = 0 else 14
15 När alla blobbar i binärbilden är lokaliserade är det enda kravet på dem för att räknas som ordentliga tryck på skärmen att deras area benner sig inom ett visst intervall. Alla blobbar som uppfyller detta krav sparas undan och skickas vidare till styrprogrammet. Figur 16: Delmoment i bildbehandlingen. Uppe vänster: Orginalbild. Nere vänster: Differansbild. Uppe höger: Efter adaptiv tröskling. Nere höger: Orginalbild med blobbar 4.4 Calibrate Calibrate-klassen används endast när systemet ska kalibreras. Kalibrering utförs genom att det på skärmen ritas ut ett antal kors på skärmen och personen som kalibrerar systemet får trycka på mitten av dessa kors. När position för samtliga kalibreringspunkter har bestämts i kamerakoordinater så kan en homogra mellan kamerakoordinaterna och skärmkoordinaterna beräknas. Homogran ska sedan skickas vidare till Analyse-klassen så att den kan transformera blobbarnas positioner till skärmkoordinater. Klassen utnyttjar OpenCV [1] för att utföra bildbehandling.
16 Funktion init setweightimage calchomography gethomography Beskrivning Initierar instansen. Bakgrundskompensering. Beräknar homogran mellan kamera- och skärmkoordintarer. Returnerar homogran mellan kamera- och skärmkoordintarer. 4.5 Analyse Analyse är den del av mjukvaran som bearbetar de blobbar som bildbehandlingen ger och används enbart då operativsystemet ska styras. Det maxmimala antalet blobbar som ska hanteras är fyra stycken så blob trackingen är gjord för att enbart tracka noll till fyra blobbar. Dessutom är det enbart vissa rörelser som är tillåtna för tre och fyra ngrar. 4.5.1 TrackBlobs Trackingen av blobbarna är nödvändig för att kunna identiera vilka rörelser som utförs av ngrarna på skärmen. Eftersom typerna av objekt som behövs trackas är väldigt begränsad samt eftersom bilduppdateringen är ganska hög så används specik tracking för olika typer av ngerrörelser. När det bara nns ett nger på skärmen så kommer det ngret implicit antas vara samma objekt bild efter bild. Om ytterligare ngrar tillkommer t.ex. genom att era ngrar sätts ner nästan samtidigt så kommer det nger som var närmast det första ensamma ngrets position väljas som samma objekt. Då två ngrar trackas samtidigt baseras blobbarnas objekttillhörighet i bild(t) på det kvadratiska avståndet till blobbarnas position i bild(t 1). Blobbarnas matchning väljs baserat på det minsta av de två möjligheterna på summan av det kvadratiska avståndet, se ekvationen nedan. Detta medför att de olika rörelser som kan utföras med två ngrar trackas korrekt. dist = blobb (x t x t 1 ) 2 + (y t y t 1 ) 2 När tre eller fyra ngrar används så är trackingen mycket begränsad till vad den klarar av för förändringar i position hos de olika blobbarna. Eftersom de enda rörelser som är implementerade för tre ngrar är en svepande rörelse åt sidan så trackas blobbarna efter deras ordning i x-led i förhållande till varandra. Detta medför att roterande rörelser med
17 tre ngrar är förbjudna när operativsystemet används. Rörelser med fyra ngrar följer samma krav som för rörelser för tre ngrar. Inte heller här tillåts ngrarna byta plats med varandra, så återigen bestäms blobbarnas objekttillhörighet efter deras ordning i x-led. 4.5.2 FilterPositions Positionssekvenserna för de blobbar som ges från trackingen har inte speciellt bra fördelningsfunktioner. Positionsbruset som antas vara gaussiskt i x- och y-led har lika stor varians som storleken på blobben. Detta resulterar i ett irriterande immrande av muspekaren. För att förbättra denna positionering så appliceras ett lågpasslter på sekvenserna av positioner. 4.5.3 Analys av rörelser Analys av rörelser är det största momentet i hela analysdelen. analysemovement:s uppgift är att känna igen vilken rörelse som ngrarna utför. Hela funktionen är baserad på en tillståndsmaskin. För varje rörelse som kan utföras ingår era tillstånd. Grundpricipen för majoriteten av rörelsen är att de börjar med ett grundtillstånd som sedan beroende på utförda rörelser går in i ett händelsetillstånd, se Appendix A för tillståndsgrafer. Grundtillstånd I tillståndsmaskinen nns 6 st huvudtillstånd: Wait movement: Då inga blobbar registrerats så går tillståndsmaskinen in i detta tillstånd och kommer ej gå ur det förrän blobbar registrerats. Stop state: Då en rörelse uförts eller då en otillåten rörelse försöker utföras så går tillståndsmaskinen in i Stop state. Enda sättet att komma ur Stop state är att noll blobbar registreras. Då kommer det nya tillståndet bli Wait movement. State 1: Då ett nger satts ner går tillståndsmaskinen in i state 1. Detta är grundtillståndet för rörelserna vänsterklick och markering med mus. Så länge som enbart en blob nns på skärmen och den blobben inte rör sig utanför de avståndsbegränsningar som nns så kommer detta tillstånd ej hoppas ur. State 2: Då två blobbar registreras och det tidigare tillståndet var state 1 eller wait movement så kommer state 2 bli det nya tillståndet. State två är grundtillstånd för rörelserna scroll, rotera, zooma in och zooma ut. Det ingår även i högerklick som är en
18 tidsbegränsad sekvens av state 1 och state 2. State 3,4: Då tre eller fyra blobbar registreras och ingen rörelse påbörjats, dvs då det tidigare tillståndet var wait state,state 1 eller state 2 så kommer det nya tillståndet bli state 3 eller state 4. Dessa är grundtillstånd för rörelsen swipe. Tre ngrar för horizontell swipe och fyra ngrar för vertikal swipe. Tillåtna rörelser De tillåtna rörelser som nns är beskrivna i tabell 2 och 3. I dessa tabeller nns även en beskrivning av de tillstånd som ingår i rörelsen.
19 Händelse Beskrivning Tillståndssekvens Vänsterklick Tryck ner ett nger utan att röra ngret i x- och y-led alltför mycket. När wait movement ngret sedan släpps så kommer vänsterklick att utföras på ngrets sista state 1 left click position. wait movement Markera med mus Tryck ner ett nger och dra ngret till godtyckling punkt på skärmen och släpp ngret. wait movement state 1 LetMouseDownAt MoveMouseTo LetMouseUpAt Högerklick Scroll Rotera Sätt ner ett nger på skärmen följt av ytterligare ett nger på godtycklig punkt på skärmen. När det andra ngret släpps upp igen så kommer högerklick utföras på det första ngrets position. Det nns en tidsbegränsning för hur lång tid det får ta att klicka med det andra ngret för att högerklick ska utföras. Sätt ner två ngrar och dra dem uppåt eller nedåt parallellt med x- axeln. Då båda ngrarna rört sig en förutbestämd sträcka i samma riktning i y-led så kommer scroll att bli nya tillståndet. Så länge som två ngrar fortfarande rör ytan och de inte rör sig i olika riktningar så kommer scroll vara aktivt. Rörelser i y-led kommer medför scroll i den riktningen. Sätt ner två ngrar och rör båda ngrarna i en roterande rörelse kring godtycklig punkt mellan ngrarna. Då en förutbestämd vinkel uppnåtts så kommer det nya tillståndet bli rotate. Rotate kommer sedan jämföra vinkeln från de två ursprungliga ngrarna med den kontinuerligt uppdaterade nya vinkeln. När den total rotationen är 70 grader så kommer roteringen utföras. Tabell 2: Tillståndssekvenser för rörelser wait movement state 1 state 2 right click stop state. wait movement (state 1) state 2 scroll wait movement (state 1) state2 rotate execute rotate stop state
20 Händelse Beskrivning Tillståndssekvens Zooma in Sätt ner två ngrar på skärmen och rör ngrarna från varandra. Då ett wait movement visst avstånd uppnåtts mellan ngrarna så kommer zoom in att ut- (state 1) state2 föras. När zoom in utförts så kommer after zoom bli det nya tillstån- zoom in after zoom det. Då är de enda tillåtna rörelserna zoom in och zoom out. Zooma ut Tre-ngrar swipe Sätt ner två ngrar på skärmen och rör ngrarna mot varandra. Då ett visst avstånd uppnåtts mellan ngrarna så kommer zoom out att utföras. När zoom out utförts så kommer after zoom bli det nya tillståndet. Då är de enda tillåtna rörelserna zoom in och zoom out. Rör tre ngrar i en svepande rörelse i x-led över skärmen. Då medelpositionen för de tre ngrarna rört sig en bestämd sträcka så kommer tre ngers swipe utföras. wait movement (state 1) state2 zoom out after zoom wait movement (state 1) (state 2) state 3 forward/backward afterforward/backward Fyra-ngrar swipe Rör fyra ngrar i en svepande rörelse i y-led över skärmen. Då medelpositionen för de fyra ngrarna rört sig en bestämd sträcka så kommer fyra ngers swipe utföras. wait movement (state 1) (state 2) (state 3) state 4 upward/downward afterupward/downward Tabell 3: Tillståndssekvenser för rörelser
4.6 Controller Controller är en klass som får instruktioner från klassen Analyse för att styra operativsystemet. Klassen kan både styra Ubuntu samt Mac OS X. För Ubuntu används API:t Xlib [5]. För OS X används Carbon [2] och CoreFoundation [3]. Dessa API:er möjliggör simulering av mus- och tangetbordstryckningar. 5 Kända begränsningar Systemet fungerar endast med tryckningar med ngerspetsar och alltså inte med hela handen eller dylikt. En annan begränsning är att ett nger som nuddar skärmen under handatan inte kommer att registreras pga. den bildbehandling som just nu sker. Ljusstyrkan får inte heller ändras för mycket i rummet för då krävs en omkalibrering samt uppdaterande av gridvärden. 6 Förbättringar Skulle ett fungerande API till kameran för OS X komma så kan kameran jobba i OS X istället, och eventuellt få högre upplösning på köpet. Val av skärmtyp är bra men tyvärr inte tillräckligt dius. IR-mättnaden borde förbättras, trots att vi är nöjda med val av teknik där, eftersom det fortfarande nns visst problem med ngertryckningar i yttersta hörnen. En mindre låda skulle ge lättare transport samtidigt som en ännu större skärm vore trevligt. Dessutom vore en upprullningsbar strömkabel till lådan trevligt för att underlätta transporter. Glasytan är känslig för repor och borde därför skyddas med tex. plast men samtidigt får inte känslan vid ngertryckningar förstöras heller. Möjligheten till kalibrering är tyvärr begränsad och kalibreringsställningarna borde utvecklas genom att tex. skapa metallställningar som kan justeras i sidled istället. Dessutom så vore det smidigt om det fanns snabbkommandon i eget fönster som aktiveras av en speciell ngernedsättning tillgängligt. 21
7 Referenser Referenser [1] Gary Bradski. OpenCV. http://opencv.willowgarage.com/, 2010. [Besökt 2010-09-24]. [2] Apple Inc. Carbon. http://developer.apple.com/carbon/, 2009. [Besökt 2010-09-20]. [3] Apple Inc. CoreFoundation. http://developer.apple.com/corefoundation/, 2009. [Besökt 2010-09-20]. [4] Inc. Point Grey Research. Point Grey - Flycapture 2.0 - Camera Control & Image Acquisition Software. http://www.ptgrey.com/products/pgrflycapture/index. asp, 2010. [Besökt 2010-09-29]. [5] Christophe Tronche. Xlib. http://tronche.com/gui/x/xlib/, 2005. [Besökt 2010-10-20]. 22
A Tillståndsscheman 23 Wait movement Stop 0 1+ 0 1 2 3 4 5+ State 3 State 2 State 1 State 4 Stop 0 1 2 3 4 5+ Left click State 3 State 2 State 4 Stop Wait movement LetMouseDownAt 0 1 2+ MoveMouseTo 0 1 2+ LetMouse UpAt 0 1+ Wait movement Stop Figur 17: Tillståndsschema för analys av rörelse, del 1
24 Wait movement Wait movement 0 1 2 3 4 5+ Right click 0 1+ State 2 Check type of movement scroll zoom in zoom out Stop State 4 State 3 rotate other zoom_in 0 2 other rotate 0 Wait movement 2 other zoom_out 0 Stop Update angle. 2 other Angle > 70 exec_rotate 0 Wait movement other Stop Stop Stop Wait movement Stop scroll after_zoom Wait movement 0 2 other Wait movement Stop Update scrolldist. Wait movement 0 2 other Stop Figur 18: Tillståndsschema för analys av rörelse, del 2
25 State 3 0 4 other Stop Wait movement forward backward 0 3 other 0 3 other after_backward Wait movement after_forward Stop 0 3 other 0 3 other Wait movement Wait movement Stop Figur 19: Tillståndsschema för analys av rörelse, del 3
26 State 4 0 4 other Stop Wait movement downward upward 0 4 other 0 4 other after_upward Wait movement after_downward Stop 0 4 other 0 4 other Wait movement Wait movement Stop Figur 20: Tillståndsschema för analys av rörelse, del 4
B h-ler 27 B.1 CaptureVideo / / CaptureVideo c a p t u r e s images from a camera connected to the computer. I f the camera doesn ' t support the use of Flycap, uncomment the l i n e "#d e f i n e USE_FLYCAP". I t w i l l then use OpenCV f o r g r a b b i n g frames o f f the camera. #ifndef CAPTUREVIDEO_H #define CAPTUREVIDEO_H #define USE_FLYCAP #include "cv. h" #include " highgui. h" #ifdef USE_FLYCAP #include " FlyCapture2. h" #endif class CaptureVideo { public : CaptureVideo () { } ~CaptureVideo ( ) ; private : // Setup the camera int i n i t ( ) ; // Capture a new image int captureframe ( ) ; // Return image p o i n t e r cv : : Mat getframe ( ) ;
28 #ifdef USE_FLYCAP // Camera FlyCapture2 : : Camera camera ; // Raw camera image FlyCapture2 : : Image rawimage ; #else #endif // Converted camera image FlyCapture2 : : Image convertedimage ; // OpenCV capture CvCapture capture ; // OpenCV frame IplImage frame ; }; // OpenCV image cv : : Mat image ; #endif
B.2 ImageProcessing 29 / ImageProcessing i s used to process frames captured from the video stream and analyse them to i d e n t i f y f i n g e r s. / #ifndef IMAGEPROCESSING_H #define IMAGEPROCESSING_H #include <s t d i o. h> #include "cv. h" #include " highgui. h" #include <vector > #include <s t r i n g. h> #include " CaptureVideo. h" #include " Blob. h" class ImageProcessing { public : ImageProcessing ( ) ; ~ImageProcessing ( ) ; // I n i t capture video void i n i t ( ) ; // C a l c u l a t e s a d a p t i v e background void backgroundmodel ( ) ; // Function t h a t does e v e r y t h i n g from grabing frame // to saving found b l o b s int findblobs ( ) ; // Preprocess image f o r e a s i e r c o n t o u r f i n d i n g void preprocess ( ) ; // Find contours in image void locatecontours ( ) ;
30 // Draw frame and goodcontours void draw ( ) ; // Used to i l u s t r a t e found b l o b s void drawtextandcontours ( ) ; // Grab new background void newbackground ( ) ; uchar getoriginalpointer ( ) ; uchar getdisplaypointer ( ) ; uchar getbackgroundpointer ( ) ; uchar getthresholdpointer ( ) ; // Set new v a l u e s f o r adaptivethreshold void setgridvalues ( std : : vector<float> gv ) { gridvalues = gv ;} // Get image width and h e i g h t int getwidth ( ) ; int getheight ( ) ; // Return a l l found b l o b s std : : vector<blob> getblobs ( ) ; private : // Capture video // Image stream CaptureVideo video ; // OpenCV // OpenCV capture stream CvCapture pcapture ; // OpenCV image IplImage s r c ; // Images
31 // Background image cv : : Mat background ; // Float v e r s i o n of background cv : : Mat backgroundfloat ; // Grey background image cv : : Mat backgroundgrey ; // Source frame cv : : Mat frame ; // Image f o r d i f f e r e n c e between frame and background cv : : Mat d i f f ; // Grey v e r s i o n of frame cv : : Mat framegrey ; // Absolute d i f f e r e n c e between frame and background cv : : Mat backgrounddiff ; // Thresholded frame cv : : Mat thresh ; // Thresholded image f o r showing cv : : Mat threshshow ; // Image f o r d i s p l a y i n g found b l o b s cv : : Mat disp ; // Contours // Vector with contours found in image std : : vector< std : : vector<cv : : Point> > contours ; // Vectors with contours p a s s i n g a l l t e s t s std : : vector< std : : vector<cv : : Point> > goodcontours ; // Vector with a l l b l o b s found in frame std : : vector<blob> blobs ;
32 // Min and max v a l u e in image double min ; double max ; // Image width and h e i g h t int imwidth ; int imheight ; // V a r i a b l e s f o r timer int timercounter ; double tt ; }; // Values f o r adaptivethreshold std : : vector<float> gridvalues ; #endif
B.3 Calibrate 33 / C a l i b r a t e p r i n t s c a l i b r a t i o n p o i n t s on the screen and reads p o s i t i o n on f i n g e r p r e s s. When a l l c a l i b r a t i o n p o i n t s has been handled i t c a l c u l a t e s both homography and p i x e l error. / #ifndef CALIBRATE_H #define CALIBRATE_H #include <GL/ glew. h> #include <s t d i o. h> #include <vector > #include "cv. h" #include " Blob. h" #include " Texture2D. h" class Calibrate { public : Calibrate () {} ~Calibrate () {} // i n i t i a l i s e c l a s s C a l i b r a t e with image width and h e i g h t void i n i t ( int ww, int wh ) ; // c a l i b r a t e p o i n t s std : : vector<cv : : Point2f> getcalibratepoints ( ) ; // c r e a t e c a l i b r a t e p o i n t s and s t o r e in v e c t o r void setupcalibration ( ) ; // c a l c u l a t e homography void calchomography ( std : : vector<cv : : Point2f >); // r e t u r n s c a l c u l a t e d homography cv : : Mat gethomography ( ) ;
34 // i s homography done? int gethomographystatus ( ) ; void setblob ( std : : vector<blob> blobs, std : : vector<blob> transblobs ) ; //main f u n c t i o n f o r c a l i b r a t e. handles drawing of // c a l i b r a t e p o i n t s and reads where the user p r e s s e s h i s // f i n g e r. c a l c u l a t e s homography when a l l p o i n t s has been // pressed // s e t s the image s i z e void setimagesize ( int iw, int ih ) ; // draws the c a l i b r a t i o n p o i n t s on the screen void draw ( ) ; private : // i s homography done? int homographystatus ; // s m a l l e s t d i s t a n c e between two f i n g e r p r e s s e s float mindist ; // counts how many f i n g e r s t h a t has been d e t e c t e d during // c a l i b r a t i o n int numblob ; // d e c i d e s how many c a l i b r a t i o n columns t h e r e should be, //same amount rows int numcols ; // s t o r e c a l i b r a t i o n s points, transformed p o i n t s f o r // error measurement and coords where user pressed std : : vector<cv : : Point2f> c a l i b r a t e P o i n t s ; std : : vector<cv : : Point2f> transpoints ; std : : vector<cv : : Point2f> imagepoints ; // s t o r e s i n t e n s i t y on screen when doing c a l i b r a t i o n, // not c u r r e n t l y used std : : vector<float> b l o b I n t e n s i t y ;
35 // the s t o r e d homography cv : : Mat homography ; // image s i z e int windowwidth ; int windowheight ; // c a l i b r a t i o n c r o s s t e x t u r e Texture2D texture ; // f o r drawing c r o s s at r i g h t p o s i t i o n GLfloat crossx ; GLfloat crossy ; }; // f o r c a l c u l a t i n g average error in f i n g e r p r e s s //compared to c a l i b r a t i o n p o i n t s float errorpush ; #endif
B.4 Analyse 36 #ifndef ANALYSE_H #define ANALYSE_H #include <s t d i o. h> #include "cv. h" #include <string > #include <iostream > #include "math. h" #include " Blob. h" #include " Controller. h" / c l a s s : P o s i t i o n Object used in the c l a s s BlobAnalyse to s t o r e and process P o s i t i o n data f o r d i f f e r e n t b l o b s. I t contains P o s i t i o n x and y and o p e r a t o r s such as addition, s u b t r a c t i o n e t c. / class Position { public : Position ( ) ; Position ( int, int ) ; ~Position ( ) ; double posx ; double posy ; Position& operator = ( const Position& param){ posx = param. posx ; posy = param. posy ; return this ; } Position operator += ( const Position& param) const{ Position temp ; temp. posx = posx + param. posx ; temp. posy = posy + param. posy ; return (temp ) ;
37 }; } Position operator ( const Position& param) const{ Position temp ; temp. posx = posx param. posx ; temp. posy = posy param. posy ; return (temp ) ; } Position operator + ( const Position& param) const{ Position temp ; temp. posx = posx + param. posx ; temp. posy = posy + param. posy ; return (temp ) ; } Position operator / ( const double param ) const{ Position temp ; temp. posx = posx/param ; temp. posy = posy/param ; return (temp ) ; } Position operator ( const double param ) const{ Position temp ; temp. posx = param posx ; temp. posy = param posy ; return (temp ) ; } / c l a s s : BlobAnalyse Class t h a t contains information on a l l the p r e v i o u s p o s i t i o n s of every a c t i v e b l o b. / class BlobAnalyse { public : BlobAnalyse ( ) ; ~BlobAnalyse ( ) ;
38 BlobAnalyse& operator = ( const BlobAnalyse& param){ area = param. area ; i n t e n s i t y = param. i n t e n s i t y ; p o s i t i o n = param. p o s i t i o n ; return this ; } // r e t u r n s number_disappeared_frames int getnumdisappearedframes ( ) ; // i n c r e a s e number_disappeared_frames void incnumdisappearedframes ( ) ; // r e t u r n s p o s i t i o n from the p o s i t i o n v e c t o r std : : vector<position > getposition ( ) ; // add p o s i t i o n in the p o s i t i o n v e c t o r void s e t P o s i t i o n ( Position ) ; // o v e r w r i t e p o s i t i o n in p o s i t i o n v e c t o r void s e t P o s i t i o n ( Position, int ) ; // r e t u r n s the area of the b l o b double getarea ( ) ; // r e t u r n s the I n t e n s i t y of the b l o b unsigned int g e t I n t e n s i t y ( ) ; // used to c o n t r o l l i f the b l o b has // been t r a c k e d t h i s frame int track_flag ; private : // contains information on a l l p r e v i o u s // p o s i t i o n s of the b l o b std : : vector<position > p o s i t i o n ; // area of b l o b double area ; // i n t e n s i t y of b l o b
39 unsigned int i n t e n s i t y ; }; // v a r i a b l e used to ensure t h a t temporary // disappereances do not d i s t u r b e s to much. int number_disappeared_frames ; / s t r u c t : eventdata Object used to t r a n s f e r information of the current event t h a t i s determined in Analyse. / struct eventdata { double posx ; double posy ; int s t a t e ; double s c r o l l d i s t a n c e ; }; / s t r u c t : Analyse Main c l a s s used f o r a l l t r a c k i n g and a n l y s i n g of b l o b s / class Analyse { public : Analyse ( ) ; ~Analyse ( ) ;
40 // i n i t i a t e v a r i a b l e s used in analyse void i n i t ( ) ; // i n i t i a t e v a r i a b l e s used in analyse // TRACKING // used to s e t new b l o b s in the current_blobs v e c t o r void updateblobposition ( BlobAnalyse ) ; // i f a b l o b d i s a p p e a r s e t h i s w i l l continue to l o o k // f o r i t f o r a few frames. Used in l i n k b l o b s () void trackmissingblobs ( ) ; // t r a c k s b l o b s. Used in l i n k b l o b s () void trackblobs ( ) ; // adds new b l o b s i f they appear. Used in l i n k b l o b s () void addnewblobs ( ) ; // main b l o b t r a c k f u n c t i o n void linkblobs ( ) ; // f i l t e r s the p o s i t i n s l i g h t l y to reduse noise void f i l t e r P o s i t i o n ( ) ; // t r a n s f e r s t r a c k e d b l o b s to the current_blob v e c t o r or void s p l i t B l o b s ( ) ; // ANALYSE // Main a n a l y s i n g f u n c t i o n void analysemovement ( ) ; // Creates Blobanalyse o b j e c t s from Blob o b j e c t s void analyseblobs ( std : : vector<blob >); // h e l p f u n c t i o n t h a t p r i n t s the p o s t i o n of p o s i t i o n s void p r i n t P o s i t i o n ( Position ) ; // s o r t s b l o b s a f t e r p o s i t i o n on the x a x i s. std : : vector<blobanalyse> quicksort ( std : : vector<blobanalyse >);
41 // Bug r e l e a s e r. used to prevent mouse l o c k void mouseup ( ) ; private : // c a l u l a t e s the square d i s t a n c e of two p o s i t i o n s double c a l c u l a t e D i s t a n c e ( Position ) ; int s t a t e ; // b l o b s in t h i s frame used in analyse s t d : : vector <BlobAnalyse> current_blobs ; // b l o b s in the p r e v i o u s frame s t d : : vector <BlobAnalyse> previous_blobs ; // new b l o b s in t h i s frame std : : vector<blobanalyse> new_blobs ; // temporary v e c t o r s used f o r c a l c u l a t i o n s std : : vector<blobanalyse> temp_new_blobs ; s t d : : vector <BlobAnalyse> temp_previous_blobs ; // V a r i a b l e s t h a t determines how f a r a movement // has to be performed b e f o r e an event i s t r i g g e r e d. double max_distance ; int zero_state_counter ; eventdata event ; int allowed_blob_disappearence ; int state2_counter ; double distance_before_swipe ; double distance_before_zoom ; double distance_before_scroll ; float angle_before_rotate ; float zoom_counter ; double rotate_sum ; double rotate_exec_angle ; }; Controller c o n t r o l l e r ;
#endif 42
B.5 Controller 43 / C o n t r o l l e r c o n t r o l s the o p e r a t i n g system. Works f o r both Linux (X11) and Mac OS X. / #ifndef CONTROLLER_H #define CONTROLLER_H #ifdef linux #include <X11/ Xlib. h> #include <X11/ extensions /XTest. h> #include <X11/keysym. h> #e l i f APPLE #include <Carbon/Carbon. h> #include <CoreFoundation/ CoreFoundation. h> #endif class Controller { public : Controller ( ) ; ~Controller ( ) ; // L e f t c l i c k at p o s i t i o n x, y void l e f t C l i c k A t ( int x, int y ) ; // Right c l i c k at p o s i t i o n x, y void rightclickat ( int x, int y ) ; // Double c l i c k at p o s i t i o n x, y void doubleclickat ( int x, int y ) ; // Move the mouse to p o s i t i o n x, y void movemouseto( int x, int y ) ; // S c r o l l void s c r o l l P i x e l s ( int32_t p i x e l s ) ;
44 // Hold down the l e f t mouse button at x, y void leftmousedownat ( int x, int y ) ; // Release the l e f t mouse button at p o s i t i o n x, y void leftmouseupat ( int x, int y ) ; // Moves the mouse w h i l e h o l d i n g down the l e f t button void pressandmove ( int xstart, int ystart, int xend, int yend ) ; // Returns the current mouse p o s i t i o n int getmouseposition ( ) ; // Open the Dashboard (F12) void opendashboard ( ) ; // Show a l l open windows (F9) void showallwindows ( ) ; // Hide a l l windows (F11) void hideallwindows ( ) ; // Zoom in void zoomin ( ) ; // Zoom out void zoomout ( ) ; // Tab void tab ( ) ; // Open keyboard void openkeyboard ( ) ; private : #ifdef linux int mouseposition [ 2 ] ; // Current p o s i t i o n of the mouse Display display ; // Display #e l i f APPLE CGPoint mouseposition ; // Current p o s i t i o n of the mouse #endif
45 }; #endif