2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 1 year has passed since last update.

ffmpegだけを使って、動画or複数の画像を1枚に合成する方法

Last updated at Posted at 2023-09-15

ffmpegだけで、動画の各フレームから画像合成を行いたかった

背景差分動画を作る時の背景画像が欲しいけど、ffmpeg 以外入れたくないとか言う人向け。
動画から連番画像を生成 → 生成した連番画像を1枚ずつ結合していく という力技をシェルスクリプトで行います。
Windowsの人は、WSLを入れましょう。

違うブレンド方法にしたいという方等は、頑張ってスクリプトをいじってください・・・。
合成のコマンド ffmpeg -i out_mixing.png -i $in_file -filter_complex "[0][1]blend=all_mode=average" -y temp.png は、「ffmpegを実行、 ストリーム[0]にout_mixing.pngを入力、ストリーム[1]に指定番号の連番画像を入力、ストリーム[0]と[1]を合成(blend)、対象色チャンネルは全て、合成方法は平均、temp.pngを出力(強制上書き)(入力がどちらも1コマなので、出力も1コマ)」です。
次のmvは、今の出力をリネームして次のループの入力にするため。
フレーム数は6桁まで対応(out000001.png と %06d ともに、1桁増やせば7桁にも対応可のはず。)

引数1:動画ファイル名
引数2:動画から連番画像を切り出す間隔をFPSで指定
引数3:結合する連番画像の枚数
出力ファイル:「./out_mixing.png」 固定
(処理途中で「./images_mixing_temp」というディレクトリを作成し、処理の最後で削除するので、同名のフォルダが無い所で実行してください。「./temp.png」 という画像も一時的に作られます。)

コマンド例
./image_mixing.sh input.mp4 1 60
(1分の動画であれば、1秒に1枚 合計60枚出力され、その60枚を1つの画像に結合します。)

image_mixing.sh
#!/bin/bash

# 引数1 動画ファイル名
# 引数2 動画から連番画像を作る時のFPS 2なら動画1秒あたり2枚出力
# 引数2 結合するファイル数 100ならout000001.png ~ out000100.png までの100枚を合成


# 引数が2個で無ければエラー表示して終了
if [ $# -ne 3 ]; then
  echo "引数の数が間違っています。"
  echo "引数1: 動画ファイル名"
  echo "引数2: 動画から連番画像を作る時のFPS"
  echo "引数3: 結合する画像ファイル数"
  exit 1
fi

# 引数を変数に格納
out_fps=$2
file_number=$3

# 一時フォルダを作成
mkdir -p images_mixing_temp

# 動画から連番画像を作成
ffmpeg -i $1 -vf "fps=$out_fps" images_mixing_temp/out%06d.png

# はじめの画像をコピーして out_mixing.png として使用
cp images_mixing_temp/out000001.png out_mixing.png

# 2番目以降の画像を全て合成していく
for i in `seq 2 $file_number`
do
	echo "画像を合成中... $i / $file_number"
	in_file="images_mixing_temp/out$(printf "%06d" $i).png"
	ffmpeg -i out_mixing.png -i $in_file -filter_complex "[0][1]blend=all_mode=average" -y temp.png
	mv temp.png out_mixing.png
done

# 一時フォルダを削除
rm -r images_mixing_temp

echo "すべての画像を合成しました。"

背景画像作成 (追記 2023/09/16)

上記の手順だと、必然的に、新しく合成する画像の比重が高くなり、積層されていった画像の比重が軽くなってしまうので、背景画像得るならこんな感じかなぁ。
opacity="1.0/$file_number" で合成する濃さを求め、ffmpegの [0][1]blend=all_mode=average:all_opacity=$opacity この部分で、合成比率を指定して合成するようになってます。
例えば、100枚なら、opacity=0.01 (元画像が0.99で、加える画像が0.01)で100回合成される。
(これも、完璧なブレンドになってない気もしますが。)

ちなみに、動画の先頭1分だけ背景画像欲しいとかなら、動画から連番静止画を吐くところ、
ffmpeg -i $1 -vf "fps=$out_fps" images_mixing_temp/out%06d.png
この-vfの前あたりにでも -t 60 とかを追加すればOKです。

create_background.sh
#!/bin/bash

#!/bin/bash

# 引数1 動画ファイル名
# 引数2 動画から連番画像を作る時のFPS 2なら動画1秒あたり2枚出力
# 引数2 結合するファイル数 100ならout000001.png ~ out000100.png までの100枚を合成


# 引数が2個で無ければエラー表示して終了
if [ $# -ne 3 ]; then
  echo "引数の数が間違っています。"
  echo "引数1: 動画ファイル名"
  echo "引数2: 動画から連番画像を作る時のFPS"
  echo "引数3: 結合する画像ファイル数"
  exit 1
fi

# 引数を変数に格納
out_fps=$2
file_number=$3

# 一時フォルダを作成
mkdir -p images_mixing_temp

# 動画から連番画像を作成
ffmpeg -i $1 -vf "fps=$out_fps" images_mixing_temp/out%06d.png

# はじめの画像をコピーして out_mixing.png として使用
cp images_mixing_temp/out000001.png out_mixing.png

# 2番目以降の画像を全て合成していく
for i in `seq 2 $file_number`
do
	echo "画像を合成中... $i / $file_number"

	in_file="images_mixing_temp/out$(printf "%06d" $i).png"
	opacity="1.0/$file_number"
	ffmpeg -i out_mixing.png -i $in_file -filter_complex "[0][1]blend=all_mode=average:all_opacity=$opacity" -y temp.png
	mv temp.png out_mixing.png
done

2つの画像を結合し、1つの画像を出力 (追記 2023/09/16 その2)

最初からこうすりゃ良かった。
力技だけど、シンプルに2枚の画像を1枚に結合するスクリプト。
(中間ファイル「./temp.png」が作成されて削除されます。)

image_composition.sh
#!/bin/bash

# 引数1 画像ファイル1"
# 引数2 画像ファイル2"
# 引数3 出力ファイル名"

# 引数が2個で無ければエラー表示して終了
if [ $# -ne 3 ]; then
	echo "Error: 引数の数が正しくありません"
	echo "引数1: 画像ファイル1"
	echo "引数2: 画像ファイル2"
	echo "引数3: 出力ファイル名"
	exit 1
fi

# 引数を変数に格納
file1=$1
file2=$2
file3=$3

ffmpeg -i $file1 -i $file2 -filter_complex "[0][1]blend=all_mode=average" -y temp.png
mv temp.png $file3
2
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
2
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?