Bash - 将数字变量插入命令

时间:2016-02-16 19:09:35

标签: linux image bash image-processing imagemagick

我一直想要一个覆盖视频的计时计时器,但我在网上找到的所有内容都是使用Adobe After Effects,这不是我真的可以选择的选项。 Linux并且我不愿意付钱。

因此,如果我可以获得一系列图像或视频,那么可以将其导入到Openshot中以非常好地覆盖视频,但是获取所述一系列图像或视频却很困难。

我已经开始编写脚本来制作一系列图像,但不知道如何将变量放入命令中。这是目前形式的脚本:

#!/bin/bash
for i in {0..18000000}
do
    echo "$i"
    convert -size 780x100 xc:#d3fff5ff -font Courier-New -pointsize 100 -fill black -draw "text 20,80 '000:00:00.00'" 0.png
done

我想要的是0.png基本上是$ i.png,所以它增加到18,000,000。时间(显示为000:00:00.00)在知道如何将变量插入命令后,我可能会自己解决。时间格式为小时,分钟,秒和帧。

以下是一个例子,如果我解释得很糟糕(对不起间距 - 由于某些原因,只有两条新线才能在这里工作):

0.png = 000:00:00.00

1.png = 000:00:00.01

49.png = 000:00:00.49

50.png = 000:00:01.00

51.png = 000:00:01.01

18000000.png = 100:00:00.00

3 个答案:

答案 0 :(得分:2)

计算小时,分钟,秒和帧的数学计算非常简单:

f=$(( i % 50 ))
s=$(( (i/50) % 60 ))
m=$(( (i/(50*60)) % 60 ))
h=$(( (i/(50*60*60)) ))

然后你可以简单地将值嵌入字符串中,如下所示:

... -draw "text 20,80 '$(printf "%03d:%02d:%02d.%02d" $h $m $s $f)'" "$i.png"

更大的问题是运行convert 1800万次需要多长时间。

答案 1 :(得分:1)

如果Bash不是单引号,则Bash会扩展命令中的变量。在这里,它们是双引号:

convert -size 780x100 xc:#d3fff5ff -font Courier-New -pointsize 100 -fill black -draw "text 20,80 '$hours:$minutes:$seconds.$frames'" $i.png

请注意,{0..18000000}首先会扩展为18M字符串列表。使用C风格的循环可能更好:

for (( i=0 ; i<=18000000 ; i++ )) ; do

另一个问题可能是拥有一个包含18M文件的目录。也许将它们存储在像小时/分钟/秒的文件夹中?

答案 2 :(得分:1)

这种建立在chepner和choroba的答案之上,但也解决了如何使用所有CPU核心生成18,000,000个图像。我在一个不错的规格iMac上对3种不同的方法进行了基准测试,并取得了以下结果 - 从最简单,最慢,从那里开始到更快的方法......

方法1 - 普通顺序bash脚本

#!/bin/bash
for ((i=0; i<18000000; i++ )); do
   f=$(( i % 50 ))
   s=$(( (i/50) % 60 ))
   m=$(( (i/(50*60)) % 60 ))
   h=$(( (i/(50*60*60)) ))
   convert -size 780x100 xc:#d3fff5ff -font Courier -pointsize 100 -fill black -draw "text 20,80 '$(printf "%03d:%02d:%02d.%02d" $h $m $s $f)'" $i.png
done

生成1800万张图片大约需要4.6天。

方法2 - GNU并行脚本

#!/bin/bash

# Define a function for GNU Parallel to run
doit() {
   i=$1
   f=$(( i % 50 ))
   s=$(( (i/50) % 60 ))
   m=$(( (i/(50*60)) % 60 ))
   h=$(( (i/(50*60*60)) ))
   convert -size 780x100 xc:#d3fff5ff -font Courier -pointsize 100 -fill black -draw "text 20,80 '$(printf "%03d:%02d:%02d.%02d" $h $m $s $f)'" $i.png
}

# Export doit() function so GNU Parallel knows about it
export -f doit

ulimit -S -n 2048

for ((i=0;i<=18000000;i++)); do
   echo $i
done | parallel -k doit {1} 

这使您的所有CPU内核保持忙碌,大约需要32小时才能生成1800万个文件。我认为与必须编写代码并在下一个答案中编译和构建代码相比,这是一个非常好的折衷方案。

方法3 - Magick ++程序并行运行8个副本

#include <Magick++.h>

using namespace std;
using namespace Magick;

int main(int argc, char* argv[]){

   // Pick up parameters
   if(argc!=3){
      printf("ERROR: Please supply 2 arguments - start and end number\n");
      exit(EXIT_FAILURE);
   }
   int start=atoi(argv[1]);
   int end  =atoi(argv[2]);

   InitializeMagick(*argv);

   // Create a basic template
   Image img(Geometry(780,100),Color("#d3fff5ff"));
   img.font("Courier");
   img.fillColor(Color("black"));
   img.fontPointsize(100);

   // Get cycling through the images
   for(int i=start;i<=end;i++){
      // Work out timestamp for this frame
      int f=i % 50;
      int s=(i/50) % 60;
      int m=(i/(50*60)) % 60;
      int h=(i/(50*60*60));
      char timestamp[100];
      sprintf(timestamp,"%03d:%02d:%02d.%02d",h,m,s,f);

      // Copy the basic template image
      Image thisframe=img;
      thisframe.draw(Magick::DrawableText(20,80,timestamp));
      char filename[100];
      sprintf(filename,"%d.gif",i);
      thisframe.write(filename);
   }
}

以下是并行运行8个副本的方法:

#!/bin/bash
./main 1 2250000 &
./main 2250001 4500000 &
./main 4500001 6750000 &
./main 6750001 9000000 &
./main 9000001 11250000 &
./main 11250001 13500000 &
./main 13500001 15750000 &
./main 15750001 18000000 &
wait

生成1800万个文件需要不到9个小时。