问题描述
我编写了一个程序,它采用照片,并为每个像素选择从一系列其他照片中插入图像。选择的图像是平均颜色最接近照片原始像素的照片。
I have written a program that takes a 'photo' and for every pixel it chooses to insert an image from a range of other photos. The image chosen is the photo of which the average colour is closest to the original pixel from the photograph.
我通过首先平均每个像素的rgb值来做到这一点。 'stock'图像,然后将其转换为CIE LAB,这样我就可以根据人类对颜色的感知来计算它与所讨论像素的接近程度。
I have done this by firstly averaging the rgb values from every pixel in 'stock' image and then converting it to CIE LAB so i could calculate the how 'close' it is to the pixel in question in terms of human perception of the colour.
然后我编辑了一个图像,其中原始照片图像中的每个像素都被最接近的股票图像替换。
I have then compiled an image where each pixel in the original 'photo' image has been replaced with the 'closest' stock image.
它工作得很好,效果是然而,股票图像大小是300乘300像素,甚至虚拟机标志为-Xms2048m -Xmx2048m,我知道这是荒谬,在555px乘540px图像我只能替换缩小到50像素的股票图像在我出现内存不足错误之前。
It works nicely and the effect is good however the stock image size is 300 by 300 pixels and even with the virtual machine flags of "-Xms2048m -Xmx2048m", which yes I know is ridiculus, on 555px by 540px image I can only replace the stock images scaled down to 50 px before I get an out of memory error.
所以基本上我试图想出解决方案。首先,我认为可以通过将原始图像的每4个像素(2x2平方)平均为单个像素然后用图像替换该像素来改善图像效果本身,因为这样小的照片将在单个打印中更加可见。这也应该允许我以更大的尺寸绘制股票图像。有没有人有这种图像处理的经验?如果是这样你发现什么技巧可以产生一个漂亮的图像。
So basically I am trying to think of solutions. Firstly I think the image effect itself may be improved by averaging every 4 pixels (2x2 square) of the original image into a single pixel and then replacing this pixel with the image, as this way the small photos will be more visible in the individual print. This should also allow me to draw the stock images at a greater size. Does anyone have any experience in this sort of image manipulation? If so what tricks have you discovered to produce a nice image.
最终我认为减少内存错误的方法是重复将图像保存到磁盘并附加下一行图像到文件,同时不断从内存中删除旧的渲染图像集。如何才能做到这一点?是否类似于附加普通文件。
Ultimately I think the way to reduce the memory errors would be to repeatedly save the image to disk and append the next line of images to the file whilst continually removing the old set of rendered images from memory. How can this be done? Is it similar to appending a normal file.
在这最后一件事情中的任何帮助将不胜感激。
Any help in this last matter would be greatly appreciated.
谢谢,
Alex
推荐答案
我建议查看Java Advanced成像(JAI)API。您现在可能正在使用BufferedImage,它确实将所有内容保存在内存中:源图像以及输出图像。这被称为立即模式处理。当您调用方法来调整图像大小时,它会立即发生。因此,您仍然将库存图像保留在内存中。
I suggest looking into the Java Advanced Imaging (JAI) API. You're probably using BufferedImage right now, which does keep everything in memory: source images as well as output images. This is known as "immediate mode" processing. When you call a method to resize the image, it happens immediately. As a result, you're still keeping the stock images in memory.
使用JAI,您可以利用两个好处。
With JAI, there are two benefits you can take advantage of.
- 延期模式处理。
- 平铺计算。
延迟模式意味着当您在图像上调用方法时,不会立即计算输出图像。相反,调用图像大小的调用会创建一个小的操作符对象,以后可以进行调整大小。这使您可以构建链,树或操作管道。因此,您的工作将为每个股票图像构建一个操作树,如裁剪,调整大小,复合。好的部分是操作只是命令对象,因此在构建命令时不会占用所有内存。
Deferred mode means that the output images are not computed right when you call methods on the images. Instead, a call to resize an image creates a small "operator" object that can do the resizing later. This lets you construct chains, trees, or pipelines of operations. So, your work would build a tree of operations like "crop, resize, composite" for each stock image. The nice part is that the operations are just command objects so you aren't consuming all the memory while you build up your commands.
此API是基于拉式的。它推迟计算,直到某些输出动作从运算符中拉出像素。这可以通过避免不必要的像素操作来快速帮助节省时间和内存。
This API is pull-based. It defers computation until some output action pulls pixels from the operators. This quickly helps save time and memory by avoiding needless pixel operations.
例如,假设您需要一个2048 x 2048像素的输出图像,从512x512裁剪比例放大超出1600x512像素的源图像。显然,放大整个1600x512源图像是没有意义的,只是扔掉2/3的像素。相反,缩放运算符将根据其输出维度具有感兴趣区域(ROI)。缩放操作符将ROI投影到源图像上,并仅计算这些像素。
For example, suppose you need an output image that is 2048 x 2048 pixels, scaled up from a 512x512 crop out of a source image that's 1600x512 pixels. Obviously, it doesn't make sense to scale up the entire 1600x512 source image, just to throw away 2/3 of the pixels. Instead, the scaling operator will have a "region of interest" (ROI) based on it's output dimensions. The scaling operator projects the ROI onto the source image and only computes those pixels.
最终必须评估命令。这种情况在少数情况下发生,主要与最终图像的输出有关。因此,要求BufferedImage在屏幕上显示输出将强制评估所有命令。同样,将输出图像写入磁盘将强制进行评估。
The commands must eventually get evaluated. This happens in a few situations, mostly relating to output of the final image. So, asking for a BufferedImage to display the output on the screen will force all the commands to evaluate. Similarly, writing the output image to disk will force evaluation.
在某些情况下,您可以保留JAI的第二个好处,即基于图块的渲染。虽然BufferedImage可以立即完成所有工作,但是在所有像素中,平铺渲染一次只能在图像的矩形部分上进行操作。
In some cases, you can keep the second benefit of JAI, which is tile based rendering. Whereas BufferedImage does all its work right away, across all pixels, tile rendering just operates on rectangular sections of the image at a time.
使用之前的示例,2048x2048输出图像将被分解为图块。假设这些是256x256,则整个图像被分成64个图块。 JAI操作符对象知道如何在tile上处理tile。因此,缩放源图像的512x512部分确实在64x64源像素上一次发生64次。
Using the example from before, the 2048x2048 output image will get broken into tiles. Suppose these are 256x256, then the entire image gets broken into 64 tiles. The JAI operator objects know how to work a tile at a tile. So, scaling the 512x512 section of the source image really happens 64 times on 64x64 source pixels at a time.
一次计算一个图块意味着在图块上循环,似乎需要更多时间。但是,在进行平铺计算时,有两件事对您有利。首先,可以同时在多个线程上评估切片。其次,瞬态内存使用量远远低于立即模式计算。
Computing a tile at a time means looping across the tiles, which would seem to take more time. However, two things work in your favor when doing tile computation. First, tiles can be evaluated on multiple threads concurrently. Second, the transient memory usage is much, much lower than immediate mode computation.
所有这些都是为什么要将JAI用于此类型的冗长解释图像处理。
All of which is a long-winded explanation for why you want to use JAI for this type of image processing.
一些注意事项和注意事项:
A couple of notes and caveats:
- 你可以在没有意识到的情况下击败基于图块的渲染。在工作流中有BufferedImage的任何地方,它都不能充当磁贴源或接收器。
- 如果使用JPEG的JAI或JAI Image I / O运算符渲染到磁盘,那时你状态很好。如果您尝试使用JDK的内置图像类,则需要所有内存。 (基本上,避免混合两种类型的图像操作。立即模式和延迟模式不能很好地混合。)
- ROI,tile和延迟模式的所有花哨的东西都是透明的该程序。您只需在JAI类上进行API调用。如果你需要更多控制瓷砖大小,缓存和并发等事情,你只需处理机器。
这篇关于附加到图像文件的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持!