OpenCV

【Python】OpenCVによる動画入出力の基本 ~VideoCapture, VideoWriter~

【Python】OpenCVによる動画入出力の基本 ~VideoCapture, VideoWriter~

PythonでOpenCVを使って動画を入出力する方法について解説します。

OpenCVによる動画入出力

OpenCVは、有名なコンピュータービジョンのライブラリです。OpenCVのPythonバインドであるcv2モジュールを使用することで、PythonでOpenCVの機能を使用することができます。

OpenCVでは、動画の入出力のためのクラスとして、VideoCaptureVideoWriterというクラスが用意されています。AVIファイル等多くのフォーマットをサポートしますが、対応可能な動画フォーマットはOSやOpenCVの構成により異なります。これらのクラスは、動画ファイルをBGRフォーマットのフレーム画像として取得します。

この記事では、PythonでOpenCVを使って画像を入出力する方法について紹介します。

画像の読み込みやOpenCVでの画像表現(BGR)については「OpenCVによる画像入出力の基本 ~imread, imwrite~」でまとめているので参考にしてください。

VideoCapture、VideoWriterによる動画の読み込み、書き込み

ここでは、VideoCaptureクラス及びVideoWriterクラスを用いた動画の読み込みや書き込みについて紹介します。

基本的な使い方

VideoCaptureクラスを使用して動画を読み込み、VideoWriterクラスを使用して別の動画ファイルとして書き込みを行ってみましょう。VideoCaptureVideoWriterは、以下のように使用します。

import cv2

# VideoCaptureのインスタンスを生成
video_capture = cv2.VideoCapture("sample.avi")
if not video_capture.isOpened():
    print("ファイルが開けませんでした。")
    exit()

# FPSの取得
fps = video_capture.get(cv2.CAP_PROP_FPS)
# サイズの取得 (width, height)
size = (
    int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)),
    int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)),
)
print(f"fps: {fps}")
print(f"Width: {size[0]}, Height: {size[1]}")

# VideoWriteのインスタンスを生成
video_writer = cv2.VideoWriter(
    "output_i420_sample.avi", cv2.VideoWriter_fourcc(*"I420"), fps, size
)
if not video_writer.isOpened():
    print("VideoWriterの生成に失敗しました。")
    video_capture.release()
    exit()

# 動画の読み込み
success, frame = video_capture.read()
# フレームがなくなるまで繰り返しで読み込み
while success:
    video_writer.write(frame)
    success, frame = video_capture.read()

# リソースの解放
video_capture.release()
video_writer.release()
【実行結果】
23.976
(720, 528)

上記のプログラムの各ポイントを説明していきます。

【モジュールのインポート】

import cv2

OpenCVの機能を使用するためにcv2モジュールをインポートしておきます。

VideoCaptureインスタンス作成と動画情報の取得】

# VideoCaptureのインスタンスを生成
video_capture = cv2.VideoCapture("sample.avi")
if not video_capture.isOpened():
    print("ファイルが開けませんでした。")
    exit()

# FPSの取得
fps = video_capture.get(cv2.CAP_PROP_FPS)
# サイズの取得 (width, height)
size = (
    int(video_capture.get(cv2.CAP_PROP_FRAME_WIDTH)),
    int(video_capture.get(cv2.CAP_PROP_FRAME_HEIGHT)),
)
print(f"fps: {fps}")
print(f"Width: {size[0]}, Height: {size[1]}")

動画ファイルを読み込むには、VideoCaptureのインスタンス生成時に動画ファイルパスを指定します。また、ファイルが開けなかったことの確認に、isOpenedメソッドを使用しています。

動画の情報を取得するにはgetメソッドを使用することができます。例えば、動画で1秒間に表示されるフレーム数はFPS (Frame Per Second)と言いますが「fps = video_capture.get(cv2.CAP_PROP_FPS)」で取得できます。同様に動画のフレームの幅 (cv2.CAP_PROP_FRAME_WIDTH)や高さ (cv2.CAP_PROP_FRAME_HEIGHT)を取得しています。

他にも様々なプロパティとなるenumが用意されていますが、詳細は公式ドキュメントのFlags for video I/OのページにおけるVideoCapturePropertiesを参考にしてください。

VideoWriterインスタンス作成】

# VideoWriteのインスタンスを生成
video_writer = cv2.VideoWriter(
    "output_i420_sample.avi", cv2.VideoWriter_fourcc(*"I420"), fps, size
)
if not video_writer.isOpened():
    print("VideoWriterの生成に失敗しました。")
    video_capture.release()
    exit()

動画書き込み用のインスタンスを作成する際には、上記のように「出力ファイルパス」「fourcc」「FPS」「サイズ (幅, 高さ)」をVideoWriterの引数で指定します。今回は読み込んだファイルを別名で出力しているのでfpssizeは上記においてgetで取得した元ファイルのFPSとサイズをそのまま指定しています。

ここで、fourccは「Four Character Code」の略で、ビデオファイルのコーデックを指定するための4文字のコードのことです。cv2.VideoWriter_fourcc(*"I420")は、AVIファイルの指定でよく使用されるもので、非圧縮のYUVエンコーディングを使用します。また、この引数の部分に0を指定すると非圧縮の生データとなります。

cv2.VideoWriter_forccは、4つの引数を受け取る関数ですが「*」を使って文字列を分解して渡しています。つまり「cv2.VideoWriter_fourcc("I", "4", "2", "0")」と同じ意味になります。

また、インスタンスが生成できなかったことの確認に、isOpenedメソッドを使用しています。

【動画フレームの読み込みと動画の書き込み】

# 動画の読み込み
success, frame = video_capture.read()
# フレームがなくなるまで繰り返しで読み込み
while success:
    video_writer.write(frame)
    success, frame = video_capture.read()

上記の部分は、動画を読み込みつつ動画を別ファイルに書き込んでいる部分です。

読み込みには、VideoCapturereadメソッドを使用します。readは、読み込みが成功したか否かのフラグとフレームが返却され、再び実行すると次のフレームを取得します。フレームが取得成功する限りwhileで読み込みを続けることで、元データのフレームをすべて取得しています。

読み込みと並行してVideoWriterのwriteメソッドで、読み込んだフレームを指定することで動画ファイルを書き込んでいます。

【リソースの解放】

# リソースの解放
video_capture.release()
video_writer.release()

プログラムの終わりでは、VideoCaptureVideoWriterのオブジェクトを適切に開放することが重要です。リソースの解放は、releaseメソッドを使用することで実行できます。

MP4ファイルでの書き込み

上記では、AVIファイルで"I420"(非圧縮のYUVエンコーディング)を使用しました。これは、広く使用されるものですが、ファイルサイズが大きくなります。

VideoWriterは、様々なビデオコーデックに対応します。例えばMP4ファイルは出力サイズを制限したいときによい選択肢です。MP4ファイルでの書き込みをする場合には、以下のようにavc1 (Advanced Video Coding 1)等を指定することが可能です。

# VideoWriteのインスタンスを生成
video_writer = cv2.VideoWriter(
    "output_avc_sample.mp4", cv2.VideoWriter_fourcc(*"avc1"), fps, size
)

avc1は、H.264コーデックを使用するものでMP4ファイル形式に出力する際には一般的に使用されます。非常に効率的な圧縮がされ、広く互換性があります。

エラーが出た場合の対処法

avc1を指定した場合には、以下のようなエラーが出る場合があります。

Failed to load OpenH264 library: openh264-1.8.0-win64.dll
	Please check environment and/or download library: https://github.com/cisco/openh264/releases

このエラーは、openh264-1.8.0-win64.dllの読み込みに失敗したとあるため、必要な環境が整っていないことを意味しています。エラーもあるようにhttps://github.com/cisco/openh264/releasesから必要なDLLをダウンロードして対応します。

openh264-1.8.0-win64.dll.bz2というバージョンをダウンロードし、ファイルを解凍してください。BZ2形式で圧縮されているので7-ZipやWinRAR等の解凍ソフトで解凍が必要です。

解凍して取得したファイル(openh264-1.8.0-win64.dll)をアプリケーションが参照できるパスに配置します。もっとも簡単な方法は実行プログラムと同じフォルダに配置することですが、その他にもPATHが設定されているフォルダを使用することが可能です。

様々なコーデックへの対応

今回は、AVIファイルを出力する際の"I420"やMP4ファイルを出力する際の"avc1"を例にしましたが、コーデックは他にも色々と使用することができますので色々と調べてみてください。例えば、OGVファイル("THEO")、FLVファイル("FLV1")のようなものもあります。

ただし、上記MP4の例でエラーが発生したように各コーデックで適切に出力できるかどうかは、お使いのOpenCVのバージョンやOSの種類、実行環境において適切なライブラリが存在するかなどに依存することに注意してください。

まとめ

PythonでOpenCVを使って動画を入出力する方法について解説しました。

OpenCVでは、動画の入出力のためのクラスとして、VideoCaptureVideoWriterというクラスが提供されています。AVIファイル等多くのフォーマットをサポートしますが、対応可能な動画フォーマットはOSやOpenCVの構成により異なります。

この記事では、VideoCaptureVideoWriterを使って基本的な読み込みや書き込みの方法を紹介しました。書き込み例としてはAVIファイルやMP4ファイルを題材にしました。

OpenCVは、非常に強力なコンピュータビジョンのライブラリで、動画の入出力は画像を扱うにあたっての基本となります。しっかりと使い方を理解していただきたいと思います。