7. ビデオファイルの取り扱い#

.aviや.movファイルなどの標準的なビデオファイルから画像シーケンスを読み取る必要がある場合があります。

科学的な文脈では、通常、これらのフォーマットは避け、単純な画像ディレクトリまたは多次元TIFを使用する方が良いでしょう。ビデオフォーマットは、部分的に読み取ることがより困難であり、通常、ランダムフレームアクセスや研究向けのメタデータをサポートしておらず、注意深く設定しないと非可逆圧縮を使用します。しかし、ビデオファイルは広く使用されており、共有が容易であるため、必要に応じて読み書きできるようになっていると便利です。

ビデオファイルを読み取るためのツールは、インストールと使用の容易さ、ディスクとメモリの使用量、およびクロスプラットフォームの互換性において異なります。これは実践的なガイドです。

7.1. 回避策: ビデオを画像シーケンスに変換する#

1回限りの解決策としては、最も簡単で確実な方法は、ビデオを連続して番号が付けられた画像ファイルのコレクション(多くの場合、画像シーケンスと呼ばれます)に変換することです。その後、画像ファイルは、skimage.io.imread_collectionによってImageCollectionに読み取ることができます。ビデオをフレームに変換することは、バイオイメージングコミュニティのクロスプラットフォームGUIベースのプログラムであるImageJ、またはビデオファイルを操作するための強力なコマンドラインユーティリティであるFFmpegで簡単に行うことができます。

FFmpegでは、次のコマンドはビデオの各フレームから画像ファイルを生成します。ファイルには、5桁の番号が付けられ、左側にゼロが埋め込まれます。

ffmpeg -i "video.mov" -f image2 "video-frame%05d.png"

詳細は、画像シーケンスに関するFFmpegチュートリアルをご覧ください。

画像シーケンスの生成には欠点があります。大きくて扱いにくく、生成に時間がかかる場合があります。一般的には、元のビデオファイルを直接操作する方が望ましいです。より直接的な解決策として、PythonからFFmpegまたはLibAVを実行してビデオからフレームを読み取る必要があります。FFmpegとLibAVは、実際に使用されている多種多様なフォーマットからビデオをデコードする2つの大規模なオープンソースプロジェクトです。Pythonからそれらを使用するには、いくつかの方法があります。残念ながら、それぞれにいくつかの欠点があります。

7.2. PyAV#

PyAVは、FFmpeg(またはLibAV)のライブラリを使用して、ビデオファイルから直接画像データを読み取ります。Cythonバインディングを使用してそれらを呼び出すため、非常に高速です。

import av
v = av.open('path/to/video.mov')

PyAVのAPIは、ビデオファイルにフレームが格納される方法を反映しています。

import numpy as np
for packet in container.demux():
    for frame in packet.decode():
        if frame.type == 'video':
            img = frame.to_image()  # PIL/Pillow image
            arr = np.asarray(img)  # numpy array
            # Do something!

7.3. PyAVにランダムアクセスを追加する#

PIMSVideoクラスはPyAVを呼び出し、科学アプリケーションの一般的な問題であるフレーム番号によるビデオへのアクセスを解決するための追加機能を追加します。ビデオファイル形式は、時間によっておおよその方法で検索できるように設計されており、特定のフレーム番号を検索する効率的な手段をサポートしていません。PIMSは、ビデオ全体をデコード(ただし読み取りはしない)し、フレームによるインデックス付けをサポートする内部目次を作成することにより、この不足している機能を追加します。

import pims
v = pims.Video('path/to/video.mov')
v[-1]  # a 2D numpy array representing the last frame

7.4. MoviePy#

Moviepyは、サブプロセスを介してFFmpegを呼び出し、デコードされたビデオをFFmpegからRAMにパイプし、それを読み取ります。このアプローチは簡単ですが、不安定になる可能性があり、使用可能なRAMを超える大きなビデオには適していません。FFmpegがインストールされていれば、すべてのプラットフォームで動作します。

FFmpegの基盤となるライブラリにリンクしていないため、インストールは簡単ですが、約半分の速度です。

from moviepy.editor import VideoFileClip
myclip = VideoFileClip("some_video.avi")

7.5. Imageio#

ImageioはMoviePyと同じアプローチを採用しています。また、他の幅広い画像ファイル形式もサポートしています。

import imageio
filename = '/tmp/file.mp4'
vid = imageio.get_reader(filename,  'ffmpeg')

for image in vid.iter_data():
    print(image.mean())

metadata = vid.get_meta_data()

7.6. OpenCV#

最後に、もう1つの解決策は、OpenCVのVideoReaderクラスです。これはFFmpegへのバインディングを持っています。他の理由でOpenCVが必要な場合は、これが最良のアプローチかもしれません。