フェードイン・アウトする動画をコマンドラインから作るスクリプト

高価な動画編集ソフト(premiere とか)がなくても動画作れちゃうんだぜ!

動画なんて,パラパラ漫画と同じ要領で作ればいいわけで.フレームごとに convert とかで画像作って mencoderエンコードすれば,どんなムービーでも作れる.動画作成頻度が低くて,高価なソフトを買いたくないし使い方を覚えたくない場合の処方箋を紹介.

ある画像から別の画像にフェードする動画生成スクリプト

ImageMagick に含まれる composite コマンドを使って,じょじょにある画像から別の画像にフェードする画像群を作り,それらを mencoderエンコードする.このスクリプトさえあれば,黒い画像からフェードインさせたり,白い画像にフェードアウトしたりする動画が簡単に生成できる.

ソース (fade-avi)
#!/bin/bash
usage="usage: fade-avi  FROM_IMG  TO_IMG  OUT_AVI [options]
  options:
    -fstep <1-100>    : FADE_STEP = fading speed. larger value is faster (default:1)
    -fclones <0-inf>  : FROM_CLONES = how many copies are put at the beginning? (default:0)
    -offset <0-100>   : OFFSET = initial value of the fading level (default=0)
    -fps <1-1000>     : FPS of the movie (default:50)
    -help             : show this"
source ~/lib/bash/option-parser.sh
set_single_opts help
parse_opts "$@"

if [ `opt help 0` -eq 1 ]; then
  echo "$usage"
  exit 1
fi
if [ ${#fargs[@]} -ne 3 ] ;then
  echo "invalid arguments."
  echo "$usage"
  exit 1
fi

img_from=${fargs[0]}
img_to=${fargs[1]}
out_file=${fargs[2]}

fade_step=`opt fstep 1`
from_clones=`opt fclones 0`
offset=`opt offset 0`
fps=`opt fps 50`


tmp_dir=/tmp/fadeavi$$

# generating fading images...
mkdir $tmp_dir
index=1
if [ $from_clones -gt 0 ];then
  basefile=$tmp_dir/frame`seq -w $index 10000 1000`.jpg
  convert -quality 100 $img_from $basefile
  index=$(($index+1))
  for i in `seq 2 1 $from_clones`; do
    echo -n " $i"
    cp $basefile $tmp_dir/frame`seq -w $index 10000 1000`.jpg
    index=$(($index+1))
  done
fi
tmp_img_from=/tmp/fadeavi$$-from.jpg
convert -quality 100 $img_from $tmp_img_from
for i in `seq $offset $fade_step 100`; do
  echo -n " $i"
  composite -dissolve $i -gravity South $img_to $tmp_img_from -matte \
    $tmp_dir/frame`seq -w $index 10000 1000`.jpg
  index=$(($index+1))
done
rm $tmp_img_from
echo ""

# generating movie encoded with avi...
mencoder "mf://$tmp_dir/frame*.jpg" -mf fps=$fps -ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=2400 -o $out_file

rm -r $tmp_dir
echo "$out_file is generated."

実行には ImageMagickmencoder が必要.また,コマンドラインオプションパーサ(~/lib/bash/option-parser.sh)が必要.

使い方
fade-avi  画像1  画像2  出力ファイル.avi [オプション]

のように使うと,画像1から画像2にフェードする動画(出力ファイル.avi)が生成される.

オプション:

  • fstep <1-100> : フェードのステップ.大きい程速くフェードする.(default:1)
  • fclones <0-inf> : 動画の最初で,画像1を何フレーム繰り返すか (default:0)
  • offset <0-100> : フェードレベルの初期値 (default=0)
  • fps <1-1000> : 動画のFPS (default:50)
  • help : ヘルプを表示
サンプル

Stanford BunnyからLennaにフェードさせた動画を生成.

fade-avi Stanford_Bunny.png lena_std.tif bunny_to_lenna.avi


タイトル文字列から画像にフェードする動画生成スクリプト

タイトル文字列を表示させて,それがじょじょに消えて行くと同時に,指定した画像がフェードインしてくる動画を生成するスクリプト

ソース (title-fade-avi)
#!/bin/bash
usage="usage: title-fade-avi  TITLE_STR  TO_IMG  OUT_AVI [options]
  options:
    -tcolor <r,g,b>     : title color (default:255,0,0)
    -tsize <1-inf>      : title font size (default=24)
    -bgcolor <r,g,b>    : background color (default:255,255,255)
    -fstep <1-100>      : FADE_STEP = fading speed. larger value is faster (default:2)
    -tdisptime <0-inf>  : TITLE_DISPLAY_TIME = how many frames is the title displayed in? (default:50)
    -tpos <x,y>         : title position (default:0,0)
    -fps <1-1000>       : FPS of the movie (default:50)
    -help               : show this"
source ~/lib/bash/option-parser.sh
set_single_opts help
parse_opts "$@"

if [ `opt help 0` -eq 1 ]; then
  echo "$usage"
  exit 1
fi
if [ ${#fargs[@]} -ne 3 ] ;then
  echo "invalid arguments."
  echo "$usage"
  exit 1
fi

title=${fargs[0]}
img=${fargs[1]}
out_file=${fargs[2]}

title_color=`opt tcolor 255,0,0`
title_size=`opt tsize 24`
bg_color=`opt bgcolor 255,255,255`
fade_step=`opt fstep 2`
title_display_time=`opt tdisptime 50`
title_pos=`opt tpos 0,0`
fps=`opt fps 50`


tmp_dir=/tmp/titlefadeavi$$
img_size=`identify -format "%wx%h" $img`


# generating fading images...
mkdir $tmp_dir
index=1
if [ $title_display_time -gt 0 ];then
  basefile=$tmp_dir/frame`seq -w $index 10000 1000`.jpg
  convert -quality 100 -size $img_size xc:"rgb($bg_color)" \
    -font Helvetica -pointsize $title_size -fill "rgb($title_color)" \
      -gravity Center -draw "text $title_pos '$title'" \
    $basefile
  index=$(($index+1))
  for i in `seq 2 1 $title_display_time`; do
    echo -n " $i"
    cp $basefile $tmp_dir/frame`seq -w $index 10000 1000`.jpg
    index=$(($index+1))
  done
fi
for i in `seq 255 -$fade_step 0`; do
  echo -n " $i"
  alpha=`echo "scale=5;$i/255"|bc`
  convert -quality 100 $img -size $img_size xc:"rgba($bg_color,$alpha)" -composite -compose Overlay \
    -font Helvetica -pointsize $title_size -fill "rgba($title_color,$alpha)" \
      -gravity Center -draw "text $title_pos '$title'" \
    $tmp_dir/frame`seq -w $index 10000 1000`.jpg
  index=$(($index+1))
done
echo ""

# generating movie encoded with avi...
mencoder "mf://$tmp_dir/frame*.jpg" -mf fps=$fps -ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=2400 -o $out_file

rm -r $tmp_dir
echo "$out_file is generated."

実行には ImageMagickmencoder が必要.また,コマンドラインオプションパーサ(~/lib/bash/option-parser.sh)が必要.

使い方
title-fade-avi  タイトル文字列  画像1  出力ファイル.avi [オプション]

のように使うと,タイトル文字列から画像1にフェードしていく動画(出力ファイル.avi)が生成される.

オプション:

  • tcolor : タイトル文字列の色 (default:255,0,0)
  • tsize <1-inf> : フォントサイズ (default=24)
  • bgcolor : 背景色 (default:255,255,255)
  • fstep <1-100> : フェードのステップ.大きい程速い (default:2)
  • tdisptime <0-inf> : タイトル文字列を何フレーム表示させるか (default:50)
  • tpos : タイトル文字列の位置 (default:0,0)
  • fps <1-1000> : 動画のFPS (default:50)
  • help : ヘルプを表示
サンプル

Lenna という文字列からLennaにフェードさせた動画を生成.

title-fade-avi -tsize 48 "Lenna" lena_std.tif lenna.avi


そのほかの技術

もっと多彩な動画を

convert コマンドを使えば,複数の画像をひとつの画像にまとめたり,文字列を配置したりできる.これをスクリプトで生成し,mencoderエンコードすれば,自由に動画が作れる.(が,なかなか一般化したスクリプトを作りにくいので,個別にスクリプトを書く必要があるorz..)

動画を連結
mencoder mov1.avi mov2.avi mov3.avi \
  -ovc lavc -lavcopts vcodec=msmpeg4v2:vbitrate=2400 -o all.avi

mov1.avi, mov2.avi, mov3.avi を連結した動画 all.avi を生成する.

動画を変換
ffmpeg -i all.avi -r 40 -b 400k all-d.mpg

all.avi (msmpeg4v2) を,フレームレートを40に,ビットレートを400kに下げ,mpeg1エンコードした動画 all-d.mpg に変換する.mencoder でも同様のことができるはずだが,mpeg1 への変換は mencoder より ffmpeg を使った方が安定して行えた(mencoder を使った場合,一部のプレーヤーで再生できないことがあった).