附加到图像文件

ale*_*ose 5 java file-io image image-processing

我写了一个程序,它采用"照片",并为每个像素选择从一系列其他照片中插入图像.所选择的图像是平均颜色最接近照片的原始像素的照片.

我这样做是首先平均'stock'图像中每个像素的rgb值,然后将其转换为CIE LAB,这样我就可以根据人类对颜色的感知来计算它与所讨论像素的"接近"程度.

然后我编辑了一个图像,其中原始"照片"图像中的每个像素都被"最接近"的股票图像替换.

它工作得很好,效果很好但是库存图像大小是300乘300像素,甚至虚拟机标志为"-Xms2048m -Xmx2048m",我知道这是荒谬,在555px乘540px图像我只能替换在我出现内存不足错误之前缩小到50像素.

所以基本上我试着想出解决方案.首先,我认为可以通过将原始图像的每4个像素(2x2平方)平均为单个像素然后用图像替换该像素来改善图像效果本身,因为这样小的照片将在单个打印中更加可见.这也应该允许我以更大的尺寸绘制股票图像.有没有人有这种图像处理的经验?如果是这样,你发现了哪些技巧可以产生漂亮的图像.

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

对此最后一件事的任何帮助将不胜感激.

谢谢,

亚历克斯

小智 3

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

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

  1. 延迟模式处理。
  2. 平铺计算。

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

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

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

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

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

使用之前的示例,2048x2048 输出图像将被分解为图块。假设这些尺寸为 256x256,则整个图像将分为 64 个图块。JAI 操作对象知道如何在一块块上工作。因此,源图像的 512x512 部分的缩放实际上一次在 64x64 源像素上发生 64 次。

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

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


一些注释和警告:

  1. 您可以在没有意识到的情况下击败基于图块的渲染。无论工作流中有 BufferedImage,它都不能充当图块源或接收器。
  2. 如果您使用 JPEG 的 JAI 或 JAI Image I/O 运算符渲染到磁盘,那么您的状态就很好。如果您尝试使用 JDK 的内置图像类,您将需要所有内存。(基本上,避免混合两种类型的图像处理。立即模式和延迟模式不能很好地混合。)
  3. 所有带有 ROI、图块和延迟模式的花哨的东西对程序来说都是透明的。您只需对 JAI 类进行 API 调用即可。仅当您需要对切片大小、缓存和并发性等进行更多控制时,才需要处理机器。