Specialeffekter och spelutveckling
i Java(TM) - Suddfiltret (BlurImage)
av Anibal Wainstein
7.1.3 Suddfiltret (BlurImage)
En
annan mycket nyttig filter är suddfiltret. Den gör
bilden suddig genom att låta varje pixel påverkas
av de 8 pixlarna runt omkring den. Man beräknar medelvärde
på varje färgkomponent hos 9 pixlar i en kvadratisk
område och sätter pixeln i centrum till resultatet
av beräkningen. Gör man detta för varje pixel
i bilden så får man en suddig bild.
x-1,y-1 |
x,y-1 |
x+1,y-1 |
x-1,y |
x,y |
x+1,y |
x-1,y+1 |
x,y+1 |
x+1,y+1 |
I pixeln (x,y) kommer att vi all lagra medelvärdet
av färgomponenterna av alla de 9 pixlarna.
Medelvärdet
räknar vi ut genom att summera de 9 röda färgkomponenterna
och dela med 9. Samma sak gör man med de gröna och
blåa färgkomponenterna. Pixeln (x,y) kommer efter
det att sättas till resultatet. Men nu står vi
inför ett problem, vad händer t.ex. om x=0? Då
finns det inga pixlar till vänster om pixeln (x,y) som
vi kan använda i medelvärdet! P.g.a. detta måste
vi därför lägga till IF-satser som kollar.
När vi bara kan arbeta med 6 pixlar, så summerar
vi deras komponenter och delar med 6 helt enkelt. Den här
gången går det inte heller att realisera den här
behandlingen med en enda FOR-slinga som gå igenom alla
pixlar, det blir för komplicerat. Observera att vi kan
behöva läsa färgkomponenterna för varje
pixel 9 gånger. Därför bör vi lagra alla
färgkomponenter i tre arrayer, en för varje RGB-komponent,
innan bildbehandlingen börjar. Detta gör vi så
att vi slipper maskera och skifta varje pixel 9 gånger
för att komma åt komponenterna. Vi
går igenom två steg i bildbehandlingsprocessen:
1.
Vi delar upp de tre färgkomponenterna för VARJE
pixel och lagrar dem i arrayerna "lr", "lg"
och "lb".
2.
Två FOR-slingor går igenom varje pixel i bilden
och IF-satser lägger till färgkomponenter till slutresultatet
beroende på vilken pixel vi behandlar just nu (om den
är en kantpixel eller inte). Resultatet divideras med
antalet pixlar som har manipulerats och stoppas i "pixels"
arrayen istället för centerpixeln (x,y).
Nu
kan vi använda filen grayimage.java som vi skrev för
det förra exemplet och ändra "gray" till
"blur". Vi ersätter metoden grayImage() med
följande:
public Image blurImage(Image img)
{
//Skapa en array för att lagra bildens pixlar och
//hämta dem.
Dimension d=new Dimension(img.getWidth(this),img.getHeight(this));
int pixels[]=new int[d.width*d.height];
PixelGrabber grabber
=new PixelGrabber(img,0,0,d.width,d.height,pixels,0,d.width);
try {grabber.grabPixels();} catch(InterruptedException e){};
//Variabeln "div" används för att dividera
//summan av alla komponenterna.
int div;
//Det är bäst att vi först skapar tre
//arrayer för att lagra färgkomponenterna
//så att bildbehandlingen snabbas upp.
//Storleken på dessa arrayer måste vara
//samma som antalet pixlar i bilden.
int lr[]=new int[d.width*d.height];
int lg[]=new int[d.width*d.height];
int lb[]=new int[d.width*d.height];
//Vi använder en enkel FOR-slinga för att
//gå lagra varje komponent.
for (int index=0; index<d.width*d.height; index++) { //Vi struntar i alfa kanalen så den //här metoden kommer bara att fungera //med transparenta bilder. lr[index]=(pixels[index]&0xff0000)>>16; lg[index]=(pixels[index]&0xff00)>>8; lb[index]=pixels[index]&0xff; }
//Vi använder två FOR-slingor för bildbehandlingen //den här gången. int r,g,b; for (int x=0; x<d.width; x++) { for (int y=0; y<d.height; y++) { //Börja med att sätta d=1 och //sätta r,g,b till pixeln //(x,y) r=lr[x+y*d.width]; g=lg[x+y*d.width]; b=lb[x+y*d.width]; div=1; if (x>0) { //Lägg till pixeln till vänster //om pixeln i mitten. r+=lr[(x-1)+y*d.width]; g+=lg[(x-1)+y*d.width]; b+=lb[(x-1)+y*d.width]; div++; if (y>0) { //Lägg till pixeln ovanför //och längst upp till vänster //om pixeln i centrum. r+=lr[x+(y-1)*d.width]; g+=lg[x+(y-1)*d.width]; b+=lb[x+(y-1)*d.width]; r+=lr[(x-1)+(y-1)*d.width]; g+=lg[(x-1)+(y-1)*d.width]; b+=lb[(x-1)+(y-1)*d.width]; div+=2; } if (y<d.height-1) { //Lägg till pixeln nedanför //och längst ner till vänster //om pixeln i centrum. r+=lr[x+(y+1)*d.width]; g+=lg[x+(y+1)*d.width]; b+=lb[x+(y+1)*d.width]; r+=lr[(x-1)+(y+1)*d.width]; g+=lg[(x-1)+(y+1)*d.width]; b+=lb[(x-1)+(y+1)*d.width]; div+=2; } } if (x<d.width-1) { //Lägg till pixeln till höger //om pixeln i mitten. r+=lr[(x+1)+y*d.width]; g+=lg[(x+1)+y*d.width]; b+=lb[(x+1)+y*d.width]; div++; if (y>0) { //Lägg till pixeln längst //upp till höger //om pixeln i centrum. r+=lr[(x+1)+(y-1)*d.width]; g+=lg[(x+1)+(y-1)*d.width]; b+=lb[(x+1)+(y-1)*d.width]; div++; } if (y<d.height-1) { //Lägg till pixeln längst //ner till höger //om pixeln i centrum. r+=lr[(x+1)+(y+1)*d.width]; g+=lg[(x+1)+(y+1)*d.width]; b+=lb[(x+1)+(y+1)*d.width]; div++; } } //Vi måste dividera med "div" som //egentligen bara säger hur många //pixlar vi har manipulerat. r/=div; g/=div; b/=div;
//Till sist så bygger vi upp pixelvärdet igen.
pixels[x+y*d.width]=0xff000000+(r<<16)+(g<<8)+b;
}
}
//Nur återstår bara att återskapa bilden och returnera den.
MemoryImageSource imgsrc
=new MemoryImageSource(d.width,d.height,pixels,0,d.width);
img=createImage(imgsrc);
return img;
}
Observera
att alfa-kanalen kommer att bli bortfiltrerat, så använd
inte det här filtret på transparenta bilder.

Bilden
"montevideo.jpg" kommer att bli suddig.
Använd
samma HTML fil
döp om "grayimage" till "blurimage"
överallt i HTML-koden. Klicka
här för att se en suddig version av ovanstående
bild.
|
 |  |
|