java - 从单个图像流有效生成多个缩略图

标签 java image-processing parallel-processing thumbnails

我有一个图像上传 servlet,它通过 HTTP POST 接收上传的图像,并且是大小从 5 MB 到 75 MB 不等的高分辨率图像。从请求输入流中读取图像数据并将其保存到本地磁盘上。我正在寻找一种有效的机制,从请求输入流并行生成不同大小(4-5 个不同大小,其中最大的是网络图像 - 1024x768)的缩略图(或者部分顺序,如果不是完全并行),并将流保存到磁盘作为原始上传文件。

到目前为止我能想到的是 -

  1. 将原始流作为图像文件保存到磁盘。
  2. 生成网络图像 (1024x768),这是众多缩略图中最大的。
  3. 然后用它来生成后续的较小图像,因为这样会更快。

有人可以建议一种更有效的方法吗?最理想的方法是同步执行此操作,但如果异步非常高效,也可以。

在这方面的任何帮助,最好是在 Java 中,我们将不胜感激。

最佳答案

这是一个非常有趣的问题,因为它有很多优化点。

您关于生成较小图像然后生成缩略图的想法可能是一个不错的想法,但我要说的第一件事是,如果您有一个 75MB 的图像,那么它显然远大于 1024x768 - 很可能是它的一些倍数,在这种情况下,您需要确保使用 SCALE_FAST ( Image ) 缩放图像。您想要实现的是,缩放通过丢弃像素将图像缩小到较小的尺寸,而不是尝试做任何看起来更好(并且更昂贵)的事情,例如面积平均。您甚至可以通过获取图像的 int[] 并对每个第 N 个元素进行采样来为新图像创建一个新的 int[] ,并按一定比例缩小,从而使其运行得更快。

此时,您将得到一个较小的图像,例如大约 2000 x 2000。然后,您可以拍摄该图像并使用更好的东西来缩放它,以查找实际的缩略图,例如 SCALE_SMOOTH。

我想说,如果可能的话,您不应该将其写入磁盘(无论如何在处理过程中)。如果可以在内存中执行操作,速度会快得多,这在存在并行性的情况下尤为重要。除非您的服务器运行 SSD,否则同时运行两个磁盘密集型操作(例如同时重新缩放其中两个图像或将一个图像重新缩放为两种不同的大小)将迫使您的磁盘崩溃(因为主轴一次只能读取一个流)。然后,您将受到寻道时间的支配,您很快就会发现序列化所有操作将比一次执行多个操作快得多。

我会说在内存中重新调整它们,然后将它们写入(同步)到 ArrayList,然后让另一个线程顺序读取这些图像并存储它们。如果您不确定我的意思,请查看我对另一个问题的回答:

Producer Consumer solution in Java

通过这种方式,您可以在有用的地方(CPU 操作)进行并行化,并按顺序进行文件写入(避免抖动)。

话虽如此,您需要问自己并行化是否会给您带来好处。您的服务器有多个 CPU/核心吗?如果不是,那么这一切都是没有意义的,你不应该费心去线程化任何东西,因为它只会浪费你的时间。

除此之外,如果您希望一次上传大量图像,那么您可能不需要并行处理每个图像,因为您最终会得到多个 Web 服务器线程,每个线程大部分时间都处理一个图像无论如何,这将为您在多个核心上提供良好的 CPU 利用率。例如,如果您预计在任何时候都会不断上传 4 个图像,那么这将很好地利用 4 个内核,而无需进一步并行化。

最后一点是,当您重新缩放图像时,一旦获得中间图像,您可以将前一个图像设置为 null 以方便垃圾回收,这意味着当您生成缩略图时,内存中将只有中间图像,不是原来的大号。

关于java - 从单个图像流有效生成多个缩略图,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/8375334/

相关文章:

parallel-processing - CL_DEVICE_LOCAL_MEM_SIZE 是用于整个设备还是每个工作组?

控制 MPI_COMM_SPAWN 的节点映射

java - Tomcat 6 无法识别 <url-mapping>

java - 响应式 ul 图像列表不会换行

java - 运行 Activity 之间的沟通?

matlab - Matlab/OpenCV创建角度图像

image-processing - 确切的肤色 HSV 范围

c++ - 检测黑白半色调屏幕的角度

multithreading - Openmp:与omp_get_thread_num()并行使用

java - 在android项目中使用maven库