views:

121

answers:

2

I have asked this question before, but I wanted to rephrase/clarify some points and expand upon it. I have a piece of code which transforms a BufferedImage using an AffineTransform.

op = new AffineTransformOp(atx, interactive ? interpolationInteractive : interpolationNormal);
displayImage = op.filter(displayImage, null);

This code works fine, however it causes a memory accumulation. Specifically, every time this piece of code is called more memory is stored up. I have tried the other form of filter as well.

op = new AffineTransformOp(atx, interactive ? interpolationInteractive : interpolationNormal);
displayImage2 = op.createCompatibleDestImage(displayImage, displayImage.getColorModel());
op.filter(displayImage, displayImage2);

However, this is much much slower than the first version. I want the speed of the first version with the memory usage of the second.

  1. How can I clean up after the first version? Specifically, where are the intermediate BufferedImages stored, and how can I delete them?
  2. Why is the second version slower than the first? What can I do to speed it up?

Thanks for your help!!!

A: 

I agree with the comment that unless you're getting OutOfMemoryErrors, then this is a normal thing and the GC will collect the images whenever it sees fit. Here's a silly test I did sometimes when I had a concern: put that into loop in a main function and watch the memory usage in a profiler (it should make a zig-zag-like pattern or something) but not always be able to complete successfully.

Amber Shah
I am getting out of memory issues. I was able to slow it down by running System.finalization and System.gc when the memory got too high (I have a thread which tracks memory management).
Jon
If you have it working now, then that's fine, although it's concerning to me that you have a thread tracking memory management - it's like you're trying to re-create Java's memory management and it won't be as good anyways. This will sound silly, but are you not allocating enough space on the heap? When I was using a lot of image tranforms, I had to allocate 512 or 1024, I think, before it was a comfortable user experience. You can also set many parameters related to memory and the GC in the JVM - try here: http://java.sun.com/docs/hotspot/gc5.0/gc_tuning_5.html
Amber Shah
A: 

How are you getting displayImage and what ColorModel is it using?

If it is an IndexColorModel, that may explain a lot.

The first code fragment will return a BufferedImage using a DirectColorModel. That will require 4 bytes per pixel vs typically 1-byte per pixel for an indexed image. That 1:4 expansion could be causing your out of memory condition.

The second code fragment makes a BufferedImage with the same model as the source. When that is an IndexColorModel and the interpolation is not NEAREST_NEIGHBOR, the filter() call will create a temporary BufferedImage with a DirectColorModel. It will use that as the destination of the filter operation, then requantize the temporary buffer and draw it into your displayImage2. So, twice as many bitblits.

If you're only doing a single transform, I'd say go with the second form.

If you're doing multiple operations, allocate a pair of BufferedImages with a DirectColorModel. large enough to hold your biggest image. Draw you source image into one of them and perform your filters back and forth between them. Then when you're finished, use a ColorConvertOp to requantize back to an indexed image. That way you only need to color convert once instead of on each filter call.

Devon_C_Miller
I think I'll try your second suggestion first, can you tell me how to use ColorConvertOp to convert from a direct to an indexed color model?
Jon
ColorConvertOp work just like AffineTransformOp, but you need to call `filter(src, dst)` passing `dst` as an existing `BufferedImage` of the desired color model.
Devon_C_Miller
OK, but how do you use the constructor from the ColorConvertOp. I did the following ColorModel indexColorModel = displayImage.getColorModel(); displayImage = op.filter(displayImage, null); ColorConvertOp colorOp = new ColorConvertOp(indexColorModel.getColorSpace(), displayImage.getColorModel().getColorSpace(), null); displayImage = colorOp.filter(displayImage, null);And when I run this it just hangs on the filter line, never returning.
Jon
I'm sorry, I mistyped one of the lines of code above, it should actually readColorModel indexColorModel = displayImage.getColorModel(); displayImage = op.filter(displayImage, null); ColorConvertOp colorOp = new ColorConvertOp(displayImage.getColorModel().getColorSpace(), indexColorModel.getColorSpace(), null); displayImage = colorOp.filter(displayImage, null);I mixed up the order of the parameters in the ColorConvertOp constructor, but it is still incredibly slow.
Jon
I've always used the simple "hints only" constructor: ColorConvertOp colorOp = ColorConvertOp (null); Then pass in a BI with the desired color space for the destination.
Devon_C_Miller