我使用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
命令之后内存被清除了?
答案 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磁盘。)