ImageMagick:如何在调整大量图像文件的同时实现低内存使用率?

我想调整大量(大约5200)的图像文件(PPM格式,每个5 MB大小),并使用convert将它们保存为PNG格式。

简洁版本:

convert吹起24 GB的内存,虽然我使用的语法告诉convert为连续处理图像文件。

长版本:

对于超过25 GB的图像数据,我想我不应该同时处理所有的文件。 我search了关于如何连续处理图像文件的ImageMagick文档,我发现 :

调整读取的每个图像的速度更快,资源更less。

$ convert '*.jpg[120x120]' thumbnail%03d.png

另外, 教程指出 :

例如,而不是…

montage '*.tiff' -geometry 100x100+5+5 -frame 4 index.jpg

它首先读取所有的tiff文件,然后调整它们的大小。 你可以做,而不是…

montage '*.tiff[100x100]' -geometry 100x100+5+5 -frame 4 index.jpg

这将读取每个图像,并调整它们的大小,然后继续下一个图像。 导致内存使用量less得多,并且在达到内存限制时可能会阻止磁盘交换(颠簸)。

因此,这就是我所做的:

 $ convert '*.ppm[1280x1280]' pngs/%05d.png 

根据文档,它应该逐一处理每个图像文件:读取,resize,写入。 我在一台有12个真实内核和24 GB内存的机器上这样做。 但是,在前两分钟内, convert过程的内存使用率增长到约96%。 它呆在那里一会儿。 CPU使用率最高。 稍微长一点,这个过程就死了,只是说:

杀害

在这一点上,没有输出文件已经产生。 我在Ubuntu 10.04和convert --version说:

 Version: ImageMagick 6.5.7-8 2012-08-17 Q16 http://www.imagemagick.org Copyright: Copyright (C) 1999-2009 ImageMagick Studio LLC Features: OpenMP 

它看起来像convert尝试在开始转换之前读取所有数据。 所以无论是在convert错误,与文档的问题,或者我没有正确阅读文档。

哪里不对? 如何在调整大量图像文件的同时实现低内存使用率?

顺便说一句:一个快速的解决scheme是只是循环使用shell的文件,并调用每个文件独立convert 。 但我想了解如何实现与纯ImageMagick相同。

谢谢!

没有直接访问你的系统,真的很难帮你调试。

但是你可以做三件事来帮助你缩小这个问题:

  1. 作为第一个命令行参数添加-monitor ,以查看有关正在进行的更多详细信息。

  2. (可选)添加-debug all -log "domain: %d +++ event: %e +++ function: %f +++ line: %l +++ module: %m +++ processID: %p +++ realCPUtime: %r +++ wallclocktime: %t +++ userCPUtime: %u \n\r"

  3. 暂时不要使用'* .ppm [1280×1280]'作为参数,而是使用'a * .ppm [1280×1280]'。 目的是限制你的通配符扩展(或其他合适的方式来实现相同的目标),而不是所有可能的匹配。

如果你做'2' 你需要做'3'。 否则你会被大量的输出所压倒。 (你的系统似乎也无法处理完整的通配符而不必杀死进程…)

如果您找不到解决方案,那么…

  1. …在官方ImageMagick错误报告论坛上注册一个用户名。
  2. …在那里报告你的问题,看看他们是否可以帮助你(如果你礼貌地问这些家伙是相当友好和回应)。

得到同样的问题,似乎是因为ImageMagick创建临时文件到/ tmp目录 ,这通常挂载为一个tmpfs。

把你的tmp移到别的地方。

例如:

  • 在一个大的外部驱动器上创建一个“tmp”目录

    mkdir -m777 /media/huge_device/tmp

  • 确保权限设置为777

    chmod 777 /media/huge_device/tmp

  • 作为root用户,将其替换为您的/ tmp

    mount -o bind /media/huge_device/tmp /tmp

注意:应该可以使用TMP环境变量来执行相同的技巧。

如果你有12个内核的话,我会选择GNU Parallel,就像这样,效果非常好。 由于它一次只能处理12个图像,同时仍然保留输出文件的编号,所以只使用最小的RAM。

 scene=0 for f in *.ppm; do echo "$f" $scene ((scene++)) done | parallel -j 12 --colsep ' ' --eta convert {1}[1280x1280] -scene {2} pngs/%05d.png 

笔记

-scene让你设置场景计数器,它出现在你的%05d部分。

--eta预测您的工作将在何时完成(估计到达时间)。

-j 12每次并行运行12个作业。