動画を扱う

目的

  • 動画ファイルの読み込み方,表示方法,保存方法を学ぶ
  • パソコン(PC)に接続したカメラで撮影した映像を表示する方法を学ぶ
  • 次の関数の使い方を学ぶ : cv2.VideoCapture(), cv2.VideoWriter()

カメラから動画を撮影する

OpenCVはカメラを使って動画を撮影するための非常に簡単なインタフェースを用意している.初めの一歩として、カメラ(私はノートPCに備え付けのウェブカメラを使っている)で撮影した動画を白黒(グレースケール)の動画に変換して表示させてみよう.

動画を撮影するにはまず VideoCapture(device)関数を用いてVideoCapture 型のオブジェクトを生成する.関数の引数deviceは撮影に用いるカメラのデバイス番号を指定する(動画の撮影にはならないが、デバイス番号の代わりに動画ファイルのファイル名を指定してもよい).デバイス番号はコンピュータに接続されているカメラを識別するための番号で、普通はカメラが1台だけしか接続されていないので,0か -1をデバイス番号として指定する(カメラが複数台ある場合は,1やそれ以上の番号を指定して区別する). VideoCapture 型のオブジェクトを生成してしまえば,1フレームごとに撮影することが可能.ただし,撮影終了後にrelease()関数を用いてビデオ撮影デバイスを解放することを忘れないようにしよう.

注意: デバイス番号を0として撮影できない場合は、デバイス番号を-1としてみよう。

実行例: 以下のプログラムはここからダウンロードできる。qをキー入力すれば終了する。
import numpy as np
import cv2

cap = cv2.VideoCapture(0)

while(True):
    # Capture frame-by-frame
    ret, frame = cap.read()

    # Our operations on the frame come here
    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    # Display the resulting frame
    cv2.imshow('frame',gray)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break

# When everything done, release the capture
cap.release()
cv2.destroyAllWindows()

メソッドcap.read() は (True/False)の2値の値を返す.フレームの読み込みが正しく行われれば True を返す(カメラ撮影ではなく動画ファイルを表示する場合、この関数がFalseを返せばファイルの最後に到達したかことがわかる).

オブジェクト cap に初期化(適切な値がセット)されていないことがある.そのような場合はエラーを返す.そこであらかじめ cap.isOpened() 関数を使ってTrueが返ってくるのを確かめることで、値の初期化の確認ができる.なおTrueでなければ(カメラ(動画ファイル)を一旦解放した状態なら)cap.open() 関数によって再びカメラを使って動画を録画(動画ファイルを表示)することができる.

この動画の属性は cap.get(propId) 関数を使って調べられる. propId は0から18までの整数値で,それぞれ数値に対し動画の属性情報(ただし、その動画が指定された属性情報を持っていれば)が対応している.属性情報の詳細についてはここ: cv::VideoCapture::get() を参照のこと.幾つかの属性情報は cap.set(propId, value) 関数を使って変更できる.ここで value は新しく設定する値である.

例えば, cap.get(3)cap.get(4) を実行すれば,フレームの横幅(width)と縦幅(height)の値が得られる.(著者が使用しているカメラであれば)デフォルトで640x480となるが,320x240に変更するのであれば, ret = cap.set(3,320)ret = cap.set(4,240) を実行する.

Note

もしもエラーが生じるようであれば,カメラを扱えるソフトウェア(Linuxであればcheese)を使って,カメラが正常に動作することを確認する.

ファイルから動画を表示する

ファイルから動画を表示する方法は,カメラから動画を撮影する方法と基本的に同じである.カメラのデバイス番号の代わりに動画ファイルのファイル名を指定するだけでよい.なおフレームを表示している間は cv2.waitKey() に適切な時間を設定すること.設定する時間が極端に短いと動画が高速に再生され,逆に長く設定すると極端なスロー再生になる.通常は25ミリ秒と指定すればよい.

実行例: 以下のプログラムはここからダウンロードできる。qをキー入力すれば終了する: (動画のサンプルはこれを使って良い)
import numpy as np
import cv2

cap = cv2.VideoCapture('vtest.avi')

while(cap.isOpened()):
    ret, frame = cap.read()

    gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

    cv2.imshow('frame',gray)
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break

cap.release()
cv2.destroyAllWindows()

Note

動かない時には、適切なバージョンのffmpeg か gstreamerがインストールされていることを確認せよ.ffmpeg/gstreamerのインストールに間違いがあると VideoCapture が期待通りに動作しない.

Note2

連続した番号をもつ静止画ファイルを「パラパラ漫画」の要領で表示させると動画にみえる。また次に学ぶ「動画を保存する」を使うと動画のファイルができあがる。 (コード(コメントを外せば動画ファイルができる), videos.zip: このファイルを展開しておくこと)

動画を保存する

ここまでで動画を撮影し,1フレームごとに処理ができるようになった。そこで動画をファイルに保存してみよう.画像として保存するなら cv2.imwrite() 関数を使えばよいが,動画ファイルとして保存するにはひと工夫必要である.

ここでは、動画ファイルとして保存するために VideoWriter(filename, fourcc, fps, frameSize, isColor)関数を用いてVideoWriter 型のオブジェクトを生成する.VideoWriter関数の第1引数filenameは保存する動画ファイル名(例: output.avi)を指定する.第2引数fourccは FourCC コード(詳細は次の段落で説明)を,第3引数fpsは動画の再生速度、第4引数frameSizeは解像度を設定する.最後の引数isColorは isColor フラグを指定します.このフラグが True であればカラーの動画,そうでなければ白黒(グレースケール)の動画として保存される.

FourCC は動画のコーデックを指定するための4バイトのコードで、使用可能なコードのリストは fourcc.org で確認できる.OS依存なので気を付けて選ぶこと.以下のコードは著者のマシンでは正しく動作した.

  • Linux: DIVX, XVID, MJPG, X264, WMV1, WMV2. (XVID が望ましい、MJPG は高解像度、 X264 は小さなサイズのビデオ)
  • Windows: DIVX (ほかにも追加される予定)
  • OSX : 不明

例えばMJPG(モーションJPEG)コーデックを使う場合、FourCC コードは cv2.VideoWriter_fourcc('M','J','P','G') もしくは cv2.VideoWriter_fourcc(*'MJPG') のように指定する.

実行例: 次のコードはカメラから撮影した映像を上下反転させて保存する.(qのキー入力で終了する)

import numpy as np
import cv2

cap = cv2.VideoCapture(0)

# Define the codec and create VideoWriter object
fourcc = cv2.VideoWriter_fourcc(*'MJPG')
out = cv2.VideoWriter('output.avi',fourcc, 20.0, (640,480))

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret==True:
        frame = cv2.flip(frame,0)

        # write the flipped frame
        out.write(frame)

        cv2.imshow('frame',frame)
        if cv2.waitKey(1) & 0xFF == ord('q'):
            break
    else:
        break

# Release everything if job is finished
cap.release()
out.release()
cv2.destroyAllWindows()

Note

ビデオが保存されていない時には、FourCCコードをいろいろ試してみよ。私のあるマシン(Linux, Anaconda Python 3.5.2)ではXVIDでは保存されず、MJPGなら保存できた。

補足資料

fourcc.org

課題