读取和写入大图像

Posted

技术标签:

【中文标题】读取和写入大图像【英文标题】:Read and Write a large Image 【发布时间】:2016-05-30 05:09:46 【问题描述】:

我需要逐个像素地读取和写入图像(我正在生成分形)。当我尝试使用图像尺寸时,我意识到当图像尺寸很大(比如 24000x18000)时使用BufferedImage 写入图像会导致OutOfMemoryError。为了解决这个问题,我使用了-Xmx -Xms 来增加堆大小。

有没有办法以像素方式写入图像而不必将整个图像加载到内存中?读取(和修改)大图像也是如此。

编辑

我正在逐个像素,从左到右,从上到下。

【问题讨论】:

您是从左到右、从上到下逐像素生成图像吗?如果是这样,您也许可以安排连续编写它。但是,如果您需要在写入之前完全生成图像,则必须先将其存储在内存中。你的问题不清楚... @JimGarrison 是的,我从左到右,从上到下逐个像素地进行操作。能否请您回答如何连续执行? 您可能不得不绕过标准图像代码并直接编写图像格式。这可能是相当多的工作,并且超出了我的专业知识范围。也许其他人会回答。我建议您重写问题以更清楚地解释您在做什么,而不是进行编辑。 看看:***.com/questions/18466513/… 【参考方案1】:

最简单的解决方案通常只是添加更多内存。 :-)

但是,有一些选项(我在您的问题中没有找到足够的信息来决定哪个是最好的,请考虑更新它):

为您的图像编写一个最小格式标题(BMP 很容易,TIFF 也可行),为您的图像分配该格式所需的磁盘空间,并对该区域进行内存映射。这将类似于使用虚拟内存。系统会一次将文件的区域复制到内存中,因此您应该一次在有限的区域上工作,以避免过多的交换。

我已经编写了一些类来允许使用像BufferedImageMappedImageFactoryMappedFileBuffer 这样的文件(相当慢)。这些可以与上述结合,以获得“实时”更新文件,或者使用更熟悉的ImageIO API 来读取/写入大文件(读入此类图像所需的特殊代码,请参阅MappedImageFactory.createCompatibleMappedImage(w, h, type) 和 @987654328 @)。

使用ImageIO API 读取和写入切片(固定大小的区域)。我所知道的唯一支持图块的图像格式是 TIFF。我认为来自ja_imageio.jarTIFFImageReaderTIFFImageWriter 将支持平铺。 RenderedImage API 也支持平铺。平铺也可以与内存映射技术结合使用,以获得更好的性能(即将平铺复制到正常的BufferedImage 以获得更快的 Java2D 操作)。

使用ImageIO API 读取和写入任意子区域。使用ImageReadParam.setSourceRegion(...) 读取区域很容易。 ImageWriter.canReplacePixels() 方法会告诉你作者是否支持写入区域。不幸的是,我不知道当前支持此功能的任何ImageWriter 实现,但从理论上讲,如果您想自己实现它,任何未压缩格式都应该很容易。

这个列表可能并不详尽。

【讨论】:

感谢您的回答。这是一个相当详细的。我会等待一段时间,如果我没有得到更好的答案,我会将此标记为答案。【参考方案2】:

我同意 haraldK 提出的解决方案。 18Kx24K 可以轻松加载到内存中。

但是当你逐个像素地进行时,你也可以使用BigBufferedImage,它被呈现在this post中。图像不会加载到内存中,而是存储到文件中。

【讨论】:

以上是关于读取和写入大图像的主要内容,如果未能解决你的问题,请参考以下文章

opencv读取ENVI标准格式

使用可序列化而不是向/从文件写入和读取对象

在 Heroku 上使用 Node 读取、写入和存储 JSON

垂直读取和写入多个字典到csv文件

C++ 内存不足:改为写入文件,在需要时读取数据?

如何在 html 网站上使用 javascript 读取和写入另一个文件?