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 >>
|