【问题标题】:How do I improve the performance of an read-write intensive imagemagick script?如何提高读写密集型 imagemagick 脚本的性能?
【发布时间】:2017-02-16 20:26:22
【问题描述】:

我使用 bash 脚本来处理延时电影的一堆图像。该方法称为快门拖动,我正在为所有图像创建移动平均值。以下脚本工作正常:

#! /bin/bash
totnum=10000
seqnum=40
skip=1
num=$(((totnum-seqnum)/1))
i=1
j=1
while [ $i -le $num ]; do
    echo $i
    i1=$i
    i2=$((i+1))
    i3=$((i+2))
    i4=$((i+3))
    i5=$((i+4))
    ...
    i37=$((i+36))
    i38=$((i+37))
    i39=$((i+38))
    i40=$((i+39))
    convert $i1.jpg $i2.jpg $i3.jpg $i4.jpg $i5.jpg ... \
            $i37.jpg $i38.jpg $i39.jpg $i40.jpg \
            -evaluate-sequence mean ~/timelapse/Images/Shutterdrag/$j.jpg 
    i=$((i+$skip))
    j=$((j+1))
done

但是,我注意到这个脚本需要很长时间来处理大量平均窗口较大的图像(每张图像 1 秒)。我想,这是由于在后台大量阅读和写作造成的。

可以提高这个脚本的速度吗?例如,将图像存储在内存中,每次迭代删除第一个图像,只加载最后一个图像。

我发现了imagemagick的mpr:{label}函数,但我想这不是正确的方法,因为在convert命令之后内存被清除了?

【问题讨论】:

  • 当您似乎多次读取每个图像时,您应该考虑制作一个 RAMdisk(您使用什么操作系统?)并将所有 JPEG 转换为 RAMdisk 上的MPC 格式文件以最小化解码负载 - 也可以使用 GNU Parallel。
  • Ubuntu 15.10 是我正在使用的操作系统。有没有简单的方法来设置和使用 RAMdisk?
  • 使用 OpenMP 支持重新编译 ImageMagick 将有助于提高 -evaluate-sequence 的性能(如果尚未启用)。
  • 我明天去看看 RAMdisk。不幸的是,编译不是我的选择。感谢您的帮助!

标签: bash image-processing imagemagick


【解决方案1】:

您无法在bash 中做任何事情来加快速度;除了convert 必须做的实际 IO 之外的所有事情都是微不足道的。但是,您可以大大简化脚本:

#! /bin/bash
totnum=10000
seqnum=40
skip=1
num=$(((totnum-seqnum)/1))


# Could use files=(*.jpg), but they probably won't be sorted correctly
for ((i=1; i<=totnum; i++)); do
  files+=($i.jpg)
done

for ((i=1, j=1; i <= num; i+=skip, j+=1)); do
  convert "${files[@]:i:seqnum}" -evaluate-sequence mean ~/timelapse/Images/Shutterdrag/$j.jpg
done

将文件存储在 RAM 磁盘中肯定会有所帮助,但这超出了本网站的范围。 (当然,如果你有足够的 RAM,操作系统应该在第一次读取文件后将文件保存在磁盘缓存中,以便后续读取更快,而无需预加载 RAM 磁盘。)

【讨论】:

  • 谢谢,这看起来好多了!
【解决方案2】:

建议 1 - RAMdisk

如果您想在开始之前将所有文件放在 RAMdisk 上,它应该会极大地提高 I/O 速度。

因此,要制作 1GB RAMdisk,请使用:

sudo mkdir /RAMdisk
sudo mount -t tmpfs -o size=1024m tmpfs /RAMdisk

建议 2 - 使用 MPC 格式

因此,假设您已完成上一步,请将您的所有 JPEG 文件转换为 RAMdisk 上的 MPC 格式文件。 MPC 文件可以直接 dma'ed 到内存中,而您的 CPU 不需要进行昂贵的 JPEG 解码,因为 MPC 与 ImageMagick 在内存中使用的格式相同,但在磁盘上。

我会像这样使用 GNU Parallel 来做到这一点:

parallel -X mogrify -path /RAMdisk -fmt MPC ::: *.jpg

-X 将尽可能多的文件传递给mogrify,而不会创建大量convert 进程。 -path 表示输出文件必须放在哪里。 -fmt MPC 使 mogrify 将输入文件转换为 MPC 格式(Magick Pixel Cache)文件,循环中的后续 convert 命令可以通过纯 DMA 而不是昂贵的 JPEG 解码来读取。

如果您没有或不喜欢 GNU Parallel,只需省略开头的 parallel -X:::

建议 3 - 使用 GNU Parallel

您也可以并行运行@chepner 的代码...

for ...; do
   echo convert ...
done | parallel

本质上,我是在回显​​所有命令而不是运行它们,然后回显命令列表由 GNU Parallel 运行。如果您无法按照 Eric 的建议使用 OpenMP 编译 ImageMagick,这可能特别有用。

您可以在parallel 之后使用诸如--eta 之类的开关来查看完成需要多长时间,或--progress。此外,根据您的机器的,尝试使用-j 2-j4


我做了一些基准测试,只是为了好玩。首先,我制作了 250 张 640x480 随机噪声的 JPEG 图像,然后运行 ​​chepner 的代码“as-is” - 耗时 2 分 27 秒。


然后,我使用了相同的图像集,但将循环更改为:

for ((i=1, j=1; i <= num; i+=skip, j+=1)); do
   echo convert "${files[@]:i:seqnum}" -evaluate-sequence mean ~/timelapse/Images/Shutterdrag/$j.jpg
done | parallel

时间减少到 35 秒。


然后我将循环恢复原状,并将所有输入文件更改为 MPC 而不是 JPEG,时间下降到 36 秒。


最后,我像上面一样使用了MPC格式 GNU Parallel,时间降到了19秒。

我没有使用 RAMdisk,因为我在与您不同的操作系统上(并且拥有非常快的 NVME 磁盘),但这也应该对您有很大帮助。您也可以将输出文件写入 RAMdisk,也可以采用 MPC 格式。

祝你好运,请告诉我们你的进展如何!

【讨论】:

  • 嘿,我终于有时间研究这个话题了。我使用了您的建议,它大大改善了处理过程。我选择 RAMdisk 为 4GB,然而,它只适合大约 150 张 2MP 分辨率的图像。因此,我正在使用一个循环来加载一堆图像,处理这些图像,然后将它们从 RAMdisk 中删除。以前是 1,11s/img (SSD),现在是 0,42s/img(RAM 上的 MPC)(40 个 img 窗口)。 Mogrify 使用-format MPC。非常感谢您的时间和帮助!
  • 太棒了!我很高兴它对你有用。祝你的项目好运。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2012-02-02
  • 2020-06-05
  • 2012-08-09
  • 2022-01-09
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多