Hem E-böcker Specialeffekter och spelutveckling i Java Gråfiltret (GrayImage) 

Specialeffekter och spelutveckling i Java(TM) - Gråfiltret (GrayImage)

av Anibal Wainstein

7.1.2 Gråfiltret (GrayImage)

Den störste applet-pionjären genom tiderna inom bildbehandling och 3D, är den norske programutvecklaren och frilansjournalisten Tonny Espeset. Redan 1996 (ett år efter att Java-språket skapades) skrev han boken Kickass Java Programming (publicerad av Coriolis group Inc.) som är fylld av bildbehandling- och 3D-programmeringsexempel som var långt före sin tid. Han visade med sina fantastiska exempel den verkliga styrkan med Java och gav inspiration åt många andra Java programmerare (jag räknar mig själv som en av hans "lärjungar"). Idag driver han programföretaget Plutonium Software där du kan se många exempel på avancerad bildbehandling och 3D i Java. Tyvärr är boken slutsålt och Tonny har inga planer på att släppa en nyutgåva. Men för er olyckliga läsare som inte har lyckats få tag i boken så kan den här kapitlet vara lite till tröst, även om den inte ens med en bråkdel täcker områderna som Kickass Java Programming går igenom. Vi skall nu gå igenom en gråfiltermetod som baseras på ett exempel i Kickass Java Programming. Som jag sade innan i avsnitt 7.0.5 så har RGB-komponenterna samma värde hos färgerna i en gråskala. Nu kanske du tänker att man skulle kunna göra om en bild till grå genom att bara räkna ut ett medelvärde av de tre RGB komponenterna och sätta var och en av dem till resultatet? Det fungerar men resultatet blir inte så bra. RGB komponenterna har olika effekter på den mänskliga ögat. Grönt är t.ex. mycket starkare än blått. Därför måste man se till att grönt får större "inflytande" i medelvärdet som räknas ut. Det optimala resultatet får man om man tar 3/9 delar rött, 4/9 delar grönt och 2/9 delar blått:

int pixelvalue=0xff2f3f4f;

//Ta fram varje komponent för sig så att vi 
//kan räkna ut ett medelvärde, alfakanalen rör vi inte
//så den behöver vi inte skifta.
int alfa=(pixelvalue&0xff000000);
int r=(pixelvalue&0x00ff0000)>>16;
int g=(pixelvalue&0x0000ff00)>>8;
int b=pixelvalue&0x000000ff;

//Räkna ut det speciella "medelvärdet" för de 
//tre RGB-komponenterna. Utför multiplikationerna
//först.
int mv=(3*r+4*g+2*b)/9;

//Bygg upp pixelvärdet, varje färgkomponent ersätts med
//resultatet, "mv".
pixelvalue=alfa+(mv<<16)+(mv<<8)+mv;

Metoden grayImage() tar en bild (Image-objekt) som argument och lämnar tillbaka en bild:

public Image grayImage(Image img)
{
    //Skapa en array för att lagra bildens pixlar.
    Dimension d=new Dimension(img.getWidth(this),img.getHeight(this));
    int pixels[]=new int[d.width*d.height];

    //Lagra pixlarna i arrayen med hjälp av PixelGrabber-
    //klassen.
    PixelGrabber grabber
        =new PixelGrabber(img,0,0,d.width,d.height,pixels,0,d.width);
    try {grabber.grabPixels();} catch(InterruptedException e){};

    int r,g,b,alfa,mv;

    //For-slingan går igenom hela arrayen
    //och gör om alla färgvärden till grå-skalor.
    //Observera att här använder vi en enda for-slinga, ty
    //den här effekten är inte beroende av x- eller y positionen
    //av den pixel man beräknar.
    for (int index=0; index<d.width*d.height; index++)
{
//Först tar vi fram varje komponent så att
//vi kan arbeta med dem.

alfa=pixels[index]&0xff000000;
r=(pixels[index]&0xff0000)>>16;
g=(pixels[index]&0xff00)>>8;
b=pixels[index]&0xff; //Nu räknar vi ut gråmedelvärdet. mv=(3*r+4*g+2*b)/9; //Till sist så bygger vi upp pixelvärdet igen. pixels[index]=alfa+(mv<<16)+(mv<<8)+mv; } //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; }

Hela bildbehandlingsproceduren har kapslats in i den här metoden. Först hämtar vi pixlarna med PixelGrabber, vi bildbehandlar med FOR-slingan och till sist återskapar vi bilden med MemoryImageSource och skickar tillbaka den. Observera att den här gången använder jag bara en FOR-slinga för att gå igenom pixelarrayen. Till skillnad från Gradient-exemplet så är den här effekten inte beroende av x eller ypositionen för pixeln man behandlar. Förresten så går det mycket snabbare att bara använda en slinga istället för två. Så här ser resten av appletkoden ut:

import java.applet.*;
import java.awt.*;
import java.awt.image.*;

public class grayimage extends Applet {

//"blueimage" kommer att hålla reda på
//bilden som vi skapar.
Image image=null;

public void init()
{
    //Ladda in bilden (filnamnet finns i
    //parametern "image").
    MediaTracker tracker=new MediaTracker(this);
    image=getImage(getDocumentBase(),getParameter("image"));
    tracker.addImage(image,0);
    try {tracker.waitForAll();}
    catch(InterruptedException e){}

    //Nu anropar vi metoden grayImage()
    //för att göra om bilden till en gråskala.
    image=grayImage(image);
}

public void paint(Graphics g)
{
    if (image!=null) g.drawImage(image,0,0,this);
}

//...(lägg in grayImage() metoden här)...

}

Nu ser du hur lätt man kan använda metoden grayImage(). Det är en nyttig metod som också kan användas för knappmenyer. Vi kommer att använda följande bild för att experimentera med appleten:


Bilden "buenosaires0.jpg" som vi kommer att göra om till grått.

Använd HTML filen som du gjorde för appleten BlueComponent och döp om "bluecomponent" till "grayimage" överallt i HTML-koden. Klicka här för att se resultatet.


Nästa sida >>