OpenCV – VideoCapture、VideoWriter の使い方

目次
概要
OpenCV の VideoCapture、VideoWriter の使い方を紹介します。
- VideoCapture
- Web カメラから映像を取得する
- 動画ファイルからフレームを取得する
- 連番の画像ファイルから順番に画像を取得する
- VideoWriter
- Web カメラから映像を取得し、動画として保存する
- 動画ファイルからフレームを取得し、画像として保存する
Advertisement
VideoCapture
Web カメラから映像を取得する
引数に映像を取得するカメラデバイスの ID を指定します。 カメラが1台しか接続されていない場合は、0を指定します。
cv2.VideoCapture(index)
引数
名前 | 型 | デフォルト値 |
---|---|---|
index | int | |
デバイス ID (0, 1, …) |
Logicool の Logitech C270 HD Webcam を PC に接続して、確認しました。 フレームの大きさや FPS といった情報は VideoCapture.get() で取得できます。
In [ ]:
import cv2
# VideoCapture を作成する。
device_id = 0
cap = cv2.VideoCapture(device_id)
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))
print(f"size: ({width}, {height}), fps: {fps}")
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()
動画ファイルからフレームを取得する
cv2.VideoCapture(filename)
引数
名前 | 型 | デフォルト値 |
---|---|---|
filename | str | |
動画ファイル名 |
In [ ]:
import cv2
filepath = "sample.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))
print(f"size: ({width}, {height}), fps: {fps}")
while True:
# 1フレームずつ取得する。
ret, frame = cap.read()
if not ret:
break # 取得に失敗した場合
cv2.imshow("Frame", frame)
cv2.waitKey(1)
cap.release()
cv2.destroyAllWindows()
sleep を入れない場合、PC の処理能力で可能な速度で映像が取得されます。 動画の実際の FPS で再生したい場合は、適当に sleep する必要があります。
FPS は1秒間のフレームレートなので、フレームを取得する間に $\frac{1}{\text{FPS}}$ 秒だけ sleep すればよいことになります。 実際はフレームの取得自体にも時間がかかるので、それを除いた以下の時間 sleep すればよいです。
$$ \text{sleep する時間 (secs)} = \frac{1}{\text{FPS}} – \text{フレーム取得にかかった時間 (secs)} $$
In [ ]:
import cv2
import time
filepath = "sample.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))
print(f"size: ({width}, {height}), fps: {fps}")
while True:
start = time.time()
# 1フレームずつ取得する。
ret, frame = cap.read()
if not ret:
break # 取得に失敗した場合
elapsed_secs = time.time() - start # 映像取得にかかった時間 (secs)
sleep_secs = max(1, int((1 / fps - elapsed_secs) * 1000)) # sleep する時間 (secs)
cv2.imshow("Frame", frame)
if cv2.waitKey(sleep_secs) & 0xFF == ord("q"):
break # q キーを押したら終了する。
cap.release()
Advertisement
連番の画像ファイルから順番に画像を取得する
以下のようにあるディレクトリ以下に連番で画像ファイルがある場合、VideoCapture で順番に読み込むことができます。filename
には、’frame_%03d.png’ のようにフレーム番号の部分を書式指定子で指定します。VideoWriter を使えば、連番画像を動画化できます。
output
├── frame_001.png
├── frame_002.png
├── frame_003.png
├── frame_004.png
├── frame_005.png
├── frame_006.png
├── frame_007.png
├── frame_008.png
├── frame_009.png
├── frame_010.png
...
In [ ]:
from pathlib import Path
import cv2
# 画像ファイルのパス
img_paths = Path("output") / "frame_%03d.png"
# VideoCapture を作成する。
cap = cv2.VideoCapture(str(img_paths))
width = int(cap.get(cv2.CAP_PROP_FRAME_WIDTH))
height = int(cap.get(cv2.CAP_PROP_FRAME_HEIGHT))
fps = 15
print(f"width: {width}, height: {height}, fps: {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()
VideoWriter
cv2.VideoWriter(filename, fourcc, fps, frameSize[, isColor])
引数
名前 | 型 | デフォルト値 |
---|---|---|
filename | str | |
出力ファイル名 | ||
fourcc | list of strs | |
FourCC を表す4つ文字のリスト (例: [‘H’, ‘2’, ‘6’, ‘4’]) | ||
fps | float | |
FPS | ||
frameSize | tuple of 2-ints | |
フレームの大きさ | ||
isColor | bool | True |
write() で書き込む画像がグレースケールの場合は False にする |
出力した動画が開けない場合
出力した動画が開けない場合は、フレームの書き込みに失敗しています。考えられる要因を以下に記載します。
fourcc
に指定したエンコード方式が対応していないframeSize
に指定した大きさと実際にwriter.write()
で書き込むフレームの大きさが一致していないisColor=True
を指定しているのに、writer.write()
で書き込むフレームがグレースケール形式になっている
Advertisement
Web カメラから映像を取得し、動画として保存する
In [ ]:
import cv2
# VideoCapture を作成する。
cap = cv2.VideoCapture(0)
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()
動画の各フレームを画像として保存する
In [ ]:
from pathlib import Path
import cv2
# 保存するディレクトリ
output_dir = Path("output")
output_dir.mkdir(exist_ok=True)
# VideoCapture を作成する。
cap = cv2.VideoCapture("sample.avi")
n_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数を取得する。
n_digits = len(str(n_frames)) # フレーム数の桁数を取得する。
while True:
# 1フレームずつ取得する。
ret, frame = cap.read()
if not ret:
break # 取得に失敗した場合
# フレームを画像として保存する。
frame_no = int(cap.get(cv2.CAP_PROP_POS_FRAMES))
save_path = output_dir / f"frame_{frame_no:0{n_digits}d}.png"
cv2.imwrite(str(save_path), frame)
cap.release()
VideoCapture.get – フレームの大きさや FPS などを取得する
retval = cv2.VideoCapture.get(propId)
引数
名前 | 型 | デフォルト値 |
---|---|---|
propId | int | |
プロパティID。VideoCaptureProperties を参照する。 |
返り値
名前 | 説明 | ||
---|---|---|---|
retval | 指定したプロパティの値。返り値は float になっている。 |
In [ ]:
import cv2
video_path = "sample.avi"
cap = cv2.VideoCapture(video_path)
# 各種プロパティを取得する。
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 = fourcc.to_bytes(4, "little").decode("utf-8") # int を4バイトずつ解釈する。
n_frames = int(cap.get(cv2.CAP_PROP_FRAME_COUNT)) # フレーム数の合計
print(
f"width: {width}, height: {height}, fps: {fps}, forcc: {fourcc}, total frames: {n_frames}"
)
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(f"pos: {curr_pos} ms, frame no: {curr_frame_no}/{n_frames}")
cv2.imshow("Frame", frame)
cv2.waitKey(1)
cap.release()
cv2.destroyAllWindows()
-
前の記事
OpenCV – アルファブレンドで画像を合成する方法 2020.06.10
-
次の記事
OpenCV – 画像に適用するアフィン変換について 2020.06.14