【画像処理】OpenCVを使ってWebカメラからキャプチャを生成して保存する

今回はリモート会議等で使用しているWebカメラを入力として、OpenCVを使ってキャプチャを生成して保存してみようと思います。

それぞれのバージョンはPython 3.10.4、OpenCV 4.6.0になります。また、今回の記事の内容はOpenCVの[公式ドキュメント](https://docs.opencv.org/4.6.0/d8/dfe/classcv_1_1VideoCapture.html#aabce0d83aa0da9af802455e8cf5fd181)を参考にしています。

![out.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866058/a7083c86-ef93-c170-da0d-b5c387cdbb6b.gif)

# OpenCVでWebカメラ画像を取得
OpenCVに実装されているWebカメラから画像を取得する処理は、「VideoCapture」になります。

```python:VideoCapture
cap = cv2.VideoCapture(deviceID)
```

|parameters|説明|
|:-:|:-:|
|deviceID|WebカメラのデバイスID（Webカメラが1つであれば0であることが多い）|


# 実装
実装はこのようになります。

```python:capture.py
import argparse
import datetime
import cv2


def parse_args() -> tuple:
    parser = argparse.ArgumentParser()
    parser.add_argument("IN_CAM", help="Input camera num or video path", type=str)
    parser.add_argument("-f", "--FPS", help="Input FPS", type=int, default=None)
    args = parser.parse_args()
    return (args.IN_CAM, args.FPS)


def main() -> None:
    (in_cam, in_fps) = parse_args()
    if in_cam.isdigit():
        in_cam = int(in_cam)
    cap = cv2.VideoCapture(in_cam)
    frame_widht = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    frame_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    if frame_widht != 640 or frame_height != 480:
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
    print("width:{}".format(frame_widht))
    print("height:{}".format(frame_height))

    cap.set(cv2.CAP_PROP_AUTOFOCUS, 1.0)
    cap.set(cv2.CAP_PROP_AUTO_EXPOSURE, 1.0)
    cap.set(cv2.CAP_PROP_AUTO_WB, 1.0)

    if in_fps is not None:
        cap.set(cv2.CAP_PROP_FPS, in_fps)
    print("fps:{}".format(cap.get(cv2.CAP_PROP_FPS)))

    while cap.isOpened():
        ret, frame = cap.read()
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break

        if cv2.waitKey(1) & 0xFF == ord("c"):
            time = datetime.datetime.now()
            timestr = time.strftime("%Y_%m_%d_%H_%M_%S")
            print(str(timestr) + ".png")
            cv2.imwrite(str(timestr) + ".png", frame)

        cv2.namedWindow("output", cv2.WINDOW_NORMAL)
        cv2.imshow("output", frame)

    cap.release()
    cv2.destroyAllWindows()


if __name__ == "__main__":
    main()

```


### フレームサイズの統一
速度の面から取得したフレームのサイズを横640px、縦480pxに統一しています。
```python
    frame_widht = cap.get(cv2.CAP_PROP_FRAME_WIDTH)
    frame_height = cap.get(cv2.CAP_PROP_FRAME_HEIGHT)
    if frame_widht != 640 or frame_height != 480:
        cap.set(cv2.CAP_PROP_FRAME_WIDTH, 640)
        cap.set(cv2.CAP_PROP_FRAME_HEIGHT, 480)
```

### カメラ入力停止
キーボードのqボタンでカメラからの入力停止ができます。
```python
        if cv2.waitKey(1) & 0xFF == ord("q"):
            break
```

### 画像キャプチャ
キーボードのcボタンで画像キャプチャを取得して、現在時刻をファイル名に設定し、画像保存ができます。
```python
        if cv2.waitKey(1) & 0xFF == ord("c"):
            time = datetime.datetime.now()
            timestr = time.strftime("%Y_%m_%d_%H_%M_%S")
            print(str(timestr) + ".png")
            cv2.imwrite(str(timestr) + ".png", frame)
```

# 実行結果
cボタンを押したときにキャプチャされた画像がスクリプトと同じ場所に自動で保存されるようになりました。また、ファイル名は日時を取得しているため、1秒間隔でキャプチャをすることでファイル名が被らずに保存することができます。
![out.gif](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/866058/4b3587e8-95f8-d91d-a5cd-0c080094faa6.gif)

ただし、やはりwhile文でループしているため、分岐の部分でうまくボタンを押せない場合はキャプチャをとれないことがありましたので、ここは次回の課題とします。


# さいごに
今回は、「OpenCVを使ってWebカメラからキャプチャを生成して保存する」について解説しました。

目次は以下の記事からご覧になれます。

https://qiita.com/spc_ehara/items/e425b6dcc0398299c40d#%E7%9B%AE%E6%AC%A1