如何提高读写密集型imagemagick脚本的性能?

时间:2016-10-07 18:47:49

标签: bash image-processing imagemagick

我使用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命令之后内存被清除了?

2 个答案:

答案 0 :(得分:3)

建议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文件可以直接进入内存而不需要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 ,这可能会特别有用。

您可以在--eta之后使用parallel等开关来查看完成所需的时间,或--progress。另外,请尝试-j 2-j4,具体取决于 big 您的计算机。

我做了一些基准测试,只是为了好玩。首先,我以640x480制作了250张随机噪音的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格式。

祝你好运,让我们知道您的成功!

答案 1 :(得分:2)

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磁盘。)