フォトグラメトリ用に4K解像度のドローン動画から1秒おきにフレーム切り出してJPEG画像に保存したい話―ドローン+ffmpeg+Reality Capture―

タイトルの通り、ちょっと地味な内容ですが、毎度やり方を忘れそうになるので、自分用のメモとして記録します。

動画をもとにフォトグラメトリをやりたいとき、ソフト側が動画読み込みに対応している場合も多いですが、たとえば、「現場で撮った動画を会社にある高性能PCで処理したいんだけど、動画そのまま送るには回線が貧弱で……」というような場合に、このワザが役立つかもしれません。

前に書いたコードを使い回す

以前の記事で、FFmpegを使って、360°動画から画像を切り出す方法について書きましたが

www.creativity-ape.com

今回はこれをちょこっと改造する(というか、ほぼオプションを削る)だけです。

あと、FFmpegをPythonから触りたいとき、FFmpeg-PythonなるPythonラッパーもあるようですが、今回はそれほど複雑ではないので、Subprocessでコマンド直叩きします。コマンドが複雑になる場合には便利そうです。

github.com

Pythonコード

ということで、さっそくですが、こちらが出来上がったコードです。

詳しいことは、インラインのコメントから読み解いてください。

import subprocess
import os
import sys
import glob

# 引数でディレクトリを指定、動画ファイルだけ
input_path = sys.argv[1]
print(input_path)

# ディレクトリだったら
if os.path.isdir(input_path):

  # ファイルパスをリストにして突っ込む
  files = glob.glob(input_path + '/*.*')

# ファイルだったら
elif os.path.isfile(input_path):

  # ファイルパスを突っ込む
  files = [input_path]

  # こっちはディレクトリパスに置き換える
  input_path = os.path.dirname(input_path)

else:
  # どっちでもなければ雑にエラー処理
  files = []
  print('不正なインプットです。')

for input_file_path in files:
  input_file_name = os.path.splitext(os.path.basename(input_file_path))[0]
  
  # 画像切り出しのフレームレート、ドローンの飛行速度・高度に合わせて適当に決める
  output_fps = 1
  
  # JPEGの品質、1が最高
  output_quality = 1

    # 出力フォルダをつくる
  output_dir_path=fr'{input_path}/{input_file_name}_frames'
  os.makedirs(output_dir_path, exist_ok=True)

  # 出力ファイル名とパスをつくる
  output_file_name=fr'{input_file_name}-%06d.jpg'
  output_file_path=fr'{output_dir_path}/{output_file_name}'

  # コマンドを組み立てる
  commands = [
    'ffmpeg',
    f'-i "{input_file_path}"',
    f'-q:v {output_quality}',
    f'-r {output_fps}',
    f'"{output_file_path}"'
    ]
  command = ' '.join(commands)
  print(command)

  # ffmpeg実行
  subprocess.call(command, shell=True)

print('完了しました。')

これをコピーして、Pythonスクリプトとして保存します。名前はとりあえず「video2jpg.py」とでもしておきましょう。

使い方

Python video2jpg.py入力フォルダorファイルパス

フォルダを指定するとその直下のファイルを一括処理、ファイル指定なら単体処理が走ります。

ためしに1つやってみると

こんな感じです。

ファイルサイズは…

ファイルサイズを92%カットすることができました! このサイズなら、通信環境が悪くてもなんとか送れそうです。途中で区切って分割送信って手も使えますね。

それでは、今日はここまで。