Pynote

Python、機械学習、画像処理について

OpenCV - VideoCapture / VideoWriter で動画の読み込み/書き込みを行う。

Web カメラから映像を取得する。

VideoCapture オブジェクトを作成する。

cv2.VideoCapture(index)
import cv2

device_id = 0
cap = cv2.VideoCapture(device_id)

while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()
    if not ret:
        break  # 映像取得に失敗
    
    cv2.imshow('Frame', frame)
    if cv2.waitKey(1) & 0xFF == ord('q'):
        break  # q キーを押したら終了する。

cap.release()
cv2.destroyAllWindows()

動画を読み込む。

VideoCapture オブジェクトを作成する。

cv2.VideoCapture(filename)
  • 引数
    • filename: ファイル名

サンプルとして こちら の動画を使用する。

import cv2

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

while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()
    if not ret:
        break  # 映像取得に失敗
    
    cv2.imshow('Frame', frame)
    cv2.waitKey(1)

cap.release()
cv2.destroyAllWindows()

動画を書き込む。

VideoWriter オブジェクトを作成する。

cv2.VideoWriter(filename, fourcc, fps, frameSize[, isColor])
  • 引数
    • filename: 出力ファイル名
    • fourcc: FourCC を表す文字4つのリスト (例: ['H', '2', '6', '4'])
    • fps: FPS
    • frameSize: フレームの大きさ
    • isColor: 書き込むフレームがカラーかどうか (このフラグは Windows のみサポート)
import cv2

# VideoCapture を作成する。
cap = cv2.VideoCapture('vtest.avi')
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = cap.get(cv2.CAP_PROP_FPS)

# VideoWriter を作成する。
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
writer = cv2.VideoWriter('output.avi', fourcc, fps, (width, height))

while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()
    if not ret:
        break  # 映像取得に失敗
    
    writer.write(frame)  # フレームを書き込む。

writer.release()
cap.release()

各フレームを画像として、保存する。

import os

import cv2

output_dirpath = 'output'

# VideoCapture を作成する。
cap = cv2.VideoCapture('vtest.avi')

# 保存用ディレクトリを作成する。
os.makedirs(output_dirpath, exist_ok=True)

while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()
    if not ret:
        break  # 映像取得に失敗
    
    # フレームを画像として保存する。
    frame_no = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
    filepath = os.path.join(output_dirpath, 'frame_{:04d}.png'.format(frame_no))
    cv2.imwrite(filepath, frame)

cap.release()

画像から動画を作成する。

今 output ディレクトリ以下に連番で画像ファイルがあるとする。

output
├── frame_0001.png
├── frame_0002.png
├── frame_0003.png
├── frame_0004.png
├── frame_0005.png
├── frame_0006.png
├── frame_0007.png
├── frame_0008.png
├── frame_0009.png
├── frame_0010.png
├── frame_0011.png
├── frame_0012.png
...

このとき、VideoCapture() に 'frame_%04d.png' のようにフレーム番号の部分だけフォーマットで指定することで、順番に読み込む機能がある。これを利用して、連番の画像ファイルから動画を作成する。

import glob
import os

import cv2

# VideoCapture を作成する。
img_path = os.path.join(output_dirpath, 'frame_%04d.png')  # 画像ファイルのパス
cap = cv2.VideoCapture(img_path)
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = 15
print('width: {}, height: {}, fps: {}'.format(width, height, fps))

# VideoWriter を作成する。
fourcc = cv2.VideoWriter_fourcc(*'DIVX')
writer = cv2.VideoWriter('output.avi', fourcc, fps, (width, height))

while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()
    if not ret:
        break  # 映像取得に失敗
    
    writer.write(frame)  # フレームを書き込む。

writer.release()
cap.release()

動画の各種プロパティを取得する。

VideoCapture.get() で幅、高さ、FPS といった動画のプロパティを取得できる。

retval = cv2.VideoCapture.get(propId)
  • 引数
  • 返り値
    • retval: 指定したプロパティの値。float 型で返すため、必要に応じて、int 型にすればよい。
import cv2

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

width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))  # フレームの幅
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))  # フレームの高さ
fps = int(cap.get(cv2.CAP_PROP_FPS))  # FPS
fourcc = int(cap.get(cv2.CAP_PROP_FOURCC))  # FOURCC
fourcc = forcc.to_bytes(4, 'little').decode('utf-8')  # int を4バイトずつ解釈する。
num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))  # フレーム数の合計
print('width: {}, height: {}, fps: {}, forcc: {}, total frames: {}'.format(
    width, height, fps, fourcc, num_frames))
# width: 768, height: 576, fps: 10, forcc: div3, total frames: 795

while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()
    if not ret:
        break  # 映像取得に失敗
    
    curr_pos = int(cap.get(cv2.CAP_PROP_POS_MSEC))  # 動画の最初から何 ms のフレームか
    curr_frame_no = int(cap.get(cv2.CAP_PROP_POS_FRAMES))  # 現在のフレーム番号
    print('pos: {} ms, frame no: {}/{}'.format(
        curr_pos, curr_frame_no, num_frames))
    # pos: 100 ms, frame no: 1/795
    # pos: 200 ms, frame no: 2/795
    
    cv2.imshow('Frame', frame)
    cv2.waitKey(1)

cap.release()
cv2.destroyAllWindows()

動画の再生 FPS を計算する。

動画自体の FPS は VideoCapture.get(cv2.CAP_PROP_FPS) で取得できるが、動画を実際に再生した際の FPS (frames per second) は、フレーム数 / 再生開始時からの計算時間で計算できる。

import time
import cv2

filepath = 'vtest.avi'
cap = cv2.VideoCapture(filepath)
num_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT))  # フレーム数

start = time.time()
while True:
    # 1フレームずつ取得する。
    ret, frame = cap.read()
    if not ret:
        break  # 映像取得に失敗

    frame_no = int(cap.get(cv2.CAP_PROP_POS_FRAMES))  # 現在のフレーム番号
    fps  = frame_no / (time.time() - start)  # fps = フレーム数 / 経過時間 (s)
    print('fps: {:.2f}, frame no: {}/{}'.format(fps, frame_no, num_frames), end='\r')

    cv2.imshow('Frame', frame)
    cv2.waitKey(1)

cap.release()
cv2.destroyAllWindows()