Hem E-böcker Specialeffekter och spelutveckling i Java Suddfiltret (BlurImage) 

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.