コンサルでデータサイエンティスト

仕事でPythonを書いてます。機械学習、Webマーケティングに興味があります。趣味は旅です。

Pythonを使ってカメラ映像をプレビュー表示しながら動画として保存する

画像を扱う仕事をしていると、カメラを使って自ら画像を撮影しなければいけない場面がありますよね。今回はPCの内臓カメラやUSBカメラを使って、カメラ映像を動画として保存するコードを実装したのでご紹介します。

準備

OpenCVをインストールします。

pip install opencv-python

Pythonソースコード

引数でいろいろな設定をできるようにしています。

import argparse
import cv2
import datetime
import os
 
def set_arguments():
    parser = argparse.ArgumentParser()
    parser.add_argument('device_id', type=int, help="通常は、 0: 内蔵カメラ, 1: USBカメラ")
    parser.add_argument('limit', type=int, help="撮影フレーム数")
    parser.add_argument('-f', '--fps', default=30, help="撮影FPS")
    parser.add_argument('-o', '--output_directory', help="出力先ディレクトリ")
    parser.add_argument('-p', '--preview', type=int, default=1, help="プレビュー画面の表示有無 0:表示しない 1:表示する(デフォルト)")
    return parser.parse_args()
 
def get_outputpath(output_directory):
    now = datetime.datetime.now()
    file_name = '{}.avi'.format(now.strftime('%Y%m%d_%H%M%S'))
    if output_directory is None:
        output_path = file_name
    else:
        os.makedirs(output_directory, exist_ok=True)
        output_path = os.path.join(output_directory, file_name)
   return output_path
 
def set_camera(device_id, fps):
    fps = int(fps)
    camera = cv2.VideoCapture(device_id)
    camera.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
    camera.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    camera.set(cv2.CAP_PROP_FPS, fps)
 
    if camera is None:
        raise Exception("Camera not found. Check device id.")
    return camera
 
def capture(camera, output_filepath, show_preview, limit = None):
    frame_number = 0
    fourcc = cv2.VideoWriter_fourcc(*'MJPG')
    ret, frame = camera.read()
 
    fps = camera.get(cv2.CAP_PROP_FPS)
    height = camera.get(cv2.CAP_PROP_FRAME_HEIGHT)
    width = camera.get(cv2.CAP_PROP_FRAME_WIDTH)
    writer = cv2.VideoWriter(output_filepath, fourcc, fps, (int(width), int(height)))
 
    while(ret):
        frame_number += 1
        writer.write(frame)
        if show_preview:
            cv2.imshow("preview", frame)
        if cv2.waitKey(int(1 / fps * 1000)) == 27: # ESC Key
            break
        if limit is not None and frame_number >= limit:
           break
        ret, frame = camera.read()
 
if __name__ == '__main__':
    args = set_arguments()
    output_path = get_outputpath(args.output_directory)
    camera = set_camera(args.device_id, args.fps)
    capture(camera, output_path, args.preview, args.limit)

カメラ映像を動画に保存する

プログラムの使い方について説明します。
引数の渡し方は-hオプションで見ることができます。

python camera_recorder.py -h


こんな感じです。

usage: camera_recorder.py [-h] [-f FPS] [-o OUTPUT_DIRECTORY] [-p PREVIEW]
                          device_id limit
 
positional arguments:
  device_id             通常は、 0: 内蔵カメラ, 1: USBカメラ
  limit                 撮影フレーム数
 
optional arguments:
  -h, --help            show this help message and exit
  -f FPS, --fps FPS     撮影FPS
  -o OUTPUT_DIRECTORY, --output_directory OUTPUT_DIRECTORY
                        出力先ディレクトリ
  -p PREVIEW, --preview PREVIEW
                        プレビュー画面の表示有無 0:表示しない 1:表示する(デフォルト)


それでは実際に動かしてみましょう。これは内臓カメラ(device_id = 0)で300フレーム分撮影してくれる実行スクリプトです。デフォルトではFPSは30なので、10秒間撮影をしてくれます。

python camera_recorder.py 0 300


f:id:hktech:20181002220736p:plain
カメラのプレビュー映像もちゃんと見えていますね。撮影時にはプレビュー表示があるとかなり便利です。

外部接続のUSBカメラで撮影をしたい場合は、次のようにするとできるはずです。

python camera_recorder.py 1 300

まとめ

Pythonを使ってカメラ映像を動画として保存するコードを紹介しました。このコードを使えば画像の学習データを自作できるのですが、アノテーションがとても大変だったりします。特に物体検出タスクなどでは、クラスだけでなくバウンディングボックスの座標なども指定しなくてはいけなくて地獄です。今後の記事ではアノテーションを楽にするような撮影方法や、バウンディングボックス座標を半自動で認識するようなプログラムについて紹介できればと思います。