The Source for Java Technology Collaboration
User: Password:



Start New Message Delete Post a Reply

Article: 
 Java Tech: Image Embossing
Subject:  Convolution
Date:  2005-12-08 10:21:13
From:  javajeff
Response to: Convolution


Hello,

I suppose you could perform embossment by using only a ConvoleOp and a ColorConvertOp. In fact, I did a Google search that revealed a kernel for performing embossment via a ConvolveOp. I took that kernel, used it as the basis of a ConvolveOp, filtered the source image with that op, created a ColorConvertOp based on a grayscale colorspace, and then filtered the
embossed image so that it would look more metalic. The emboss() method containing the resulting code appears below:


private BufferedImage emboss (BufferedImage src)
{
Kernel kernel = new Kernel (3, 3, new float [] { -2, 0, 0, 0, 1, 0, 0, 0, 2 });
BufferedImageOp op = new ConvolveOp (kernel);
BufferedImage tmp = op.filter (src, null);

ColorConvertOp grayOp = new ColorConvertOp (ColorSpace.getInstance (ColorSpace.CS_GRAY), null);
return grayOp.filter (tmp, null);
}


I wasn't happy with the result -- even when I first performed the grayscale followed by the convolution, the resulting image just didn't look embossed to me. Perhaps another kernel would yield a better result. If you have such a kernel, I'd
appreciate examining it.

Another problem with the above method is that the kernel may be difficult to understand by those new to embossing and Java 2D's image-processing architecture. In contrast, I believe my algorithm is easier to understand.

However, I should have gone one step further in the article -- introduce a custom EmbossOp class based on the BufferedImageOp interface, and have that class's filter() method carry out my algorithm. Like the EmbossedIcon class, that would have provided another way to easily introduce embossing into Java programs. Because I failed to provide that class in the article,
I am providing it below. (NOTE: Apart from the filter() method, the implementations for the other four methods in the class below are taken from code found in Jonathan Knudsen's excellent "Java 2D Graphics" book -- ISBN: 1-56592-484-3, 1999,
O'Reilly. If you don't have this book in your library, and if it is still available, I recommend getting yourself a copy.)


class EmbossOp implements BufferedImageOp
{
public final BufferedImage filter (BufferedImage src, BufferedImage dst)
{
if (dst == null)
dst = createCompatibleDestImage (src, null);

int width = src.getWidth ();
int height = src.getHeight ();

for (int i = 0; i < height; i++)
for (int j = 0; j < width; j++)
{
int current = src.getRGB (j, i);

int upperLeft = 0;
if (i > 0 && j > 0)
upperLeft = src.getRGB (j - 1, i - 1);

int rDiff = ((current >> 16) & 255) - ((upperLeft >> 16) & 255);
int gDiff = ((current >> 8) & 255) - ((upperLeft >> 8) & 255);
int bDiff = (current & 255) - (upperLeft & 255);

int diff = rDiff;
if (Math.abs (gDiff) > Math.abs (diff)) diff = gDiff;
if (Math.abs (bDiff) > Math.abs (diff)) diff = bDiff;

int grayLevel = Math.max (Math.min (128 + diff, 255), 0);
dst.setRGB (j, i,
(grayLevel << 16) + (grayLevel << 8) + grayLevel);
}

return dst;

}

public BufferedImage createCompatibleDestImage (BufferedImage src,
ColorModel dstCM)
{
BufferedImage image;
if (dstCM == null)
dstCM = src.getColorModel ();

int width = src.getWidth ();
int height = src.getHeight ();
image = new BufferedImage (dstCM,
dstCM.createCompatibleWritableRaster (width, height),
dstCM.isAlphaPremultiplied (), null);
return image;
}

public final Rectangle2D getBounds2D (BufferedImage src)
{
return src.getRaster ().getBounds ();
}

public final Point2D getPoint2D (Point2D srcPt, Point2D dstPt)
{
if (dstPt == null)
dstPt = new Point2D.Float ();
dstPt.setLocation (srcPt.getX (), srcPt.getY ());
return dstPt;
}

public final RenderingHints getRenderingHints ()
{
return null;
}
}
</pre>

Using EmbossOp in EmbossIcon's emboss() method is extremely simple, as the following emboss() method reveals:


private BufferedImage emboss (BufferedImage src)
{
EmbossOp op = new EmbossOp ();
return op.filter (src, null);
}


I recommend enhancing EmbossedOp to emboss from different directions.

Jeff

 Feed java.net RSS Feeds