20250907001

自動で字幕シーン抽出!|シェルスクリプト編

著者: 管理者 / 2025-09-07 (更新: 2025-09-07)

動画編集や字幕作成をしていると、「この動画の字幕部分だけを抜き出したい」 と思うことはありませんか?
1秒ごとにスクショを撮って確認して…なんてやっていたら、とても時間がかかってしまいます。

そこで今回は、ffmpeg + ImageMagick + Tesseract OCR を組み合わせたシェルスクリプトで、
「動画から字幕が表示されているシーンだけを自動抽出」する方法を紹介します。

ストーリー仕立てで学びつつ、技術的なポイントも整理していきましょう。


user01 Surprised
まあ!動画から字幕だけを自動で抜き出せるなんて、まるで魔法みたいですわ ✨
わたくし、字幕作成でスクショ地獄に陥っておりましたのに……!
user02 Happy
ふふ、便利な仕組みでしょう。
今回は Bash スクリプトを使って、フレーム抽出 → 類似シーン削除 → OCR で字幕検出 → タイムスタンプ整理、という流れを実現しています。

📝 スクリプト全文

cd /Users/ここにユーザー名/Downloads/字幕作成

THRESH=0.02
for VIDEO in *_small.mp4; do
  [ -f "$VIDEO" ] || continue
  BASE="${VIDEO%_small.mp4}"
  OUTDIR="${BASE}_frames"
  mkdir -p "$OUTDIR"
  ffmpeg -y -i "$VIDEO" -vf fps=1 -q:v 3 "$OUTDIR/frame_%04d.jpg"

  cd "$OUTDIR"
  prev=""
  for img in $(ls -1 frame_*.jpg); do
    if [ -z "$prev" ]; then prev="$img"; continue; fi
    AE=$(compare -metric AE -fuzz 5% "$prev" "$img" null: 2>&1 || echo 99999999)
    read W H < <(identify -format "%w %h" "$img")
    PIXELS=$((W * H))
    RATIO=$(awk -v ae="$AE" -v p="$PIXELS" 'BEGIN{ if(p==0){print 1} else {printf "%.8f", ae/p} }')
    if (( $(echo "$RATIO <= $THRESH" | bc -l) )); then rm "$img"; else prev="$img"; fi
  done

  for img in frame_*.jpg; do
    text=$(tesseract "$img" stdout -l jpn+eng 2>/dev/null | tr -d '[:space:]')
    if [ -z "$text" ]; then
      echo "削除: $img (文字なし)"
      rm "$img"
    fi
  done

  i=0
  : > timestamps_kept.txt
  for f in $(ls -1 frame_*.jpg); do
    printf "%02d:%02d  %s\n" $((i/60)) $((i%60)) "$(basename "$f")" >> timestamps_kept.txt
    i=$((i+1))
  done
  cd ..
done


user01 Calm
先生、このスクリプトはなかなか長いですわね。どの部分で字幕を検出しているのか、わたくし少し混乱いたしましたの……💦
user02 Serious
大丈夫ですよ。ポイントごとに区切って整理すれば、処理の流れはシンプルです。
解説していきましょう。

📝 スクリプトの処理フロー

1. 動画をフレームに分割

ffmpeg -vf fps=1
  • 動画を 1秒ごとに静止画 として切り出し
  • frame_0001.jpg のように保存
  • 素材作りの段階

2. 類似フレームの削除

compare -metric AE -fuzz 5%
  • 前フレームとの差分を算出
  • 違いが 2%以下なら削除(ほぼ同じ画像)
  • シーンチェンジのみ残す → 重複を間引いて効率化

3. OCRで字幕検出

tesseract -l jpn+eng
  • 画像に写っている文字を OCR で解析
  • 日本語+英語に対応
  • テキストが見つからなければ削除
  • 字幕を含む画像だけ残る

4. タイムスタンプを付与

printf "%02d:%02d  %s\n"
  • 残ったフレームを時系列で整理
  • timestamps_kept.txt00:01 frame_0001.jpg のように出力
  • 字幕シーンのリスト化が完成

user01 Happy
なるほどですわ! ✨
無駄なフレームを削除してから OCR で検出しているのですのね。
それなら字幕付きのシーンだけを効率よく集められますわ!
user02 Calm
その通りです。最終的には、`timestamps_kept.txt` を整形すれば YouTube のチャプターリストや字幕ファイル (SRT) にも応用できます。

📝 出力イメージ

  • video_frames/ ディレクトリ
    • frame_0005.jpg(字幕あり)
    • frame_0012.jpg(字幕あり)
  • timestamps_kept.txt
00:05  frame_0005.jpg
00:12  frame_0012.jpg
...

📝 応用例

  • 🎥 YouTube動画の自動チャプター生成
  • 📚 映像講義からスライド+字幕要約の抽出
  • 🌍 翻訳用データ作成(字幕付き動画を多言語展開)

user01 Serious
先生、このスクリプトは便利ですけれど、改善できる部分もあるのでしょうか?
user02 Happy
ええ、もちろんです。例えば:

- `fps=1` を変更して 0.5秒ごと/2秒ごとに調整
- OCR結果を 別ファイルに保存して翻訳や検索に活用
- `timestamps_kept.txt` を直接 SRT形式に変換

これらを組み合わせれば、さらに実用的になります。

✅ まとめ

今回学んだポイント:

  • 🎞 ffmpeg で動画をフレーム化
  • 🗑 ImageMagick で類似フレーム削除
  • 🔍 Tesseract OCR で字幕検出
  • タイムスタンプ整理で字幕リスト化

このスクリプトにより、面倒な「動画を見ながら字幕シーンを探す作業」が 全自動化 できます。


user01 Happy
先生、とてもよく分かりましたわ!これならわたくしの字幕作成も楽になりますのね 💕
次は SRTファイルに変換する方法を学んでみたいですわ!
user02 Calm
良い目標ですね。次回は、今回のスクリプトを拡張して 自動で字幕ファイルを生成する方法 を取り上げましょう。