Matematiska institutionen, LTH, December 2, 2004 Flervariabelanalys, inriktning bildbehandling, datorövning 3 Matlab Gå till underkatalogen matlab (skapa den om den inte redan finns) av din rotkatalog. Kopiera dit alla filerna du inte redan har. Faltning Flera operationer man vill göra på bilder kan beskrivas som faltningar alternativt korrelation. Hit hör t ex lågpassfiltrering (utjämning), högpassfiltrering (skarpare bild) och kantdetektering. Faltningar är mycket enkla att göra i Matlab. Ett filter kan man ange som en matris, t ex >> medel=[1 1 1;1 1 1;1 1 1]/9 Sedan faltar man med rutinen conv2 , t ex utbild=conv2(inbild,medel) Utbildens gråskalenivåer ligger inte alltid mellan 0 och 255, och det är därför lämpligt att använda kommandot imagesc för att se på den. Detta kommando transformerar minimum i bilden till 0 och maximum till 255. När man faltar har man ofta problem med randeffekter. Bilden har ju begränsad utsträckning. Det är inte självklart hur man skall definiera faltningen vid kanten av bilden. I rutinen conv2 utvidgas bilden som i kompediet med nollor, och utbilden blir därför lite större än inbilden. En speciell användning av lågpassfiltrering är brusreducering. Hämta och ladda in bilden pkalle.pgm med kommandot >> pkalle = readpgm(’pkalle.pgm’); och titta på den före och efter filtrering med medelvärdesfiltret medel. Som synes försvinner bruset men tillsammans med det också alla finare detaljer i bilden. För gråskalebilder skriver man lämpligen också >> colormap gray Några andra vanliga filter är • Derivering i x-led: derx = [-1 1] • Derivering i y-led: dery = [-1;1] • Laplacefilter: laplace = [0 1 0;1 -4 1;0 1 0] 1 Notera att i den här laborationen så pekar x-axeln horisontellt åt höger och y-axeln pekar vertikalt nedåt. Prova derivering i x-led och i y-led samt diskret laplacefilter på bilden pkalle. Genom att använda dessa metoder kan man få en hyfsad kantdetektor. Tyvärr blir den ganska bruskänslig. Hitta ansikten i bilder En enkel metod att hitta objekt i bilder är att använda sig av korrelation, där filtret är en mall av det man vill känna igen. Ladda in en bild och en mall >> load korrdata; Mallen består av en suddig bild av ett ansikte. Se på denna genom att skriva >> imshow(uint8(suddansikte)); Vi ska nu försöka hitta detta ansikte i bilden staty, och för detta har vi skrivit ett enkelt program, hitta.m. Titta på programmet, t.ex. med >> type hitta och prova det sedan genom att skriva (det kan ta rätt lång tid) >> hitta(staty, suddansikte); Trots det mycket enkla tillvägagångssättet får vi i detta fall ett bra resultat (lägg märke till att vi hittar ”rätt” ansikte). Som generell metod är denna dock inte särskilt stabil. Bildrestaurering Vid bildrestaurering så utgår man från en bild som har distorderats på något sätt. Har man en modell för hur distordering uppkommit kan man använda den för att försöka återskapa den odistorderade bilden. Här utgår från en bild som degraderats på grund av likformig rörelse av kameran. Vi förutsätter också att man exakt känner rörelsens riktning och längd. Ladda in bilden >> rickKalle1 = readpgm(’rickKalle1.pgm’); För att simulera rörelseoskärpa i x-riktningen kan man falta bilden med en funktion av formen ( 1, 0 ≤ x ≤ a, y = 0 h(x, y) = 0, annars. Detta kan ni göra med ett skript blurra.m. Detta samplar även ner bilden till formatet 256×256, för att räkningarna inte skall ta för lång tid. Kör blurra med kommandot >> rickBlurr = blurra(rickKalle1); och se på resultatet med >> imagesc(rickBlurr); 2 Det går att approximativt få tillbaka ursprungsbilden rickKalle1 från rickBlurr om man känner filtret h(x, y). Metoden för att beräkna urspungbilden involverar derivatan av den blurrade bilden, så man kan misstänka att metoden är bruskänslig. Restaureringsmetoden finns färdigprogrammerad i skriptet avblurra.m. Titta på skriptet med kommandot >> type avblurra Kör skriptet med >> rickAvBlurr = avblurra(rickBlurr); Titta på den avblurrade bilden rickAvBlurr. Resultatet bör bli ganska hyfsat, men prova nu att lägga på lite normalfördelat brus på bilden innan du ”avblurrar” den. Detta kan du göra genom >> sig = 5; >> g = rickBlurr + sig*randn(size(rickBlurr)); Avblurra sedan bilden g. För att få en uppfattning om vad brus av denna storlek innebär i en bild så lägg samma brus som ovan på den skarpa bilden rickKalle1 och se på resultatet. Tror du att det skulle gå att ta bort riktig rörelseoskärpa med den här metoden? Kantdetektering I avsnittet om faltning presenterades filter för partiell derivata i horisontell led (x-led) and vertikal led (y-led). Dessa filter är enkla och går snabbt att räkna med för en dator men tyvärr är de ganska bruskänsliga. Det finns flera exempel på filter som är mer praktiskt användbara. För derivator i x-led kan man t ex använda Sobel- respektive Prewitt-maskerna av storlek 3 × 3: −1 0 1 −2 0 2 −1 0 1 −1 0 1 −1 0 1 . −1 0 1 Motsvarande Sobel-operator av storlek 5 × 5 är 1 2 2 2 1 2 4 6 4 2 0 0 0 0 0 −2 −4 −6 −4 −2 −1 −2 −2 . −2 −1 Deriverande filter i y-led fås genom transponering av ovanstående filter. Ofta vill man att kantdetektorn ska bestämma vilka bildelement som utgör en kant och vilka som inte gör det. En sådan kantdetektor kan man få genom att först filtrera med något lämpligt filter och sedan tröskla resultatet. En typisk kantdetektorrutin skulle kunna se ut så här: % kantprewitt.m % KANTPREWITT - Kantprewitt är en kantdetektor baserad på 3 % % In: inbild % troeskel % Ut: utbild Prewittmaskerna. : Den bild som kanter ska detekteras ur. : Tröskelvärde. : Den trösklade bilden som innehåller kanter prewitt3x=[ -1 0 1; -1 0 1; -1 0 1]; prewitt3y=prewitt3x’; derx = conv2(inbild,prewitt3x); dery = conv2(inbild,prewitt3y); gradabs = sqrt(derx.^2+dery.^2); gradarg = atan2(dery,derx); utbild=( gradabs > troeskel); Resultatet efter faltning med prewitt3x har stort belopp där bilden ändrar sig mycket i x-led. Genom att titta på absolutbeloppet på den approximativa gradienten, får vi ett resultat som är känsligt för kanter både i horisontell och vertikal led. Tillverka tre olika kantdetektorer baserad på sobel, prewitt och laplace-maskerna. Detta gör du lämpligast genom att tillverka tre nya filer med filändelsen .m. Du startar en editor från matlab genom att skriva >> edit En något mer avancerad kantdetektor baserad på en ide av Canny finns i matlabrutinen canny, som anropas med utbild = canny(inbild,troeskel). Den fungerar väsentligen på samma sätt som kantprewitt, d v s först faltning och sedan tröskling. Canny har utarbetat filter som är optimala i någon mening. Testa sedan de fyra kantdetektorerna på någon bra bild. Om du inte har någon egen så kan du ladda in en med load klossar, där bilden hamnar i variabeln klossar. Det är ofta svårt att bestämma lämpliga tröskelvärden. En mycket grov gissning är sobel: prewitt: laplace: canny: troeskel=500; troeskel=100; troeskel=40; troeskel=0.2; I de egenhändigt tillverkade kantdetektorerna är det lätt att testa nya tröskelvärden med >> imagesc(gradabs > troeskel); Undersök speciellt vad som sker när man ändrar tröskelvärdet. Beror resultatet mycket på valet av tröskelvärde? Är något tröskelvärde mycket bättre? Vilken detektor fungerar bäst? Matlab har också en egen funktion för att detektera bilder, som heter edge. Testa den på samma bild som ovan och jämför med de andra. 4 Bildkomprimering Vi ska här komprimera bilder på det sätt som beskrivs i kompediet. Läs gärna igenom avsnittet om du inte redan gjort det. Metoden bygger på att man approximerar en bild som en linjärkombination av andra bilder. Ladda in bilden rickKalle2.jpg genom att skriva >> rickKalle = imread(’rickKalle2.jpg’); Titta på bilden med kommandot imagesc. Välj en kompressionsgrad 0 ≤ c ≤ 1. Komprimera den sen med >> rickKalleC = Compress(rickKalle, c); Prova med lite olika c och se hur den komprimerade bilden ’rickKalleC förändras. Den ursprungliga och den komprimerade bilden visa automatiskt. Parametern c anger hur stor del av den ursprungliga datamängden som bilden rickKalle upptar som försvinner. Vid c = 0.5 sparas hälften så mycket data som för den ursprungliga bilden. Subpixeldetektering När man vill ha stor noggrannhet i sina beräkningar räcker det inte alltid att räkna med hela pixlar. För att kunna få subpixelprecision måste vi kunna interpolera fram bildintensiteter i ’decimalkoordinater’, dvs kunna svara på vilket värde bildmatrisen har t ex i (10.8,23.2). Det finns många interpoleringsmetoder, t ex pixelreplikering, bilinjär-, kubisk spline-, normalfördelnings- och sinc interpolering. I denna laboration skall vi använda interpolering med en normalfördelningsfunktionen 2 2 gσ (x) = e−x /σ och endast göra det i x-led. Parametern σ anger hur ’bred’ funktionen gσ (x) är. Denna metod ger samtidigt en utjämning av bilden vilket är önskvärt i många sammanhang. Låt nu f (k) vara en diskret bild definierad i alla heltal. Intensiteten i en punkt beräknas nu som summan av alla intensiteter i bilden viktade med en normalfunktion med centrum i punkten vi vill bestämma intensiteten i, dvs X h(x) = f (k)gσ (x − k). k Bredden σ avgör hur mycket utjämning som görs. Notera att det här inte rör sig om intepolering i den bemärkelsen som vi har behandlat tidigare i kursen eftresom h(k) 6= f (k) här, dvs den interpolerade funktionen och den ursprungliga stämmer inte överens i heltalspunkterna. Derivatan i en punkt given med ’decimalkoordinater’ kan bestämmas som X h0 (x) = f (k)gσ0 (x − k) k För endimensionella signaler kan kanter definieras som lokala maximi i derivatan av intensiteten. De lokala maximana bestäms t ex med Newtons metod. En rutin för kantdetektering för en rad på subpixelnivå finns implementerad i rowedges.m. Prova denna för flera rader i en bild t ex genom skriptet >> b=1.2 5 >> threshold=10; >> edgedata=[]; >> for rownr=180:260; row=bild(rownr,:); edgeposfine=rowedges(row,b,threshold); edgedata=[edgedata [edgeposfine;rownr*ones(size(edgeposfine))]]; >> end >> figure >> colormap(gray(256)); >> hold on; >> imagesc(bild); >> rita(edgedata,’r+’); >> zoom on Du kan också lägga in skriptet i en fil. 6