OpenCVでWebカメラ/ビデオカメラの動画をリアルタイムに変換してみる

# はじめに

OpenCV(Open Source Computer Vision Library)はBSDライセンスの映像/画像処理ライブラリ集です。画像のフィルタ処理、テンプレートマッチング、物体認識、映像解析、機械学習などのアルゴリズムが多数用意されています。

OpenCVを使った動体追跡の例 (OpenCV Google Summer of Code 2015)
[https://www.youtube.com/watch?v=OUbUFn71S4s](https://www.youtube.com/watch?v=OUbUFn71S4s)

インストールと簡単な使い方はこちら
[http://qiita.com/olympic2020/items/d5d475a446ec9c73261e](http://qiita.com/olympic2020/items/d5d475a446ec9c73261e)

静止画像のフィルター処理についてはこちら
[OpenCVでエッジ検出してみる](http://qiita.com/olympic2020/items/2c3a2bfefe73ab5c86a4)

動画ファイルの処理についてはこちら
[OpenCVで動画をリアルタイムに変換してみる](http://qiita.com/olympic2020/items/ce00fab38d829965db3b)

今回は、Webカメラ、ビデオカメラのようにリアルタイムに入力がある動画の処理をしてみます。

# 平滑化
平滑化は、文字の領域を判定したり、追跡する動体の領域を判定したりする際に使うフィルターです。
例としては、下記ような流れの中で平滑化を行い領域判定につなげます。

![blur.png](https://qiita-image-store.s3.amazonaws.com/0/107056/4607854c-f530-43d3-8d16-75d806a4301b.png)

OpenCVでは、以下の平滑化がサポートされています。

- ガウシアン平滑化：cv2.GaussianBlur
- 平均化フィルタを用いた平滑化：cv2.blur
- メディアン（中央値）を用いた平滑化：cv2.medianBlur
- バイラテラルフィルタを用いた平滑化：cv2.bilateralFilter

# プログラム
今回は、ビデオ入力に対してリアルタイムにガウシアン平滑化を行い、ウィンドウ表示およびファイル保存を行うプログラムを作ってみます。

```sebcam.py
import cv2

# cv2.cv.CV_FOURCC
def cv_fourcc(c1, c2, c3, c4):
    return (ord(c1) & 255) + ((ord(c2) & 255) << 8) + \
        ((ord(c3) & 255) << 16) + ((ord(c4) & 255) << 24)


if __name__ == '__main__':
    # 定数定義
    ESC_KEY = 27     # Escキー
    INTERVAL= 33     # 待ち時間
    FRAME_RATE = 30  # fps
    
    ORG_WINDOW_NAME = "org"
    GAUSSIAN_WINDOW_NAME = "gaussian"

    GAUSSIAN_FILE_NAME = "gaussian.avi"

    DEVICE_ID = 0

    # カメラ映像取得
    cap = cv2.VideoCapture(DEVICE_ID)

    # 保存ビデオファイルの準備
    end_flag, c_frame = cap.read()
    height, width, channels = c_frame.shape
    rec = cv2.VideoWriter(GAUSSIAN_FILE_NAME, \
                          cv_fourcc('X', 'V', 'I', 'D'), \
                          FRAME_RATE, \
                          (width, height), \
                          True)

    # ウィンドウの準備
    cv2.namedWindow(ORG_WINDOW_NAME)
    cv2.namedWindow(GAUSSIAN_WINDOW_NAME)

    # 変換処理ループ
    while end_flag == True:
        # ガウシアン平滑化
        g_frame = cv2.GaussianBlur(c_frame, (15, 15), 10)

        # フレーム表示
        cv2.imshow(ORG_WINDOW_NAME, c_frame)
        cv2.imshow(GAUSSIAN_WINDOW_NAME, g_frame)

        # フレーム書き込み
        rec.write(g_frame)

        # Escキーで終了
        key = cv2.waitKey(INTERVAL)
        if key == ESC_KEY:
            break
        
        # 次のフレーム読み込み
        end_flag, c_frame = cap.read()

    # 終了処理
    cv2.destroyAllWindows()
    cap.release()
    rec.release()
```

スクリプトの動作確認は以下の環境で行いました。

- Windows 10
- Python 3.5.1
- OpenCV 3.1.0

動画ファイルとカメラからの入力は、プログラムではほぼ同じように扱うことができます。
カメラからの入力を扱う場合は、ファイル名のところをデバイスＩＤを指定してあげればＯＫです。
> cv2.VideoCapture(DEVICE_ID)

カメラが１台しかない場合は、`DEVICE_ID = 0` を指定します。

# 実行結果
+ 実行環境
    - ５年前に買ったノートＰＣ
    - CPU: Intel Core i5-2410M
    - メモリ:4GB
    - カメラ：ノートＰＣ前面に組み込まれているカメラ

+ 撮影対象
    - 床にカボチャを転がしたところ

+ 撮影方法
    ２回撮影を行いました
    - 通常の撮影（フィルター処理なし）
    - OpenCVでガウシアン平滑化を行いながら録画

![mov_org.png](https://qiita-image-store.s3.amazonaws.com/0/107056/84088b4f-5089-f086-42ec-b09a548a8d16.png)
　　　　**フィルター処理なし**

![mov_gaussian.png](https://qiita-image-store.s3.amazonaws.com/0/107056/d65473fe-7b93-fbe9-b462-1ed7c7fc1c13.png)
　　　　**ガウシアン平滑化処理あり**


動画を見たい方はこちら。

- フィルタ処理なし  
    　ＰＣ付属ソフトで単純に録画（[リンク](https://github.com/olympic2020/OpenCV/blob/master/webcam/org.wmv)）
- ガウシアン平滑化処理  
    　カメラで撮影しながらOpenCVで処理して保存（[リンク](https://github.com/olympic2020/OpenCV/blob/master/webcam/gaussian.avi)）

「古いノートＰＣだし、PythonでOpenCVってパフォーマンス的に耐えられるの？」
と半信半疑で実行してみましたが、問題なく動作しました(^^)v