Convert a Color Image to a Gray Scale Image in Java

This Java tutorial shows how to convert a color image to a gray scale image in Java. In Java, there are a number of ways to convert a color image to gray scale. This tutorial will show you three ways convert the image including output quality and performance.

For reference, below is the color image that was converted:

Changing the Color Space
One way to convert a color image to gray scale, is to change the color space of the image. The sample code below shows how to change the color space:

ColorSpace cs = ColorSpace.getInstance(ColorSpace.CS_GRAY);
ColorConvertOp op = new ColorConvertOp(cs, null);
BufferedImage image = op.filter(bufferedImage, null);

Performance: Poor (approx. 60ms)
Image Results: Poor


Drawing to a Grayscale BufferedImage
The easiest way to convert a color image to a gray scale image is to simply draw the color image to a gray scale BufferedImage. The sample code below shows how to draw the colored image to a gray scale BufferedImage:

BufferedImage image = new BufferedImage(width, height,
BufferedImage.TYPE_BYTE_GRAY);
Graphics g = image.getGraphics();
g.drawImage(colorImage, 0, 0, null);
g.dispose();

Performance: Good (approx. 9 ms)
Image Results: Best


Using the GrayFilter
The final way to convert a color image to a gray scale image is to use the GrayFilter. In order to use the GrayFilter, the color image must either be an ImageProducer or a BufferedImage (use the getSource() method to get the ImageProducer). The sample code below shows how to use the GrayFilter:

ImageFilter filter = new GrayFilter(true, 50);
ImageProducer producer = new FilteredImageSource(colorImage.getSource(), filter);
Image mage = this.createImage(producer);

Performance: Best (approx. 1 ms)
Image Results: Good. When constructing the GrayFilter, you can control the brightness of the grays with the second parameter.

Which Method Should You Use
The low quality and slow performance, should rule out using the ColorSpace method. If you need the best performance and can live with the image quality, the GrayFilter would be the option for you. Drawing to a gray scale BufferedImage is the overall best option, it is only a few milliseconds slower than the best, the image quality is the best, and the code is the simplest.


11 comments:

bitkidoku said...

Nice article, just what I wanted.

You didn't include all the implementation notes and stuff. simple, yet very effective.

Thank you again.

Mohd Rafiulddin Marzuki said...

how to implement the code?..can u give me full code example of it.. i really blur about this...i take a snapshot using

byte[] image = videoControl.getSnapshot("encoding=jpeg")

i hope u can help me..thanks..

You Know Phoo said...

Hey dude.. the code was inofrmative.. But cn u gimme where to implement it??? V r working on a title hw to convert JPEG images to PGM....

//import java.io.*;
import javax.media.jai.*;
import javax.imageio.ImageIO;

public class ConvertSpeed
{
private static String inputFileName = "C:\\Program Files\\balloon.jpg";
private static String outputFileName = "C:\\Program Files\\balloon.pgm";

public static void main(String args[])
{
System.out.println("Start....");
File inputFile = new File(inputFileName);

RenderedOp src = JAI.create("fileload", inputFile.getAbsolutePath());
FileOutputStream stream = null;
try
{
stream = new FileOutputStream(outputFileName);
ImageIO.write(src, "pgm", stream);
}
catch(IOException ioe)
{
System.out.println(ioe);
}

System.out.println("Done.");
}
}//


This s our code.. it compiles well but shows me error at 15th line whil running!!!


Cn u ping me back at kehakartik@gmail.com


Thnks!!!

photo restoration said...

Extremely informative article, well researched and clearly presented. I am thankful Gizmo took the time to share this informative post.

Anonymous said...

I think you forgot to mention the memory overhead for transformation #2 and #3 (additional ImageBuffer in memory)...
transformation #1 should be less memory consuming than the others.

regards

Anonymous said...

Very helpful example, but I get different performance results with method 1 and 2. Method 1 took me 47 ms and method 2 took 78 ms to transform one 580x580 color image to grayscale.

Miraj said...

Thanks for sharing!

Anonymous said...

Thanks for sharing! I'd like to use #2, however transparency is lost :(.

Anonymous said...

In hope for everything to be useful, here is the code that creates new instance of grayscale transparent image:

ColorSpace gsColorSpace = ColorSpace.getInstance(ColorSpace.CS_GRAY);

ComponentColorModel ccm = new ComponentColorModel(gsColorSpace, true, false,
Transparency.TRANSLUCENT, DataBuffer.TYPE_BYTE);

WritableRaster raster = ccm.createCompatibleWritableRaster(width, height);

Image result = new BufferedImage(ccm, raster, ccm.isAlphaPremultiplied(), null);

Anonymous said...

When using JAI, a BandCombine operation that calculates the luminance gives off a great gray scale image at decent speed.

PlanarImage gray = JAI.create("bandcombine",image,new double[][] { 0.299, 0.587, 0.114, 0.0 } });

Maarten said...

@Anonymous(April 27, 2010 6:03 PM)

Oh wow, thanks so much for that transparent grayscale code. It's a real life saver when making 'disabled' icons.

Post a Comment