【问题标题】:Read pixel from a big jp2 image without loading the whole image into memory从大 jp2 图像中读取像素而不将整个图像加载到内存中
【发布时间】:2015-01-02 15:20:05
【问题描述】:

我正在尝试从 java 中的大图像中读取部分内容。我的图像大小超过 700 MB。我使用了这段代码,它通常读取像素而不将整个图像加载到内存中:

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

但是,我得到了错误:

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)

请帮忙阅读这张大图的部分内容?

【问题讨论】:

标签: java image


【解决方案1】:

有不同的方法可以将图像的一部分加载到内存中,然后再进行处理。您可以尝试以下方法读取片段:

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;
}

然后这样称呼它:

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 线程中被标记为正确答案。

如果需要,您可以使用此技术通过一些简单的计算最终将整个图像读入内存。

编辑:
您尝试处理的图像的分辨率大于数组的分辨率 (95168x154832)。所以基本上你将无法读取图像,因为ImageIO.createImageInputStream() 试图将整个图像加载到数组 AFAIK 中。

可以做的是使用一个名为ImgLib2 的库。 Here 你可以找到一些例子。 ImgLib2 使用多维数组来读取(大)图像数据,因此它比 ImageIO 可以处理的要大。

【讨论】:

  • 这里的主要区别是使用了重载的 setInput 方法,允许忽略元数据。这还有其他影响,但如果在处理元数据时抛出异常,则 /might/ 起作用。 docs.oracle.com/javase/8/docs/api/javax/imageio/…
  • MemoryCacheImageInputStream /might/ 最终会将整个对象读入内存。但是,根据堆栈跟踪,这肯定不是这里发生的事情。
  • 那么,这是什么意思?
  • @Ihsan “因为 ImageIO.createImageInputStream() 试图将整个图像加载到数组中 [...]”。这是不正确的。 createImageInputStream() 只包装流,不读取。 ImageReader 实现执行实际读取。尝试将整个图像读入堆内存的是J2KImageReaderCodecLib 阅读器(大多数ImageReaders 不会也不应该这样做)。
猜你喜欢
  • 2013-03-25
  • 2012-06-04
  • 2013-04-24
  • 1970-01-01
  • 2017-09-22
  • 2016-02-13
  • 2020-06-11
  • 2014-03-28
  • 2020-05-01
相关资源
最近更新 更多