java - 附加到图像文件

标签 java image file-io image-processing

我编写了一个程序来拍摄“照片”,并为它选择的每个像素插入一系列其他照片中的图像。选择的图像是平均颜色最接近照片原始像素的照片。

我这样做的方法是首先对“库存”图像中每个像素的 rgb 值进行平均,然后将其转换为 CIE LAB,这样我就可以根据人类对颜色。

然后我编译了一张图像,其中原始“照片”图像中的每个像素都已替换为“最接近”的库存图像。

效果很好,但库存图像大小为 300 x 300 像素,即使虚拟机标志为“-Xms2048m -Xmx2048m”,是的,我知道这是荒谬的,在 555px x 540px 图像上我可以在出现内存不足错误之前,仅替换缩小到 50 像素的库存图像。

所以基本上我正在尝试考虑解决方案。首先,我认为图像效果本身可以通过将原始图像的每 4 个像素(2x2 正方形)平均为一个像素然后用图像替换这个像素来改善,因为这样小照片在单独打印时会更明显.这也应该允许我以更大的尺寸绘制库存图像。有没有人有这种图像处理的经验?如果是这样,您发现了什么技巧可以制作精美的图像。

最终,我认为减少内存错误的方法是重复将图像保存到磁盘并将下一行图像附加到文件,同时不断从内存中删除旧的渲染图像集。如何才能做到这一点?它类似于附加一个普通文件吗?

对于最后这件事的任何帮助,我们将不胜感激。

谢谢,

亚历克斯

最佳答案

我建议查看 Java Advanced Imaging (JAI) API。您现在可能正在使用 BufferedImage,它会将所有内容保存在内存中:源图像和输出图像。这称为“立即模式”处理。当您调用方法来调整图像大小时,它会立即发生。因此,您仍在内存中保留库存图像。

使用 JAI,您可以利用两个好处。

  1. 延迟模式处理。
  2. 瓦片计算。

延迟模式意味着当您在图像上调用方法时,输出图像不是正确计算的。相反,调整图像大小的调用会创建一个小的“运算符”对象,它可以稍后进行调整大小。这使您可以构建链、树或操作管道。因此,您的工作将为每个库存图像构建一个操作树,例如“裁剪、调整大小、合成”。好的部分是操作只是命令对象,因此您在构建命令时不会消耗所有内存。

此 API 是基于拉动的。它推迟计算,直到某些输出操作从运算符中拉出像素。这可以通过避免不必要的像素操作来快速帮助节省时间和内存。

例如,假设您需要一个 2048 x 2048 像素的输出图像,从 1600x512 像素的源图像中裁剪出 512x512 并按比例放大。显然,将整个 1600x512 的源图像按比例放大是没有意义的,只是为了丢掉 2/3 的像素。相反,缩放运算符将具有基于其输出维度的“感兴趣区域”(ROI)。缩放运算符将 ROI 投影到源图像上,并且只计算那些像素。

命令最终必须得到评估。在少数情况下会发生这种情况,主要与最终图像的输出有关。因此,要求 BufferedImage 在屏幕上显示输出将强制所有命令进行评估。同样,将输出图像写入磁盘将强制评估。

在某些情况下,您可以保留 JAI 的第二个好处,即基于图 block 的渲染。 BufferedImage 在所有像素上立即完成所有工作,而平铺渲染一次只对图像的矩形部分进行操作。

使用之前的示例,2048x2048 输出图像将被分解成图 block 。假设这些是 256x256,那么整个图像被分成 64 个图 block 。 JAI 运算符对象知道如何在一个磁贴上处理一个磁贴。因此,缩放源图像的 512x512 部分实际上一次在 64x64 源像素上发生了 64 次。

一次计算一个图 block 意味着遍历图 block ,这似乎需要更多时间。但是,在进行分块计算时,有两件事对您有利。首先,可以在多个线程上同时评估图 block 。其次, transient 内存使用量比立即模式计算低得多。

所有这些都是对为什么要使用 JAI 进行此类图像处理的冗长解释。


一些注意事项和注意事项:

  1. 您可以在不知不觉中击败基于图 block 的渲染。在工作流中任何有 BufferedImage 的地方,它都不能充当图 block 源或接收器。
  2. 如果您使用 JAI 或 JAI 图像 I/O 运算符为 JPEG 渲染到磁盘,那么您的状态就很好。如果您尝试使用 JDK 的内置图像类,您将需要所有内存。 (基本上,避免混合两种类型的图像处理。立即模式和延迟模式不能很好地混合。)
  3. 所有带有 ROI、图 block 和延迟模式的奇特内容对程序都是透明的。您只需对 JAI 类进行 API 调用。只有在您需要更多地控制磁贴大小、缓存和并发性等事情时,您才需要处理机器。

关于java - 附加到图像文件,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4362332/

相关文章:

C# 正则表达式拆分为 Java 模式拆分

java - 在 Eclipse 中的父项目之间移动 Maven 模块

java - 如何使用Swing Timers来制定整体更新率?

c++ - 如何使用 C++ 从图像采集卡中获取图像?

c - 返回文件*

python-3.x - Python Bokeh 文件输入小部件

java - 反射(reflection):当 A 可以动态地成为任何类时,创建一个 Consumer<A> 吗?

ios - 在 iOS 上一个接一个地保存大图像内存释放

python - 在 python 中按图像从文件中搜索谷歌图像

c++ - 为新文件类型重载 >> 运算符的优雅方法是什么?