【问题标题】:ImageMagick single convert command performanceImageMagick 单次转换命令性能
【发布时间】:2017-06-20 18:00:16
【问题描述】:

我有几千张图像要处理,所以每一毫秒都很重要。每张图片的大小约为 2-3Mb。

提供给转换器的源文件: 图片.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

结合 ImageMagicks 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"

【问题讨论】:

  • 你能分享一张原图给我们玩吗?
  • 使用 libjpeg-turbo 重建 Imagemagick。
  • strace convert... 表明它实际上是从 jpeg-turbo 获取库文件。在这种情况下,图像不相关,大小约为 2mb 且大于 1024x768
  • 我会添加 -define jpeg:size=2048x1536 作为第一个参数,假设您的原件大于 4096x3072,它应该会给您一个简单的 x2 加速。

标签: php imagemagick imagemagick-convert


【解决方案1】:

您没有使用 jpeg 加载时收缩,这样可以轻松加快速度。

jpeg 库有一个简洁的功能,可以让您以 1/2、1/4 或 1/8 的全分辨率解压缩。由于 jpg 在内部工作的方式,1/8 分辨率特别快。

要在convert 中利用这一点,您需要向 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

虽然实时时间只下降了 2 倍,但用户时间下降了 5 倍左右。这使得与 gnu 并行运行很有用。例如:

parallel vipsthumbnail image.jpg -s {} -o {}_image.jpg ::: \
    1024x768 250x250 174x174

【讨论】:

  • 结果看起来确实很吸引人,但不幸的是,由于某些库不兼容,我无法在我的 Slackware 系统上编译 vips 包。由于没有时间,我没有追求这个解决方案,但由于数字不言自明,我肯定会很快回到这个包。谢谢!
  • 有一些针对贵宾的 slackbuilds,例如。 github.com/igorek7/SlackBuilds/tree/master/vips 虽然那个有点老了。
【解决方案2】:

Eric 和 John 的建议有很多共同点,可以与我的建议混合使用 - 即使用 GNU Parallel。当您拥有数千张图片时,它真的很重要。

我创建了 100 个图像(实际上是使用 GNU Parallel,但这不是重点),分别称为 image-0.jpgimage-99.jpg。然后我做了一个简单的调整大小操作,只是为了展示如何做到这一点,而不会过于关注 ImageMagick 方面。首先我按顺序进行,调整 100 张图像的大小需要 48 秒,然后我用 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 中弹出的速率。

【讨论】:

    【解决方案3】:

    这很有趣,因为我前段时间做了一些转换,发现 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:您需要在输入图像之前添加-define jpeg:size - 与 user894763 显示的完全一样。
    【解决方案4】:

    在 Magick Persistent Registry (.mpr) 上尝试 Magick Persistent Cache 图像文件格式 (.mpc)。

    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 秒)。尽管在 answers/cmets 中提到了所有调整,但三个单独的命令仍然可以更快地完成工作
    【解决方案5】:

    ImageMagick 有一个名为-thumbnail <geometry> 的特殊调整大小运算符变体,用于将非常大的图像转换为小缩略图。它在内部使用

    1. -sample 将图像缩小到最终高度的 5 倍,如果缩略图比原始图像小得多,这比 -resize 快​​得多。 由于此运算符使用缩减的过滤器集,-filter 运算符被忽略!
    2. -strip 从图像中删除所有缩略图通常不需要的配置文件。这也进一步减小了生成的图像文件的大小。
    3. -resize 最终创建所需的大小和比例

    在从 JPEG 图像创建缩略图时,可以使用特殊的 JPEG 加载时收缩选项-define jpeg:size=<size> 来代替,如 user894763 所述。 请注意,必须在convert 之后立即指定此选项,例如:

    convert -define jpeg:size=<size> input-image.jpg ...
    

    无论如何,-thumbnail 运算符可以额外指定,因为它会从缩略图中删除所有配置文件,从而减小文件大小。

    详细信息可见ImageMagick usage documentation

    【讨论】:

      【解决方案6】:

      我在 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.952s

      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.478s

      不需要合并多个命令,因为 JPG 不支持虚拟画布。所以删除它会将乘法命令行时间减少到 0m0.738s

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-12-20
        • 2017-12-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2019-01-23
        相关资源
        最近更新 更多