ImageMagick单个转换命令的性能

3

我有几千张图片需要处理,因此每毫秒都很重要。每张图片的大小约为2-3Mb。

提供给转换器的源文件: image.jpg

从源文件生成的文件:

orig_image.jpg      // original image
1024x768_image.jpg  // large image
250x250_image.jpg   // thumbnail 1
174x174_image.jpg   // thumbnail 2

在浏览有关imagemagick转换性能的不同主题时,我有一种感觉,即单个命令应该比每个图像大小的单独转换快得多。此外,内存利用被提到作为性能提升的一个方面。(ImageMagick batch resizing performance

多命令转换(每个命令通过php的exec()循环运行):

convert "image.jpg" \
    -coalesce -resize "1024x768>" +repage "1024x768_image.jpg"

convert "1024x768_image.jpg" \
    -coalesce \
    -resize "250x250>" \
    +repage \
    -gravity center \
    -extent "250x250" "250x250_image.jpg"

convert "1024x768_image.jpg" \
    -coalesce \
    -resize "174x174>" \
    +repage \
    -gravity center \
    -extent "174x174" "174x174_image.jpg"

mv image.jpg orig_image.jpg

单个命令转换,包含ImageMagick的mpr:

convert "image.jpg" -quality 85 -colorspace rgb -coalesce \
    -resize "1024x768>" \'
    -write "1024x768_image.jpg" \
    -write mpr:myoriginal +delete \
    mpr:myoriginal -coalesce \
    -resize "250x250>" \
    -gravity center \
    -extent "250x250" \
    -write "250x250_image.jpg" +delete \
    mpr:myoriginal -coalesce \'
    -resize "174x174>" \
    -gravity center \
    -extent "174x174" \
    -write "174x174_image.jpg"

在性能测试之后,结果有些出乎意料。在循环中执行单个命令转换需要 62 秒,而执行多个命令的转换只需 16 秒?
# convert -version
Version: ImageMagick 7.0.2-1 Q8 i686 2017-02-03 http://www.imagemagick.org
Copyright: Copyright (C) 1999-2016 ImageMagick Studio LLC
License: http://www.imagemagick.org/script/license.php
Features: Cipher DPC HDRI OpenMP
Delegates (built-in): bzlib freetype jng jpeg lzma png tiff wmf xml zlib

还安装了libjpeg-turbo jpg处理库,但我不知道(不知道如何检查)ImageMagic是否在使用它或旧的libjpeg。

有什么想法可以加快图像转换过程吗?

编辑: 不知道如何在stackoverflow上正确格式化它,但我刚刚注意到单行命令有一个参数“ -colorspace rgb”,而多行命令没有,这实际上导致了这样奇怪的结果,其中多个命令被更快地处理。

删除“ -colorspace rgb”参数后,MPR转换版本效果最好,并提高了性能。

总之,我最终使用了这个命令:

// MPR
convert "orig_image.jpg" -quality 80 -coalesce \
    -resize "1024x768>" \
    -write 1024x768_image.jpg \
    -write mpr:myoriginal +delete \
    mpr:myoriginal -resize "250x250>" \
    +repage -gravity center -extent "250x250" \
    -write "250x250_image.jpg" \
    -write mpr:myoriginal +delete \
    mpr:myoriginal -coalesce -resize "174x174>" \
    +repage -gravity center -extent "174x174" \
    -write "174x174_image.jpg"

你能分享一张原始图片让我们玩耍吗? - emcconville
重新编译Imagemagick并使用libjpeg-turbo库。 - saurabheights
strace转换...显示它实际上从jpeg-turbo中选择库文件。在这种情况下,图像不相关,大小约为2mb,大于1024x768。 - Didzis
我会将-define jpeg:size=2048x1536添加为第一个参数,这应该可以让您轻松加速两倍,假设您的原始图像大于4096x3072。 - jcupitt
6个回答

4
您没有使用JPEG缩放加载,这将使速度更快。
JPEG库有一个很棒的功能,可以让您以全分辨率、1/2、1/4或1/8解压缩。由于jpg的内部工作方式,1/8分辨率尤其快。
为了在转换中利用它,您需要向JPEG加载程序提示需要特定大小的图像。为避免出现走样,您应该请求至少比目标大小大200%的图像。
在这台机器上,我看到:
$ vipsheader image.jpg 
image.jpg: 5112x3470 uchar, 3 bands, srgb, jpegload
$ time convert image.jpg -resize 1024x768 1024x768_image.jpg
real    0m0.405s
user    0m1.896s
sys 0m0.068s

如果我设置缩小加载提示,速度会快大约2倍:
$ time convert -define jpeg:size=2048x1536 image.jpg -resize 1024x768 1024x768_image.jpg
real    0m0.195s
user    0m0.604s
sys 0m0.016s

你将会看到非常大的jpg文件速度会显著提升。
你也可以考虑使用另一个缩略图生成器。例如vipsthumbnail,它的速度更快一些。
$ time vipsthumbnail image.jpg -s 1024x768 -o 1024x768_image.jpg
real    0m0.111s
user    0m0.132s
sys 0m0.024s

尽管实时时间仅减少了约一半,但用户时间下降了约5倍。这使得使用GNU Parallel运行非常有用。例如:
parallel vipsthumbnail image.jpg -s {} -o {}_image.jpg ::: \
    1024x768 250x250 174x174

结果看起来很吸引人,但不幸的是,由于一些库不兼容性问题,我无法在我的Slackware系统上编译vips软件包。由于时间不足,我没有追求这个解决方案,但由于数字说明了一切,我肯定会很快回到这个软件包。谢谢! - Didzis
有一些针对vips的SlackBuilds,例如 https://github.com/igorek7/SlackBuilds/tree/master/vips ,尽管那个可能有点旧。 - jcupitt

4
Eric和John的建议都很有见地,可以将它们与我的建议混合使用——使用GNU Parallel。当你有成千上万的图片时,这会非常重要。
我创建了100个图像(实际上是使用GNU Parallel创建的,但这不是重点),文件名为image-0.jpgimage-99.jpg。然后,我进行了简单的调整大小操作,只是为了演示如何在不太关注ImageMagick方面的情况下完成它。首先,我按顺序执行,需要48秒才能调整大小100个图像,然后我使用GNU Parallel执行完全相同的操作,仅用了不到10秒钟-因此可以节省大量时间。
#!/bin/bash
# Create a function used by both sequential and parallel versions - it's only fair
doit(){
   echo Converting $1 to $2
   convert -define jpeg:size=2048x1536 "$1" -resize 1024x768 "$2"
}
export -f doit

# First do them all sequentially - 48 seconds on iMac
time for img in image*.jpg; do
   doit $img "seq-$img"
done

# Now do them in parallel - 10 seconds on iMac
time parallel doit {} "par-{}" ::: image*.jpg

仅供娱乐 - 观察电影右上角的CPU计量器和在电影最后1/6中GNU Parallel弹出文件的速率。

enter image description here


2

我之前做过一些转换,发现mpr更慢。无论如何,请尝试以下方法:

$cmd = " convert "image.jpg" -colorspace rgb -coalesce \( -clone 0 -resize 1024x768> -write 1024x768_image.jpg +delete \)".
" \( -clone 0 -resize 250x250> -gravity center -extent 250x250 -write 250_wide.jpg +delete \) ".
" -resize 174x174> -gravity center -extent 174x174  null: ";
exec("convert $cmd 174x174_image.jpg ");

我注意到您的范围没有背景颜色。
您还可以在循环方法中添加一个-define,可以在此列表中查看:https://www.imagemagick.org/script/command-line-options.php#define。jpeg:size = geometry仅读取创建图像所需的数据,而不读取整个图像。您可能还可以将其添加到第一行中。 -quality用于输出,在您放置它的地方将不起作用。
 $cmd = " convert "image.jpg" jpeg:size=1024x768 -colorspace rgb -coalesce \( -clone 0 -resize 1024x768> -write 1024x768_image.jpg +delete \)"..

我总是记不清楚它是在文件名之前还是之后


添加了-define jpeg:size=1024x768并使用了-clone功能,但仍然没有性能提升。 - Didzis
@Didzis:你需要在输入图像之前添加-define jpeg:size,就像user894763向你展示的那样。 - Mark Setchell

2

建议使用Magick持久缓存图像文件格式(.mpc)替代Magick持久注册表(.mpr)。

convert "image.jpg" -quality 85 -colorspace rgb myoriginal.mpc
convert myoriginal.mpc \
    -resize "1024x768>" \
    -write "1024x768_image.jpg" \
    -resize "250x250>" \
    -gravity center \
    -extent "250x250" \
    -write "250x250_image.jpg"  \
    -resize "174x174>" \
    -gravity center \
    -extent "174x174" \
    "174x174_image.jpg"

以下是测试1.8mb Jpeg时的结果。
real    0m0.051s
user    0m0.133s
sys     0m0.013s

确实需要两个命令来完成这个操作(尽管可以通过-write ... +delete简化为一个命令),但是在.mpc重新加载到图像堆栈后,I/O成本非常低。

或者

您可能完全可以跳过.mpc,使用...

convert "image.jpg" -quality 85 -colorspace rgb \
    -resize "1024x768>" \
    -write "1024x768_image.jpg" \
    -resize "250x250>" \
    -gravity center \
    -extent "250x250" \
    -write "250x250_image.jpg"  \
    -resize "174x174>" \
    -gravity center \
    -extent "174x174" \
    "174x174_image.jpg"

随着结果的返回...

real    0m0.061s
user    0m0.163s
sys     0m0.012s

首先将其转换为mpc格式,然后在循环中使用您提供的命令可以使我获得约7秒的性能提升(之前是62秒,现在是55秒)。尽管在答案/评论中提到了所有的调整,但仍然需要三个单独的命令才能更快地完成任务。 - Didzis

1
ImageMagick有一个特殊的调整大小操作符变体,名为-thumbnail <geometry>,用于将非常大的图像转换为小缩略图。在内部,它使用以下方法:
  1. -sample 将图像缩小到最终高度的五倍,如果缩略图比原始图像小得多,则比-resize快得多。由于此操作符使用了减少的过滤器集,因此会忽略 -filter 运算符!
  2. -strip 从图像中删除通常不需要的所有配置文件。这还可以进一步减小生成的图像文件的大小。
  3. -resize 最终创建所需的大小和比例
当从JPEG图像创建缩略图时,可以使用特殊的JPEG缩小选项-define jpeg:size=<size>,如user894763所述。请注意,此选项必须在convert之后立即指定,例如:
convert -define jpeg:size=<size> input-image.jpg ...

无论如何,-thumbnail 运算符可以被额外指定,因为它会从缩略图图像中删除所有配置文件,从而减小文件大小。
详细信息可以在ImageMagick使用文档中找到。

0

我使用ImageMagick 6.9.10.0 Q16 Mac OSX中的一个命令行,处理一个3 MB的输入JPG图像时,时间减少了一半。

list="image.jpg"
time for img in $list; do
convert "image.jpg" \
-coalesce -resize "1024x768>" +repage "1024x768_image.jpg"

convert "1024x768_image.jpg" \
-coalesce \
-resize "250x250>" \
+repage \
-gravity center \
-extent "250x250" "250x250_image.jpg"

convert "1024x768_image.jpg" \
-coalesce \
-resize "174x174>" \
+repage \
-gravity center \
-extent "174x174" "174x174_image.jpg"
done

时间:0m0.952秒

time convert "image.jpg" \
-resize "1024x768>" \
+write "1024x768_image.jpg" \
-resize "250x250>" \
-gravity center \
-extent "250x250" \
+write "250x250_image.jpg"  \
-resize "174x174>" \
-gravity center \
-extent "174x174" \
"174x174_image.jpg"

时间:0m0.478秒

由于JPG不支持虚拟画布,因此您的多个命令中的聚合是不必要的。因此,去除它可以将多个命令行时间缩短至0m0.738s。

由于您必须编写和读取中间图像,因此多个命令应该更长。由于您的中间图像是JPG格式,每次编写和读取中间图像时都会丢失更多的视觉质量。因此,一个长的命令行的质量也应该更好。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接