見出し画像

Pythonコードで動画のFPSを下げる方法

生き物の行動観察をしようと、動画撮影したはいいが、動画解析にかかる時間とパソコンの処理能力の限界を感じて、動画の質を下げたいと思っている研究者の方は多いと思います。
本記事では、30 fpsで撮影した録画データ(mp4)を半分の15 fps
さらに1 fpsまで動画の質を下げる方法を紹介します。



作業環境

今回は、google様のColaboratoryを用いてPythonコードを実行しますので、googleアカウントが必要です。
なくてもPythonコードが実行できる環境でしたら大丈夫です。 

Colaboratoryを開く

google chromeのホーム画面の右上の「Googleアプリ」から「ドライブ」を開きます。
左上の「+新規」から「その他」へ、そして「Google Colaboratory」に進みます。
これで、Pythonコードを書く準備ができました。

動画の読み込み(アップロード)

まずは、動画のデータを読み込みます。
一つ目のセルに以下のコードをコピペし、実行▶️します

from google.colab import files

# 動画ファイルをアップロードする
uploaded = files.upload()

実行▶️すると、「ファイル選択」というボタンが出てくるので、動画ファイルを選択します。
アップロードが完了すると、左側のファイル欄に動画データが表示されます。

OpenCVをインストール

次に、Pythonで動画などを処理することができるライブラリの「OpenCV」をインストールします。

# OpenCVのインストール

!pip install opencv-python
!pip install opencv-python-headless

これで動画処理の準備は完了です。

動画処理① 30 fpsを15 fpsに

以下のコードを実行▶️すれば、15 fpsに変換されたファイルが出力されます。

import cv2

# 入力ファイルと出力ファイルの指定
input_file = "input.mp4"
output_file = "output_15fps.mp4"

# 動画を読み込む
cap = cv2.VideoCapture(input_file)

# 動画のプロパティを取得
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')

# 出力動画の設定 (15fpsで保存)
out = cv2.VideoWriter(output_file, fourcc, 15.0, (width, height))

frame_count = 0
while True:
    ret, frame = cap.read()
    if not ret:
        break
    # 2フレームに1フレームを抽出 (30fpsを15fpsに変換)
    if frame_count % 2 == 0:
        out.write(frame)
    frame_count += 1

# リソースを解放
cap.release()
out.release()
cv2.destroyAllWindows()

print(f"変換完了: {output_file}")

動画処理①の解説

1. ライブラリのインポート

import cv2

先ほどインストールしたOpenCVをインポートすることでOpenCVを使うことができます。

2. 入力ファイルと出力ファイルの指定

input_file = "input.mp4" 
output_file = "output_15fps.mp4"

input_file には変換したい動画ファイルを指定します。
output_file には変換後に保存する動画ファイル名を指定します。

3. 動画の読み込み

cap = cv2.VideoCapture(input_file)

cv2.VideoCapture は、指定した動画ファイルを読み込む関数です。これで、動画ファイルをプログラム内で操作できるようになります。

4. 動画のプロパティを取得

fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')

cap.get(cv2.CAP_PROP_FPS) で、元の動画のフレームレート(ここでは30fps)を取得します。
cv2.CAP_PROP_FRAME_WIDTHcv2.CAP_PROP_FRAME_HEIGHT で、動画の幅と高さを取得し、変換後の動画にも同じサイズを適用します。cv2.VideoWriter_fourcc(*'mp4v') は、動画のエンコード方法を指定します。ここでは、MP4形式で出力するために指定しています。

5. 出力動画の設定

out = cv2.VideoWriter(output_file, fourcc, 15.0, (width, height))

cv2.VideoWriter を使って、動画を書き出す設定をします。
出力する動画は15fpsで保存するので、第3引数には15.0を指定しています。これにより、動画の再生速度が15fpsになります。

6. フレームの抽出と保存

frame_count = 0
while True:
    ret, frame = cap.read()
    if not ret:
        break
    if frame_count % 2 == 0:
        out.write(frame)
    frame_count += 1

cap.read() で動画から1フレームずつ読み込みます。ret が False になった場合は、動画が終了したことを意味します。
フレーム番号(frame_count)が偶数のときだけ(2で割って、余りが0になる場合)フレームを出力し、奇数のフレームはスキップします。これにより、2フレームに1フレームを抽出して15 fpsに変換できます。
30 fpsでは1秒間に30フレームが再生されますが、その半分の15フレームだけを書き出すことで、動画の再生速度を15fpsに落とすことができます。

7. リソースの解放

cap.release()
out.release()
cv2.destroyAllWindows()

処理が終わった後は、読み込んだ動画と書き出した動画を解放して、リソースを適切に閉じます。これにより、メモリリークを防ぎます。

8. 処理完了メッセージ

print(f"変換完了: {output_file}")

最後に、動画の変換が完了したことを知らせるメッセージを表示します。

動画処理② 30 fpsを1 fpsに

基本的に構造は同じですが、処理の部分だけが異なります。

import cv2

# 入力ファイルと出力ファイルの指定
input_file = "input.mp4"
output_file = "output_1fps.mp4"

# 動画を読み込む
cap = cv2.VideoCapture(input_file)

# 動画のプロパティを取得
fps = cap.get(cv2.CAP_PROP_FPS)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fourcc = cv2.VideoWriter_fourcc(*'mp4v')

# 出力動画の設定 (1fpsで保存)
out = cv2.VideoWriter(output_file, fourcc, 1.0, (width, height))

frame_count = 0
while True:
    ret, frame = cap.read()
    if not ret:
        break
    # fps分のフレームをスキップして、1fpsの間隔でフレームを取得
    if frame_count % int(fps) == 0:
        out.write(frame)
    frame_count += 1

# リソースを解放
cap.release()
out.release()
cv2.destroyAllWindows()

print(f"変換完了: {output_file}")

動画処理②の解説

動画処理①では偶数(2で割り切れる)のフレームだけを用いましたが、1 fpsではこの部分が異なります。

frame_count = 0
while True:
    ret, frame = cap.read()
    if not ret:
        break
    # fps分のフレームをスキップして、1fpsの間隔でフレームを取得
    if frame_count % int(fps) == 0:
        out.write(frame)
    frame_count += 1

1 fpsにする処理では、元の画像のfpsで割り切れるframe_countの時だけ動画を使うように処理しています。元の動画は30 fpsなので、30枚に1枚だけということです。

処理後の動画のダウンロード

あとは出力されたファイルをダウンロードすれば完成です。
ファイル欄にある出力ファイルを右クリックして「ダウンロード」するだけです。

注意点

Colaboratoryではセッション(一連の作業)が中断すると、その間にアップロードしたデータや出力結果のデータが消去されてしまいます。作業が完了したら、速やかに保存やダウンロードを行ってください。

動画データが重たい場合

動画が何時間もあるような重たいデータの場合、ColaboratoryではGoogle様のグラフィックボード(GPU)をお借りして処理することができます(時間制限あり)。
メニューの「ランタイム」から「ランタイムのタイプを変更」へ進むと「GPU」を選択することができます。これで動画処理は爆速で終わるでしょう!

まとめ

この方法では、30fpsの動画を15fpsに変換するために、2フレームに1フレームを抽出する方法と、30フレーム分の1フレームを抽出するアプローチを取っています。OpenCVの基本的な操作を理解し、フレームをスキップすることで任意のフレームレートに変換することができます。このコードを使えば、他のフレームレートへの変換も簡単に応用できるので、試してみてください。

この記事が気に入ったらサポートをしてみませんか?