動画を扱う

目的

動画ファイルの読み込み方,表示方法,保存方法を学ぶ

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

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

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

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

実行例: 以下のプログラムはqをキー入力すれば終了する。(注: 画像の場合と同様に、Jupyter notebookとしては停止させられないことがある)

In [1]:
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()

# Notebookの場合はこれが必要
for _ in range(5):
    cv2.waitKey(1)

メソッド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をキー入力すれば終了する:

In [1]:
import numpy as np
import cv2

fname="test.avi"
cap = cv2.VideoCapture(fname)
cv2.namedWindow(fname)

if (cap.isOpened()):
    while True:
        ret, frame = cap.read()
        if ret:
            cv2.imshow(fname,frame)
            if cv2.waitKey(25) & 0xFF == ord('q'):
                break
        else:
            break

cap.release()
cv2.destroyAllWindows()

# Notebookの場合はこれが必要
for _ in range(5):
    cv2.waitKey(1)

Note 動かない時には、適切なバージョンのffmpeg か gstreamerがインストールされていることを確認せよ.ffmpeg/gstreamerのインストールに間違いがあると VideoCapture が期待通りに動作しない.なおcodecにも注意すること。 (私の環境では MJPG なら動くが他のはダメであった)

mp4ファイルに挑戦してみる。

In [9]:
import numpy as np
import cv2

fname="cockatoo.mp4"
cap = cv2.VideoCapture(fname)  # mp4 file
cv2.namedWindow(fname)

if (cap.isOpened()):
    while True:
        ret, frame = cap.read()
        if ret:
            gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)
            cv2.imshow('frame')
            if cv2.waitKey(25) & 0xFF == ord('q'):
                break
        else:
            break
else:
    print("Cannot open the file!")

cap.release()
cv2.destroyAllWindows()

# Notebookの場合はこれが必要
for _ in range(5):
    cv2.waitKey(1)
Cannot open the file!

このようにファイルは存在しても『開けない』。そこでskvideoを試す

注: pip install sk-videoが必要になろう

In [7]:
import numpy as np
import cv2

import skvideo.io

fname="test.mp4"     # MOV形式のファイルも再生できる
# cap = cv2.VideoCapture('cockatoo.mp4')  # mp4 file
cap = skvideo.io.FFmpegReader(fname)
cv2.namedWindow(fname)

for frame in cap.nextFrame():
            frame=cv2.cvtColor(frame,cv2.COLOR_RGB2BGR) # MOVファイルなどで必要
            cv2.imshow(fname,frame)
            if cv2.waitKey(25) & 0xFF == ord('q'):
                break

cap.close()
cv2.destroyAllWindows()

# Notebookの場合はこれが必要
for _ in range(5):
    cv2.waitKey(1)

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

In [3]:
import numpy as np
import cv2

cap = cv2.VideoCapture('videos/slow%03d.jpg')

while(cap.isOpened()):
    ret, frame = cap.read()
    if ret:
        cv2.imshow('frame',frame)
        # rec.write(frame)
    else:
        break
    if cv2.waitKey(25) & 0xFF == ord('q'):
        break

cv2.destroyAllWindows()
# Notebookの場合はこれが必要
for _ in range(5):
    cv2.waitKey(1)
cap.release()

動画を保存する

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

ここでは、動画ファイルとして保存するために VideoWriter(filename, fourcc, fps, frameSize, isColor)関数を用いてVideoWriter 型のオブジェクトを生成する.VideoWriter関数の第1引数filenameは保存する動画ファイル名(例: output.avi)を指定する.第2引数fourccFourCC コード(詳細は次の段落で説明)を,第3引数fpsは動画の再生速度、第4引数frameSizeは解像度を設定する.最後の引数isColorisColor フラグを指定します.このフラグが 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のキー入力で終了する)

In [4]:
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:
        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()

# Notebookの場合はこれが必要
for _ in range(5):
    cv2.waitKey(1)

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

追記: ビデオ読み込みと同様、skvideoを使うと、mp4形式の書き込みも可能なようである。詳しくは skvideo-io参照のこと

In [10]:
import skvideo.io
import numpy as np

outputdata = np.random.random(size=(25, 480, 680, 3)) * 255
outputdata = outputdata.astype(np.uint8)

skvideo.io.vwrite("outputvideo.mp4", outputdata)
In [13]:
import skvideo.io
import numpy as np

outputdata = np.random.random(size=(25, 480, 680, 3)) * 255
outputdata = outputdata.astype(np.uint8)

writer = skvideo.io.FFmpegWriter("outputvideo2.mp4")
for i in range(25):
        writer.writeFrame(outputdata[i, :, :, :])
writer.close()

目次

  • 最初に戻る
  • 一つ上: OpenCVのGUI機能
    画像と動画の表示方法と保存方法,およびGUIの機能であるマウスとトラックバーの作り方を学ぶ
  • 前の学習項目 画像を扱うimageDisplay.ipynb
    画像の読み込み,表示,保存方法を学ぶ.
  • 次の学習項目 OpenCVの描画機能 drawing.ipynb
    OpenCVを使った基本形状オブジェクトの描き方を学ぶ.