2008-08-29

Vecka 35

I veckan har jag till största del programmerat. Jag har äntligen en funktion som räknar kopplade komponenter och tilldelar de färger automatiskt och den fungerar ganska bra, så bilderna nedan är en liten demo. Den första bilden har ett schackmönster där varje ruta (nätt och jämnt) sitter ihop med de andra, vilket betyder att bilden innehåller en enda kopplad komponent och får en grå färg.
Nästa bild är identisk, förutom att en erosion nu har gjort att rutorna nu inte sitter ihop. De är alltså olika kopplade komponenter och får olika färger (men de börjar bli så många att man har svårt att särskilja vissa färger).
Slutligen en riktig bild, där jag med binär thresholding har behållit alla föremål med vissa ljusvärden och sedan "öppnat bilden" (opening) för att bli av med några tusen pixlar som orsakats av brus (som annars skulle räknats som "kopplade komponenter" och tilldelats unika färger).
Arbetet med kopplade komponenter tog oväntat lång tid, men resultatet är väldigt praktiskt i många sammanhang. Exempelvis antar några författare att den största kopplade komponenten i bilden som är hudfärgad är användarens hand/arm, vilket verkar fungera bra.

Den nuvarande tanken för mitt projekt är att mjukvaran först genomgår en kalibreringsfas där användaren håller upp handen framför kameran. Snakes (aktiva konturer) är nuvarande det starkaste hoppet för att kunna följa handens form, men som bilden nedan visar skulle en väldigt enkel lösning vara att indikera ett område där alla pixlar antas vara hud och be användaren att hålla handen innanför.
Oavsett hur färgvärdena plockas ut så används den informationen sen för att uppskatta vilka färgvärden som antas tillhöra hudområden och vilka som inte gör det (färgmodellen tränas/kalibreras). Med hjälp av färginformationen och rörelse i bilden och/eller formen/texturen på objekt spåras sedan handen mellan varje bildruta. Detta har fördelen att området av bilden som behöver genomsökas blir mindre eftersom handen rimligtvis inte bör röra sig alltför långt mellan två bildrutor som kommer med cirka 0.03 sekunders mellanrum. Detta förutsätter dock att programmet hinner med att göra beräkningarna i realtid, eller att det är acceptabelt att köra långsammare (vilket det bör vara om ett existerande videoklipp används).

Det viktigaste som behövs just nu är robust kantdetektering, eftersom det som jag beskrivit vore bättre att inte behöva förlita sig på färginformation för att hitta handen, utan istället semi-automatiskt hitta handen och extrahera den informationen under kalibreringen.
Bilden ovan visar en snake med 25 punkter som knappt syns och förvirrat försöker inhägna inget i allmänhet, men tre av punkterna har ett "energilandskap" utritat kring sig. Varje punkt använder flera olika mått för att bestämma sin nya position men tanken är alltid att minimera energin, där måttet på "energi" är saker som att försöka hålla jämna avstånd till sina grannar, behålla en fin, rund form, söka sig mot ljusa föremål och kanter. Av de fyra måtten jag nyss nämnde visar de färgade områdena de första tre (röd - "ballongenergi", grön - "kontinuititetsenergi", blå - "intensitetsenergi"). De mörkare områdena inom de färgade grannskapen för punkterna visar vars energin är lägst, vilket är vars punkten vill röra sig. Det sista måttet på energi är att söka sig mot kanter, vilket är det viktigaste och något som jag inte har fungerande i alla olika situationer än (närmare bestämt i nerskalade/subsamplade bilder, vilket jag tänkt använda med snakes för att låta dom hierarkiskt söka sig till bättre anpassningar).

Jag har också utökat min faltningsfunktion i veckan för att bland annat hantera kanteffekter bättre genom att reflektera delar av bilden och skapa en större utökad version under operationen. Detta ledde oväntat nog till ett ganska roligt tidsfördriv, eftersom det inte är något som hindrar att man reflekterar 100% av bilden, live.

Min LCD-skärm är större än din (och mer självrefererande).
Det här är en del av ett fönster.
Nu är det vecka 35, vilket betyder att nästa vecka är den tionde och halva tiden för exjobbet är över nu. Det känns som om jag fått mycket gjort, men jag uppskattar att jag inte varit framsynt nog att inse hur mycket arbete vissa saker skulle kräva i förväg. Om jag hade vetat det i förväg är det inte lika säkert att jag kommit igång. Högst på dagsordningen nästa vecka står att ordna kantdetektering som fungerar bra vid låg upplösning, jag har några redan implementerade metoder som kan fungera, annars finns Canny. Utöver det vill jag få gråskalemorfologi att fungera, halvt av samma anledning (kantdetektering) och titta på om varians/standardfördelningen i bilden ger några ledtrådar till vilka områden som innehåller hud. Rapporten börjar hamna bakom det jag faktiskt gjort också, så förr eller senare borde jag gå över till att skriva mer och programmera mindre, men just nu vill jag få mer resultat.

2008-08-22

Vecka 34

Jag började under veckan att försöka få funktionen för att räkna kopplade komponenter att fungera, vilket är oväntat svårt med tanke på hur lätt det är att beskriva - man vill veta hur många föremål det finns i en bild där varje pixel endast kan vara en del av bakgrund eller förgrund. Det behövs två pass över bilden för att ge etiketter till alla föremål på ett entydigt sätt, med ett steg mellan där dubbeltydiga etiketter blir sammanslagna. Jag har fortfarande inte det sista steget fungerande, men jag har fått en utdrag ur en bok som beskriver hur man löser det som jag ska använda i början av nästa vecka.

Eftersom händer har en mycket mer varierande form än ansikten blir det troligtvis snakes (aka active contours/aktiva konturer) istället för active shape models (ASM) som jag kommer använda för att försöka spåra händernas form. Tanken bakom snakes är att man har ett antal punkter som har en ursprunglig position, som sedan uppdateras genom ett antal tendenser för ormen som att hålla avståndet mellan punkterna konstant, bilda "mjuka"/runda linjer, söka sig mot områden med viss färg och kontrastförändringar. Jag har implementerat en modell av snakes i veckan, men kantdetekteringen eller andra saker som ska ge den information vad den ska söka efter i sin omgivning för att lägga sig kring en hand fattas fortfarande.

Jag ägnade slutet av veckan åt att läsa och sammanfatta artiklar, främst yang99, akyol01 och holden05 om metoder för att hitta rörelse i bilder och hur snakes kan användas för att hålla isär hand och ansikte även när de överlappar varandra (dock med enfärgad mörk bakgrund och kontrollerade ljusförhållanden).

Nästa vecka kommer jag försöka få kopplade komponenterna att fungera och se om det går att använda statistiska mått på färgvärden i bilden som varians, kolla över mina snakes för att se hur de beter sig i olika situationer och se om det går att dra nytta av de olika måtten för rörelse som artiklarna tog upp. Planen är precis som tidigare att försöka plocka ut en grov uppskattning av hudfärgens fördelning med så få begränsningar på den miljö som förväntas som möjligt, genom att t.ex. be användaren hålla upp sin hand framför kameran och låta en snake lägga sig kring handflatan.

2008-08-15

Vecka 33

Största delen av veckan ägnade jag åt att skriva på rapporten, och det finns ett nytt utkast (även länkat från första sidan) som är mer aktuellt än det förra upplagt nu. Jag har beskrivit mänskligt färgseende och huddetektering med hjälp av färgvärden baserat på statiska, histogram, naiva Bayesiska och Gaussiska modeller. Eftersom de flesta metoderna var nya för mig tog det större delen av veckan att ta mig genom en sammanfattning av olika hudmodeller (kakumanu07 [PDF]) och beskriva de som var relevanta. Jag skrev också om system som spelar in multispektral data, med vilket i detta fall innebar att de fångade synligt ljus på massor av våglängder, inte bara tre stycken (R, G, B). De tre RGB-värdena i en vanlig bild räcker för att beskriva alla färger som människor uppfattar, men mänsklig hud har reflekterande egenskaper i ljus med andra vågländer som man går miste om. Slutpoängen var att de kunde kalibrera ett system som direkt såg skillnad på mänsklig hud och t.ex. en skyltdocka, även fast deras RGB-värden var identiska.

Jag programmerade även lite stödfunktioner i veckan som kommer behövas som matrismultiplikation och delar av ett läge som "spårar" händerna.
Funktioner som jag skrev som skalar ner upplösningen på en bild genom interpolering är tänkta att användas i ASM (Active Shape Models) för att förbättra uppskattningen av formen på föremål. Detta görs i en hierarki, där det översta lagret har mycket låg upplösning (160x120 eller 80x60) och försöker passa in formen av en hand, vilket bara resulterar i en suddig blobb, som förhoppningsvis är på ungefär rätt position. Nästa lager har högre upplösning och justerar punkterna kring kanten på föremålet, vilket när man är tillbaks på full upplösning med lite tur leder till en ganska bra anpassning till handen.

Tanken är att jag genom några antaganden om händernas placering och form ska försöka använda ASM eller någon liknande metod för att först hitta hudområden, som sedan ska användas till att bygga en modell av hudfärgens fördelning. På det sättet kan systemet förhoppningsvis kalibrera sig efter de faktiska förhållandena och bli mer robust för variationer. I ett färdigt system skulle det först kunna be användaren att hålla upp handen framför kameran och efter att kalibreringsfasen var över följa händerna någorlunda nogrannt. Det vore intressant att kombinera rörelse och färg (som jag redan undersökt till viss del) med form och kontinuitet över tid (en hand bör inte röra sig mer än ett visst antal pixlar mellan bildrutor) och se vilka resultat man får.

Under nästa vecka är min första prioritet att försöka få ASM eller liknande metod för att spåra former att fungera. Om och när det gör sitt jobb bör mitt system automatiskt kunna göra uppskattningar av fördelningen av färgvärde för hud och icke-hud över bilden, vilket kan användas av metoder jag redan har eller mer sofistikerade som Mahalanobis-avstånd. Det kräver vissa saker som jag redan har (matrismultiplikation, tröskling, mm) och vissa jag behöver konstruera (beräkning av kovariansmatris, invers av sådan..). Jag har också kvar att beskriva hudklassificering med SOM (Self-organizing maps) under huddetektering, vilket är en typ av neurala nätverk som lär sig att separera data i två klasser utan övervakning. Sen har jag också ett halvt dussin artiklar kvar att läsa, för att inte tala om avsnitten om att skriva om/implementera klassificeringsfeatures för tecken, men det får bli en sak i taget.

2008-08-08

Vecka 32

Oroligheterna inom företaget fortsätter och det är alltmer oklart vad framtiden kommer innehålla för Teligent. Stora nedskärningar har påbörjats under veckan och kontoret i Umeå har inte sluppit undan. Det kvarstår att se vad som kommer hända med företaget i allmänhet och med detta kontor, men jag har inte så många alternativ annat än att fortsätta med mitt arbete.

Jag ägnade mig under början av veckan åt att implementera morfologiska operationer i mängder, vilket började med erosion och dilation och fortsatte med opening, closing, boundary detection, hit-or-miss samt delar av andra operationer. Bilden nedan demonstrerar boundary detection (dvs kantdetektering), inklusive de problem med bakgrund som har jämförbar ljusintensitet som mig själv.
Med detta implementerat gjorde jag ett nytt försök med rörelsedetektering. Tidigare hade jag skrivit en enkel funktion som jämförde nuvarande bildruta med den föregående pixel för pixel och färglagde dom som förändrats tillräckligt mycket. Detta var mer eller mindre meningslöst eftersom nivån av bruset i bilden såg till att varenda pixel ständigt var i förändring. Det jag gjorde annorlunda nu var att plocka ut en referensbild när man byter till rörelsedetekteringsläget eller trycker R (reset). Vid varje efterföljande bildruta beräknas en "avståndskarta" (distance map) jämfört med referensen och om rörelse upptäcks färgläggs det området. På bilden nedan har jag jämfört med referensbilden höjt min arm. Märk väl att själva handen inte upptäcks, eftersom väggen i bakgrunden under lysrörsbelysningen och ljuset utifrån har i princip identisk färg som min hud och förändringen i färgvärde när handen rör sig inte är tillräcklig för att upptäcka den.
Ännu en bild nedan visar en binär mask där områden som har rörelse har värdet 0 (vita), medan övriga är 1 (svarta). Utöver rörelsedetekteringen har jag även lekt med morfologi genom att utföra en "öppning" (morphological opening) med ett ganska stort strukturelement. Detta resulterar i att detaljer som är mindre än strukturelementet försvinner, större objekt blir mer eller mindre opåverkade (vilket kan vara behändigt för att minska brus).
Det uppenbara testet var nu att kombinera rörelse med färgdetektering, så endast områden som rör på sig och matchar färgen hos hud finns kvar, vilket resulterade i bilden nedan.
Det ser väldigt lovande ut, bortsett från de kritvita regionerna som på grund av ljuset utifrån är för långt bort från hudfärg så plockas hud och endast hud ut (jag rörde inte min vänstra hand). Problemen kommer när man inser att "målvärdet" för vilken färg som motsvarar hud fortfarande påverkas kraftigt av belysning (både från lysrör och solen), samt att metoden inte kan se skillnad på en hudfärgat (från kamerans synpunkt) del av väggen där det tidigare fanns en axel eller något annat som rört sig och en yta som tidigare inte hade hud men nu har det. Jag tror dock att rörelse i kombination med färg-baserad detektering kan användas för att spåra händernas rörelse.

Utöver implementering (till viss del omstrukturering av tidigare kod som kunde förbättras) hade jag på torsdagen också första mötet med Fredrik Georgsson, min handledare inom universitetet. Vi kommer mötas veckovis framöver, vilket säkert kommer hjälpa mig att undvika att ägna tid åt kod eller kapitel som inte leder någonstans. Jag fick många intressanta förslag på saker jag borde testa och en hög artiklar, varav jag börjat läsa en hittils.

Det kan verka som om jag ägnar oproportioneligt mycket tid åt att försöka segmentera hudområden i den dåliga ljusmiljön som finns här, men eftersom jag när som helst skulle kunna förenkla processen genom att införa enfärgad (mörk) bakgrund och/eller ställa kameran i ett rum där belysningen inte ändras ser jag det som en utmaning att undersöka hur pass robust segmentering jag kan åstadkomma under svåra och varierande förhållanden innan jag börjar förenkla uppgiften. Inom några veckor vill jag dock kunna gå över till att beräkna features som ska klassificeras till det tecken som utförts, vilket kräver att segmenteringen fungerar någotsånär. Själva klassificeringen kommer om föregående steg är fungerande vara ganska enkel, men jag vill också hinna jämföra så många olika metoder som möjligt, så jag bör kanske inte vänta alltför länge.

Under nästa vecka kommer jag till att börja med försöka koda några förslag jag fått av Fredrik och också skriva på de delar av rapporten som berör olika metoder för att dela in bilder i områden med och utan hud. Jag kommer också fortsätta läsa de nytillkomna artiklarna och arbeta in deras resultat i rapporten.

2008-08-01

Vecka 31

Denna vecka har jag ägnat helt åt att implementera funktionalitet i den ordning som känns mest logisk. Jag började med att skriva rutiner för att läsa tangentbordstryckningar så jag dynamiskt kunde uppdatera inställningar för hur en enstaka bildruta skulle visas. Systemet som jag började med växte snabbt i komplexitet och i nuläget hanteras följande tangenter:
  • F1-F5 byter modes
  • 1-6 byter submodes
  • Pil upp/ner och vänster/höger ändrar värdet på två aktiva parametrar
  • Vänster CTRL, ALT, SHIFT och höger CTRL fungerar som modifiers
  • Q/Esc stänger ner programmet
Exempelvis innebär F4 att man byter till Post-processing mode, där en binär tröskling görs enligt en lägre och övre gräns för genomsnittligt färgvärde. Gränserna kan ändras med piltangenterna. Som standard är submode = 1 när man byter mode, men genom att byta till 2-5 kan man i Post-processing se olika varianter av kantdetektering, medan submode = 5 är en Gaussian smoothing (utjämning av brus). Jag har som detta antyder skrivit funktioner för att lagra matriser och utföra faltning (convolution) med godtyckliga kärnor (kernels) och också börjat på morfologiska funktioner.

Tidigt i veckan upptäckte jag att det var mycket enklare än förväntat att strömma video live från AXIS-kameran som jag använder, så jag anpassade mina funktioner till att manipulera och visa det kameran ser i realtid. Jag hittade också ett exempel på hur RGB kan användas för att rendera direkt med SDL, vilket var enormt mycket smidigare än den YUVOverlay (YCbCr) som jag tidigare använde. Jag har också implementerat konvertering till diverse format som HSI och normaliserad RGB. Utöver det redan nämnda fick jag också en ganska smidig snapshot-funktion att fungera, så man under körningen kan spara bilder i PPM eller BMP-format. Mot slutet av veckan skrev jag en mode för att interaktivt kunna kalibrera vilket målvärde för hud som systemet letar efter (korset styrs med piltangenterna), vilket syns på bilden nedan.
Den översta delen av skärmen indikerar vilket färgvärde som man pekar på. Segmenteringsdelen av systemet är ungefär likadant som förut och bör räcka till, förutsatt att inspelningsmiljön blir bättre. För att demonstrera vad jag menar visar bilden nedan hur det såg ut på eftermiddagen samma dag som jag kalibrerat systemet efter min uppfattade hudfärg.
Den hudfärg som kameran uppfattar har här ändrats ganska långt från det systemet letar efter (överst på bilden), enkom på grund av solens rörelse och att det blivit molnigare. Slutligen visar den tredje bilden nedan varför min inspelningsmiljö allmänt är problematisk.
De gröna områdena är de där systemet tror det finns hud. Utöver de korrekta kommer även stora delar av taket med eftersom lysrören belyser ytan på sådant sätt att alla uppfattade färgvärden som hud rimligtvis kan ha finns med någonstans på taket, från vitare än mig till ganska mörk. Detta är orsaken till att alla tidigare artiklar som jag hittat har genomförts i känd miljö utan ljuskällor på bilden. Alltså; när jag ska börja spela in träningsdata där systemet verkligen behöver kunna hitta hudområdena kommer jag behöva använda en annan miljö.

Nästa vecka kommer jag fortsätta implementera saker som känns viktiga, främst de morfologiska grundoperationerna, en region growing-algoritm för att testa den segmenteringsmetoden och någon metod för att räkna kopplade komponenter (connected components). Eventuellt kommer jag ägna någon dag åt att skriva om neurala nätverk, support vector machines eller tidigare artiklar så jag har lite mer att komma med om jag skickar in ett uppdaterat utkast till rapporten under veckan.