Skip to main content

Down Scale performance and tiling

10 replies [Last post]
tledouxfr
Offline
Joined: 2005-04-12

Hello,
I'm trying to scale down big JPEG images. After reading various messages, I came up with the following algorithm :

public static PlanarImage scaleDown(PlanarImage imageSrc, float factor) {
// Blur the image
PlanarImage imageBlur = imageSrc;
int kernelSize = Math.round(1 / factor);
if (kernelSize > 1) {
if (kernelSize <= 3) kernelSize = 3;
else if (kernelSize > 3 && kernelSize <= 5)
kernelSize = 5;
else if (kernelSize > 5 && kernelSize <= 7)
kernelSize = 7;
else if (kernelSize > 7) kernelSize = 9;
int nbElmts = kernelSize * kernelSize;
float weight = 1.0f / ((float) nbElmts);
float[] elements = new float[nbElmts];
for (int i = 0; i < nbElmts; i++) {
elements = weight;
}
KernelJAI kernel = new KernelJAI(
kernelSize, kernelSize, elements);
ParameterBlock params1 = new ParameterBlock();
params1.addSource(imageSrc);
params1.add(kernel);
HashMap map = new HashMap();
map.put(RenderingHints.KEY_RENDERING,
RenderingHints.VALUE_RENDER_QUALITY);
BorderExtender extender =
BorderExtender.createInstance(
BorderExtender.BORDER_COPY);
map.put(JAI.KEY_BORDER_EXTENDER, extender);
RenderingHints rh = new RenderingHints(map);
imageBlur = JAI.create("Convolve", params1, rh);
}
PlanarImage image2 = imageBlur;
Interpolation interp = Interpolation.getInstance(
Interpolation.INTERP_BICUBIC);
while (factor < 0.4f) {
// Never reduce more than twice in one shot
ParameterBlock pb = new ParameterBlock();
pb.addSource(image2);
pb.add(0.5f).add(0.5f).add(0.0f).add(0.0f);
pb.add(interp); // interpolation method
image2 = JAI.create("Scale", pb, null);
factor *= 2.0f;
}
ParameterBlock pb = new ParameterBlock();
pb.addSource(image2);
pb.add(factor).add(factor).add(0.0f).add(0.0f);
pb.add(interp); // interpolation method
image2 = JAI.create("Scale", pb, rh);

return image2;
}

This algorithm works well for me ... except that for certain images it takes forever.

Then after some work, it ends up that before bluring I need to ALWAYS retile my imageSrc by doing :
PlanarImage image1 = imageSrc;
int tilex = imageSrc.getWidth();
int tiley = Math.min(imageSrc.getHeight(), 64);
image1 = new TiledImage(imageSrc, tilex, tiley);
With this simple modification the time taken goes from 10 hours to 5 minutes !!!
Can someone explain me this behaviour ?

Then I suppose that everything was ok but for one image I got a coredump in the native interface :
An unexpected exception has been detected in native code outside the VM.
Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0x4565e56b
Function name=(N/A)
Library=D:\mlib_jai_mmx.dll

NOTE: We are unable to locate the function name symbol for the error just occurred. Please refer to release documentation for possible reason and solutions.

Current Java thread:
at com.sun.medialib.mlib.Image.ZoomTranslate(Native Method)
at com.sun.media.jai.mlib.MlibScaleBicubicOpImage.computeRect(MlibScaleBicubicOpImage.java:138)
at javax.media.jai.ScaleOpImage.computeTile(ScaleOpImage.java:1271)
at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:912)
at javax.media.jai.OpImage.getTile(OpImage.java:1139)

removing the java native acceleration make everything goes
right ?!?

If anyone has a insight, I will be most interested.
Thanks in advance
Thomas

[i]

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
Robert Casties

jai-interest@javadesktop.org wrote:
> I found it very clear and wise to keep everything in JAI atomic.
> However, I still wasn't able scale an image of 5MB down to 10% with a
> reasonable result of quality. Fireworks or Photoshop do a way better
> job than me using JAI.
> My approach: - apply BoxFilter - operation "scale" using bicubic
> interpolation
>
> From what I've read people get neat results using this serial
> approach. Is it correct? (I use RenderedOP to pass and store the
> image from one function/operation to the other - but I assume that is
> of no importance in this matter)

I'm routinely applying much lower scaling factors with good performance
and quality in our project (http://digilib.berlios.de).

The operations are

1) load with subsampling to at least double the destination size
2) blur with convolution (kernel size at least 2)
3) scale with interpolation to destination size (bilinear or bicubic)

Code and some documentation is at our berlios site. See specially:

digilib.servlet.DigilibImageWorker.work()
digilib.image.ImageLoaderDocuImage.scale()
(this implementation uses Java2D but you can use JAI as well)

HTH
Robert

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

Alex.K
Offline
Joined: 2006-02-14

Hello,
It's not a secret that there are 2 main problems with Java2D and JAI interpolation implementations:
1) average-close-to-bad quality;
2) no any good solution for downsampling huge images without corresponding memory use.

Now I'm developing the commercial library to resolve both issues:
- resize images with top-notch quality and good speed (depending on chosen algorithm it's some times faster then Java2D Bilinear/Bicubic implementations and works with the same speed when the most qualified algorithms are used);
- supports downsampling huge images on-the-fly.

The library core is almost ready plus more than 20 interpolation algorithms are implemented - you can review how it works in the next thread http://forum.java.sun.com/thread.jspa?threadID=650207&tstart=0.

Now I try to resolve the second issue which lets for some image formats (already implemented for JPEG) downsampling huge images on-the-fly without loading the whole images into memory: during the latest tests my library resized 10000x10000 JPEG image to 500x500 with just 1.5M-3.5M (depending on algorithm) memory usage.
Do you find such functionality useful? And if yes then which image formats this library you would like to support? Please note that these formats should be also supported by Java ImageIO.

tledouxfr
Offline
Joined: 2005-04-12

Brian,

thanks a lot for the pointer which helps me understand what I was doing :-)

I end up having a minimal program that shows the core :
import java.io.*;
import javax.media.jai.*;
import java.awt.image.renderable.ParameterBlock;

public class BugScale {
public static void main(String[] args) {
float factor = Float.parseFloat(args[0]);
// Load image
ParameterBlock pb1 = new ParameterBlock();
pb1.add(args[1]).add(null).add(new Boolean(true));
PlanarImage imgSrc = JAI.create("FileLoad", pb1);
// Scale down
PlanarImage imgScale = scaleDown(imgSrc, factor);
// Save new image
ParameterBlock pb2 = new ParameterBlock();
pb2.addSource(imgScale);
pb2.add(args[2]).add("JPEG").add(null).add(new Boolean(true));
PlanarImage imgCible = JAI.create("FileStore", pb2);
}

public static PlanarImage scaleDown(PlanarImage imageSrc, float factor) {
int tilex = imageSrc.getWidth();
int tiley = Math.min(imageSrc.getHeight(), 16);
System.out.println("Tile image with " + tilex + "," + tiley);
PlanarImage image1 = new TiledImage(imageSrc, tilex, tiley);

Interpolation interp = Interpolation.getInstance(Interpolation.INTERP_BICUBIC);
//Interpolation interp = Interpolation.getInstance(Interpolation.INTERP_BILINEAR);
ParameterBlock pb = new ParameterBlock();
pb.addSource(image1);
pb.add(factor).add(factor).add(0.0f).add(0.0f);
pb.add(interp); // interpolation method
return JAI.create("Scale", pb, null);
}
}

The core only appears with BICUBIC interpolation and not BILINEAR one, with native acceleration on.

I have a specific case with factor 0.73492825 and a big image of 4180x2956 in RAW TIFF. The problem is that the image is 34Mb big.
I'm also able to circumvent the core adding tiles in the x-direction :
int tilex = Math.min(imageSrc.getWidth(), 1024);

Regards
Thomas

russland
Offline
Joined: 2010-03-11

Hi Brian, Hi Thomas,

I found it very clear and wise to keep everything in JAI atomic. However, I still wasn't able scale an image of 5MB down to 10% with a reasonable result of quality. Fireworks or Photoshop do a way better job than me using JAI.
My approach:
- apply BoxFilter
- operation "scale" using bicubic interpolation

From what I've read people get neat results using this serial approach. Is it correct? (I use RenderedOP to pass and store the image from one function/operation to the other - but I assume that is of no importance in this matter)

I'm happy for any copy-&-paste code that just works (before I reach the limit of 1 entire month of investigation)

Thanks heaps,
Brayan

Stéphane Wasserhardt

Maybe this old post from Bryan can help you :

http://archives.java.sun.com/cgi-bin/wa?A2=ind0311&L=jai-interest&F=&S=&...

Stephane

-----Message d'origine-----
De : jai-interest@javadesktop.org [mailto:jai-interest@javadesktop.org]
Envoyé : mercredi 3 août 2005 14:20
À : interest@jai.dev.java.net
Objet : [JAI] Re: Down Scale performance and tiling

Hi Brian, Hi Thomas,

I found it very clear and wise to keep everything in JAI atomic. However, I still wasn't able scale an image of 5MB down to 10% with a reasonable result of quality. Fireworks or Photoshop do a way better job than me using JAI.
My approach:
- apply BoxFilter
- operation "scale" using bicubic interpolation

>From what I've read people get neat results using this serial approach. Is it correct? (I use RenderedOP to pass and store the image from one function/operation to the other - but I assume that is of no importance in this matter)

I'm happy for any copy-&-paste code that just works (before I reach the limit of 1 entire month of investigation)

Thanks heaps,
Brayan
---
[Message sent by forum member 'russland' (russland)]

http://www.javadesktop.org/forums/thread.jspa?messageID=103574&#103574

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

russland
Offline
Joined: 2010-03-11

well, that's what Brian posted at the top. But didn't make me any smarter on what to apply first.

Brian Burkhalter

Which interpolation method are you using with "Scale"?
Did you try "SubsampleAverage"?

Brian

On Wed, 3 Aug 2005, jai-interest@javadesktop.org wrote:

> well, that's what Brian posted at the top. But didn't make me any smarter on what to apply first.
> ---
> [Message sent by forum member 'russland' (russland)]

----------------
Brian Burkhalter
Advanced Development/Media & Entertainment
Market Development Engineering
Sun Microsystems, Inc.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This email message is for the sole use of the intended recipient(s)
and may contain confidential and privileged information. Any
unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

Marc Boscher

Hello,

I am color reducing images to 4 bit grayscales using ErrorDiffusion. I first
bandcombine to get a 1-band 8 bit grayscale and I then pass that through
ErrorDiffusion with a lookup tables of 16 entries. Those 16 values (0 to
255) represent the gamma curve of a 4 bit OLED screen.

The problem is that the output of the error diffusion cannot be displayed
correctly. All pixel values are between 0 and 15 which are basically near
black when displayed. I used the format operation to set a 4 bit
IndexColorModel (16 RGB entries) on the image and still the image is not
displayed correctly. It's as if the index color model is ignored when the
rendered image is displayed. If I request the pixel values I get values from
0 to 15, not the RGB values these indexes point to.

If I do the same thing using a 3-band grayscale (the 3 bands are the same
grayscale) and a 3-band lookup table for error diffusion, it works
correctly. But I'm assuming it would be faster and less memory intensive to
use the 1-band approach.

Any ideas?

Marc

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

Brian Burkhalter

Marc,

> I am color reducing images to 4 bit grayscales using ErrorDiffusion. I first
> bandcombine to get a 1-band 8 bit grayscale and I then pass that through
> ErrorDiffusion with a lookup tables of 16 entries. Those 16 values (0 to
> 255) represent the gamma curve of a 4 bit OLED screen.
>
> The problem is that the output of the error diffusion cannot be displayed
> correctly. All pixel values are between 0 and 15 which are basically near
> black when displayed. I used the format operation to set a 4 bit
> IndexColorModel (16 RGB entries) on the image and still the image is not
> displayed correctly. It's as if the index color model is ignored when the
> rendered image is displayed. If I request the pixel values I get values from
> 0 to 15, not the RGB values these indexes point to.

That should work. I wonder whether the Format failed to replace the ColorModel
or something. Do you have a test case?

> If I do the same thing using a 3-band grayscale (the 3 bands are the same
> grayscale) and a 3-band lookup table for error diffusion, it works
> correctly. But I'm assuming it would be faster and less memory intensive to
> use the 1-band approach.

If you are using a 1-band ComponentSampleModel (which wastes 4 bits per pixel)
then you could use a ColorModel like this

ColorModel cm =
new ComponentColorModel(ColorSpace.getInstance(ColorSpace.CS_GRAY),
new int[] {4}, false, false,
Transparency.OPAQUE,
DataBuffer.TYPE_BYTE);

and the [0,15] gamut should be remapped to [0,255] at the display level.

Brian

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net

Brian Burkhalter

On Mon, 30 May 2005 jai-interest@javadesktop.org wrote:

> Hello,
> I'm trying to scale down big JPEG images. After reading various messages, I came up with the following algorithm :

For more ideas please also see

http://archives.java.sun.com/cgi-bin/wa?A2=ind0311&L=jai-interest&F=&S=&...

> public static PlanarImage scaleDown(PlanarImage imageSrc, float factor) {
[...]
> }
>
> This algorithm works well for me ... except that for certain images it takes forever.

Which images?

> Then after some work, it ends up that before bluring I need to ALWAYS retile my imageSrc by doing :
> PlanarImage image1 = imageSrc;
> int tilex = imageSrc.getWidth();
> int tiley = Math.min(imageSrc.getHeight(), 64);
> image1 = new TiledImage(imageSrc, tilex, tiley);
> With this simple modification the time taken goes from 10 hours to 5 minutes !!!
> Can someone explain me this behaviour ?

A TiledImage will cause the imageSrc to remain in memory. Otherwise depending
on where imageSrc comes from it is possible its data will need to be
regenerated perhaps because of its tiles having been flushed from a TileCache.

> Then I suppose that everything was ok but for one image I got a coredump in the native interface :
> An unexpected exception has been detected in native code outside the VM.
> Unexpected Signal : EXCEPTION_ACCESS_VIOLATION occurred at PC=0x4565e56b
> Function name=(N/A)
> Library=D:\mlib_jai_mmx.dll
>
> NOTE: We are unable to locate the function name symbol for the error just occurred. Please refer to release documentation for possible reason and solutions.
>
> Current Java thread:
> at com.sun.medialib.mlib.Image.ZoomTranslate(Native Method)
> at com.sun.media.jai.mlib.MlibScaleBicubicOpImage.computeRect(MlibScaleBicubicOpImage.java:138)
> at javax.media.jai.ScaleOpImage.computeTile(ScaleOpImage.java:1271)
> at com.sun.media.jai.util.SunTileScheduler.scheduleTile(SunTileScheduler.java:912)
> at javax.media.jai.OpImage.getTile(OpImage.java:1139)
>
> removing the java native acceleration make everything goes
> right ?!?

The above trace comes from the native acceleration module of course. For all
operations we have a complete Java implementation which is supposed to be able
to handle all data layouts, etc. Most operations (such as this one) have a
natively accelerated version which is used if it can handle the data layout
and possibly satisfy other constraints. See the README for more information.

As far as the core dump, if you would be able to supply an isolated test case
with data that would be great.

Brian

> If anyone has a insight, I will be most interested.
> Thanks in advance
> Thomas
>
>
> [i][/i][i][/i][i][/i]
> ---
> [Message sent by forum member 'tledouxfr' (msg4738)]
>
> http://www.javadesktop.org/forums/thread.jspa?messageID=85788&#85788
>
> ---------------------------------------------------------------------
> To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
> For additional commands, e-mail: interest-help@jai.dev.java.net
>
>

----------------
Brian Burkhalter
Advanced Development, Graphics and Media
Software Chief Technology Office
Sun Microsystems, Inc.

~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
This email message is for the sole use of the intended recipient(s)
and may contain confidential and privileged information. Any
unauthorized review, use, disclosure or distribution is prohibited.
If you are not the intended recipient, please contact the sender by
reply email and destroy all copies of the original message.
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

---------------------------------------------------------------------
To unsubscribe, e-mail: interest-unsubscribe@jai.dev.java.net
For additional commands, e-mail: interest-help@jai.dev.java.net