Flervariabelanalys, inriktning bildbehandling, datorövning 3

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