2

I'm trying to read parts from a big image in java. My image size is more than 700 MB. I have used this code which normally reads pixels without loading the whole image into memory:

Rectangle sourceRegion = new Rectangle(0, 0, 512, 512); // The region you want to extract

ImageInputStream stream = ImageIO.createImageInputStream( new File("/home/dhoha/Downloads/BreastCancer.jp2")); // File or input stream
final Iterator<ImageReader> readers = ImageIO.getImageReaders(stream);

if (readers.hasNext()) {
ImageReader reader = (ImageReader)readers.next();

reader.setInput(stream, true);

ImageReadParam param = reader.getDefaultReadParam();
param.setSourceRegion(sourceRegion); // Set region

BufferedImage image = reader.read(0, param); // Will read only the region specified

However, I got the error:

Exception in thread "main" java.lang.IllegalArgumentException: Dimensions (width=95168 height=154832) are too large
    at java.awt.image.SampleModel.<init>(SampleModel.java:130)
    at java.awt.image.ComponentSampleModel.<init>(ComponentSampleModel.java:146)
    at java.awt.image.PixelInterleavedSampleModel.<init>(PixelInterleavedSampleModel.java:87)
    at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.createSampleModel(J2KRenderedImageCodecLib.java:741)
    at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.createOriginalSampleModel(J2KRenderedImageCodecLib.java:729)
    at com.sun.media.imageioimpl.plugins.jpeg2000.J2KRenderedImageCodecLib.<init>(J2KRenderedImageCodecLib.java:261)
    at com.sun.media.imageioimpl.plugins.jpeg2000.J2KImageReaderCodecLib.read(J2KImageReaderCodecLib.java:364)
    at testJai2.test3.main(test3.java:21)

Any help please to read parts from this big image?

didowa
  • 106
  • 9
  • Can you provide more of the stack trace so that we can see what class(es) are responsible for throwing this exception? – Brett Okken Jan 02 '15 at 15:27
  • I updated it.. Hope that will help in identifying the error.. – didowa Jan 02 '15 at 15:49
  • Is the image tiled? What is the tile height and width? http://docs.oracle.com/javase/8/docs/api/javax/imageio/ImageReader.html#isImageTiled-int- http://docs.oracle.com/javase/8/docs/api/javax/imageio/ImageReader.html#getTileHeight-int- http://docs.oracle.com/javase/8/docs/api/javax/imageio/ImageReader.html#getTileWidth-int- – Brett Okken Jan 02 '15 at 15:59
  • Hopefully tiles are available, which would allow you to read individual tiles: http://docs.oracle.com/javase/8/docs/api/javax/imageio/ImageReader.html#readTile-int-int-int- – Brett Okken Jan 02 '15 at 16:11
  • I tried to test if the image is tiled or not. However, the test isImageTiled did not give me any response. – didowa Jan 02 '15 at 16:15
  • How can I make them available? – didowa Jan 02 '15 at 16:16
  • Let us [continue this discussion in chat](http://chat.stackoverflow.com/rooms/68089/discussion-between-brett-okken-and-didowa). – Brett Okken Jan 02 '15 at 16:19
  • This seems to be a JAI bug to me. It's not necessary to create such a huge array when you only want to read a small region. – Harald K Jan 05 '15 at 09:31
  • BTW... Have you tried to use the non-CodecLib version of the JAI J2KImageReader? It might behave different, so worth giving a try. No guarantees though... And it's probably slower. ;-) – Harald K Jan 05 '15 at 09:45
  • Unfortunately it gives the same exception :( – didowa Jan 05 '15 at 11:26

1 Answers1

0

There are different ways to load parts of image to memory and then process it afterwards. You can try out the following method to read fragments:

public static BufferedImage readFragment(InputStream stream, Rectangle rect)
            throws IOException {
        ImageInputStream imageStream = ImageIO.createImageInputStream(stream);
        ImageReader reader = ImageIO.getImageReaders(imageStream).next();
        ImageReadParam param = reader.getDefaultReadParam();

        param.setSourceRegion(rect);
        reader.setInput(imageStream, true, true);
        BufferedImage image = reader.read(0, param);

        reader.dispose();
        imageStream.close();

        return image;
}

And calling it like this:

URL url = new URL("..."); // You can use your own stream instead of URL
Image chunk = readFragment(url.openStream(), new Rectangle(150, 150, 300, 250));

This is marked as a correct answer in this thread.

You can use this technique to finally read the whole image into the memory if you need by doing some simple calculations.

EDIT:
The resolution of the image you are trying to process is larger than an array can have (95168x154832). So basically you will not be able to read the image, since ImageIO.createImageInputStream() tries to load the whole image into an array AFAIK.

What you can do is use a library called ImgLib2. Here you can find some examples. ImgLib2 uses multidimensional arrays to read the (big) image data and so it's larger than ImageIO can handle.

Community
  • 1
  • 1
ihsan
  • 576
  • 2
  • 5
  • 18
  • The key difference here is the use of the overloaded setInput method allowing metadata to be ignored. There are other effects to this, but if the exception is being thrown while processing the metadata, this /might/ work. http://docs.oracle.com/javase/8/docs/api/javax/imageio/ImageReader.html#setInput-java.lang.Object-boolean-boolean- – Brett Okken Jan 02 '15 at 15:38
  • 1
    The MemoryCacheImageInputStream /might/ end up reading the entire object into memory. However, according to the stack trace that is certainly not what is happening here. – Brett Okken Jan 02 '15 at 16:01
  • So, what does that mean? – didowa Jan 02 '15 at 16:06
  • @Ihsan "since `ImageIO.createImageInputStream()` tries to load the whole image into an array [...]". This is incorrect. `createImageInputStream()` only wraps the stream, and does no reading. The `ImageReader` implementations do the actual reading. It's the `J2KImageReaderCodecLib` reader that tries to read the entire image into heap memory (most `ImageReader`s will not, and should not, do that). – Harald K Jan 05 '15 at 09:42