Skip to main content

Creating mosaic out of many images and running out of memory

5 replies [Last post]
newmanw10
Offline
Joined: 2009-08-17
Points: 0

I am trying to create a mosiac out of a bunch of images. Some of the images are slightly different sizes so I need to scale the images indivually before adding them to the mosaic.

</p>
<p>// Read in all images<br />
List<RenderedOp> images = new ArrayList<RenderedOp>();<br />
for (File imageFile : files) {</p>
<p>   float x = //set to correct minX for this image</p>
<p>   float y = // set to correct minY for this image</p>
<p>   //using imageio-ext project to read DTED files<br />
    ImageReader reader = newDTEDImageReaderSpi().createReaderInstance();<br />
    ParameterBlockJAI pbjImageRead = new ParameterBlockJAI("ImageRead")<wbr></wbr>;<br />
    pbjImageRead.setParameter("<wbr></wbr>Input", file);<br />
    pbjImageRead.setParameter("<wbr></wbr>reader", reader);<br />
    RenderedOp image = JAI.create("ImageRead", pbjImageRead);</p>
<p>    // scale the image into the correct minX minY to put into mosaic<br />
    ParameterBlockJAI scalePb= new ParameterBlockJAI("scale");</p>
<p>    scalePb.addSource(image);<br />
    scalePb.setParameter("xScale", 10 / image.getWidth());  // Scale to 10x10<br />
    scalePb.setParameter("yScale", 10 / image.getHeight());  // Scale to 10x10</p>
<p>    scalePb.setParameter("xTrans", x);</p>
<p>    scalePb.setParameter("yTrans", y);<br />
    image = JAI.create("scale", pbjImageRead);</p>
<p>    images.add(image);<br />
}</p>
<p>// Create a mosaic out of the images<br />
ParameterBlockJAI mosaicPb= new ParameterBlockJAI("mosaic");<br />
for (RenderedOp image : images) {<br />
    mosaicPb.addSource(image);<br />
}<br />
mosaicPb.setParameter("<wbr></wbr>mosaicType", MosaicType.MOSAIC_TYPE_<wbr></wbr>OVERLAY);<br />
RenderedOp mosaic = JAI.create("mosaic", mosaicPb);</p>
<p>// Now lets encode the mosaic to a png</p>
<p>// peform a sink, i.e. display the png</p>
<p>

What can I do to try and avoid an OutOfMemory exception? The indivual images are scaled down pretty small so I should be able to fit the image into memory when I create the mosaic. But I am not sure if memory is getting cleaned up properly.

I do have one fear in that since the images are not all sized exactly the same, when I read in the image using JAI I then need to perform a image.getWidth() and image.getHeight() to get to width and height so that I can scale the images down to 10x10. I am guessing that when I do that each image is read into memory before it is scaled, and if that is the case will result in a big memory hit. If this is a probelm, Is there a way that I can get the image size and height without reading the entire image into memory? Or can I somehow clean up the memory without affecting the chain later.

Any ideas on how I can improve this code so that I can solve my OutOfMemoryException problem would be greatly appreciated.

Thanks!

Reply viewing options

Select your preferred way to display the comments and click "Save settings" to activate your changes.
rgd
Offline
Joined: 2005-08-23
Points: 0

If your input images are bigger than 10x10 then you don't really need
them any more once you do the scale. So you might try disabling the
tile cache for the imageread operator. It means that whenever data is
requested, the file is re-read, but since the output of scale is cached
(by default, everything is), you really shouldn't need to read more than
once.

That way the tile cache has only the 10x10's, so you consume memory only
for that and for the output image. It's still ~2x the memory of the
output, but that's an improvement over also saving the raw inputs...
especially if they're much bigger than 10x10.

There's no requirement that getHeight/Width read the entire image, but
it's possible that some IIO plugins do. It depends on the specific
reader (and file format) you're using. I think most try not to read the
entire image but I don't recall for sure.

As to why the OOM error, it's possible the default tile cache size is
larger than the available memory (-Xmx option when starting java). You
could also try reducing the tile cache size so it will comfortably fit.
That will slow down performance but might stop the OOM. I think the
first approach is preferable, but this is an option too.

Obviously increasing the -Xmx memory size will help but I assume that's
not something you want to/can do for whatever reason.

Hope that helps...

-Bob

On 8/17/11 6:46 PM, forums@java.net wrote:
> I am trying to create a mosiac out of a bunch of images. Some of the
> images
> are slightly different sizes so I need to scale the images indivually
> before
> adding them to the mosaic.
>
>

<br />
><br />
> // Read in all images<br />
> List images = new ArrayList();<br />
> for (File imageFile : files) {<br />
><br />
>     float x = //set to correct minX for this image<br />
><br />
>     float y = // set to correct minY for this image<br />
><br />
>     //using imageio-ext project to read DTED files<br />
>      ImageReader reader = newDTEDImageReaderSpi().createReaderInstance();<br />
>      ParameterBlockJAI pbjImageRead = new ParameterBlockJAI("ImageRead");<br />
>      pbjImageRead.setParameter("Input", file);<br />
>      pbjImageRead.setParameter("reader", reader);<br />
>      RenderedOp image = JAI.create("ImageRead", pbjImageRead);<br />
>      // scale the image into the correct minX minY to put into mosaic<br />
>      ParameterBlockJAI scalePb= new ParameterBlockJAI("scale");<br />
><br />
>      scalePb.addSource(image);<br />
>      scalePb.setParameter("xScale", 10 / image.getWidth());  // Scale to<br />
> 10x10<br />
>      scalePb.setParameter("yScale", 10 / image.getHeight());  // Scale to<br />
> 10x10<br />
><br />
>      scalePb.setParameter("xTrans", x);<br />
><br />
>      scalePb.setParameter("yTrans", y);<br />
>      image = JAI.create("scale", pbjImageRead);<br />
><br />
>      images.add(image);<br />
> }<br />
> // Create a mosaic out of the images<br />
> ParameterBlockJAI mosaicPb= new ParameterBlockJAI("mosaic");<br />
> for (RenderedOp image : images) {<br />
>      mosaicPb.addSource(image);<br />
> }<br />
> mosaicPb.setParameter("mosaicType", MosaicType.MOSAIC_TYPE_OVERLAY);<br />
> RenderedOp mosaic = JAI.create("mosaic", mosaicPb);<br />
><br />
> // Now lets encode the mosaic to a png<br />
><br />
> // peform a sink, i.e. display the png<br />
><br />
> 

>
> What can I do to try and avoid an OutOfMemory exception? The indivual
> images are scaled down pretty small so I should be able to fit the image
> into
> memory when I create the mosaic. But I am not sure if memory is getting
> cleaned up properly.
>
> I do have one fear in that since the images are not all sized exactly the
> same, when I read in the image using JAI I then need to perform a
> image.getWidth() and image.getHeight() to get to width and height so that I
> can scale the images down to 10x10. I am guessing that when I do that each
> image is read into memory before it is scaled, and if that is the case will
> result in a big memory hit. If this is a probelm, Is there a way that I
> can
> get the image size and height without reading the entire image into memory?
> Or can I somehow clean up the memory without affecting the chain later.
>
>
>
> Any ideas on how I can improve this code so that I can solve my
> OutOfMemoryException problem would be greatly appreciated.
>
>
>
> Thanks!
>
>

newmanw10
Offline
Joined: 2009-08-17
Points: 0

Bob,
Thanks for the help. Seems I mis-stated my actual problem. After further debugging I determined that I am not having memory issues I am in fact running out of file descriptors.
ImageReader reader = newDTEDImageReaderSpi().createReaderInstance();
ParameterBlockJAI pbjImageRead = new ParameterBlockJAI("ImageRead");
pbjImageRead.setParameter("Input", file);
pbjImageRead.setParameter("reader", reader);
// Failed attempt to turn off tile cache
RenderedOp image = JAI.create("ImageRead", pbjImageRead, new RenderingHint(JAI.KEY_TILE_CACHE, null));
It seems the call to pbjImage.setParameter("reader", reader); is opening a file descriptor.
Since I loop many times I am opening a ton of file descriptors.
I have tried setting the "VerifyInput" to false hoping that would avoid this problem but a file descriptor is still opened each time.
Laslty for a quick solution I tried using the reader directly to read the image into memory:
BufferedImage image = reader.read(0);
//Now scale to image to reduce the memory footprint
ParameterBlockJAI scaledParams = // set up scaled params here.
RenderedOp scaledImage = JAI.create("scale", scaledParms);
// Not sure how to clean up memory from the original BufferedImage which was read into memory
image.flush();image = null;
// Still does not seem that memory is getting cleaned up
Lastly I am not sure I set the tile cache to null correctly. Or if forcing JAI to not use a the tile cache will solve the file descriptor problem.
Thanks again for the help.

rgd
Offline
Joined: 2005-08-23
Points: 0

I doubt the tile cache adjustments will solve the file descriptor
problems, unfortunately.

Can you simply raise the number of available descriptors? On Unix
that's simple to a point, I think it's ulimit. Generally the user limit
is set lower than the system limit so it can be raised.

There has been traffic in the list in the past about how to get files
closed but I didn't pay much attention to it and I don't recall. You
might try an archive search. I think this was generally in the context
of releasing the streams so they could be deleted but it's the same
problem. That might help broaden your keyword search.

Good luck...

-Bob

On 8/19/11 9:05 AM, forums@java.net wrote:
> Bob, Thanks for the help. Seems I mis-stated my actual problem. After
> further debugging I determined that I am not having memory issues I am in
> fact running out of file descriptors. ImageReader reader =
> newDTEDImageReaderSpi().createReaderInstance();
> ParameterBlockJAI pbjImageRead = new ParameterBlockJAI("ImageRead");
> pbjImageRead.setParameter("Input", file);
> pbjImageRead.setParameter("reader", reader); // Failed attempt to turn off
> tile cache
> RenderedOp image = JAI.create("ImageRead", pbjImageRead, new
> RenderingHint(JAI.KEY_TILE_CACHE, null)); It seems the call to
> pbjImage.setParameter("reader", reader); is opening a file descriptor.
> Since
> I loop many times I am opening a ton of file descriptors. I have tried
> setting the "VerifyInput" to false hoping that would avoid this problem
> but a
> file descriptor is still opened each time. Laslty for a quick solution
> I tried using the reader directly to read the image into memory:
> BufferedImage image = reader.read(0); //Now scale to image to reduce the
> memory footprint ParameterBlockJAI scaledParams = // set up scaled params
> here. RenderedOp scaledImage = JAI.create("scale", scaledParms); // Not
> sure
> how to clean up memory from the original BufferedImage which was read into
> memory image.flush();image = null; // Still does not seem that memory is
> getting cleaned up Lastly I am not sure I set the tile cache to null
> correctly. Or if forcing JAI to not use a the tile cache will solve the
> file descriptor problem. Thanks again for the help.
>

simboss1
Offline
Joined: 2005-08-08
Points: 0

Ciao,
I believe the problem should be in how the png encoder works. Going by memory
I believe it does a getData call on the provided rendered image prior
to writing therefore it might force
the mosaic to load everything in memory.

I would try to simply visualize the mosaic without writing or better
do a getTiles to force mosaic loading and then check if you still get
an OOM.

Regards,
Simone Giannecchini

sigel
Offline
Joined: 2005-02-18
Points: 0

Try searching for TCTool (Tile Cache Tool). You can instantiate it
prior to any JAI calls and it might help you track down memory and
caching issues.

Dennis

On 08/17/2011 06:46 PM, forums@java.net wrote:
> I am trying to create a mosiac out of a bunch of images. Some of the
> images
> are slightly different sizes so I need to scale the images indivually
> before
> adding them to the mosaic.
>
>

<br />
><br />
> // Read in all images<br />
> List images = new ArrayList();<br />
> for (File imageFile : files) {<br />
><br />
>    float x = //set to correct minX for this image<br />
><br />
>    float y = // set to correct minY for this image<br />
><br />
>    //using imageio-ext project to read DTED files<br />
>     ImageReader reader = newDTEDImageReaderSpi().createReaderInstance();<br />
>     ParameterBlockJAI pbjImageRead = new ParameterBlockJAI("ImageRead");<br />
>     pbjImageRead.setParameter("Input", file);<br />
>     pbjImageRead.setParameter("reader", reader);<br />
>     RenderedOp image = JAI.create("ImageRead", pbjImageRead);<br />
>     // scale the image into the correct minX minY to put into mosaic<br />
>     ParameterBlockJAI scalePb= new ParameterBlockJAI("scale");<br />
><br />
>     scalePb.addSource(image);<br />
>     scalePb.setParameter("xScale", 10 / image.getWidth());  // Scale to<br />
> 10x10<br />
>     scalePb.setParameter("yScale", 10 / image.getHeight());  // Scale to<br />
> 10x10<br />
><br />
>     scalePb.setParameter("xTrans", x);<br />
><br />
>     scalePb.setParameter("yTrans", y);<br />
>     image = JAI.create("scale", pbjImageRead);<br />
><br />
>     images.add(image);<br />
> }<br />
> // Create a mosaic out of the images<br />
> ParameterBlockJAI mosaicPb= new ParameterBlockJAI("mosaic");<br />
> for (RenderedOp image : images) {<br />
>     mosaicPb.addSource(image);<br />
> }<br />
> mosaicPb.setParameter("mosaicType", MosaicType.MOSAIC_TYPE_OVERLAY);<br />
> RenderedOp mosaic = JAI.create("mosaic", mosaicPb);<br />
><br />
> // Now lets encode the mosaic to a png<br />
><br />
> // peform a sink, i.e. display the png<br />
><br />
> 

>
> What can I do to try and avoid an OutOfMemory exception? The indivual
> images are scaled down pretty small so I should be able to fit the
> image into
> memory when I create the mosaic. But I am not sure if memory is getting
> cleaned up properly.
>
> I do have one fear in that since the images are not all sized exactly the
> same, when I read in the image using JAI I then need to perform a
> image.getWidth() and image.getHeight() to get to width and height so
> that I
> can scale the images down to 10x10. I am guessing that when I do that
> each
> image is read into memory before it is scaled, and if that is the case
> will
> result in a big memory hit. If this is a probelm, Is there a way that
> I can
> get the image size and height without reading the entire image into
> memory?
> Or can I somehow clean up the memory without affecting the chain later.
>
>
>
> Any ideas on how I can improve this code so that I can solve my
> OutOfMemoryException problem would be greatly appreciated.
>
>
>
> Thanks!
>
>