前回、高機能な画像動画ライブラリのOpenCVに関して、インストールから簡単な使い方を紹介した。今回は、OpenCVのWebカメラの機能を利用して、自作の監視カメラを作ってみよう。ここでは、留守宅に侵入者があった場合に画像を保存するというものを作ってみよう。

  • 監視カメラを実行したところ - 侵入者があると画像をファイルに保存する

    監視カメラを実行したところ - 侵入者があると画像をファイルに保存する

Webカメラをセットアップしよう

最近のノートPCには、だいたいWebカメラが付いているので、今回は、これを利用しよう。もし、Webカメラが付いていないとしても、2000円ちょっと出せば、USBのWebカメラが入手できる。そして、OpenCVがインストールされていれば、手軽にWebカメラの画像を取得出来る。OpenCVのインストールについては、前回紹介した。

OpenCVでWebカメラの画像を得るには、以下のようなプログラムを記述すれば良い。以下のプログラムを「camera.py」という名前で保存しよう。

import cv2
# カメラのキャプチャを開始 --- (*1)
cam = cv2.VideoCapture(0)
while True:
    # 画像を取得 --- (*2)
    _, img = cam.read()
    # ウィンドウに画像を表示 --- (*3)
    cv2.imshow('PUSH ENTER KEY', img)
    # Enterキーが押されたら終了する
    if cv2.waitKey(1) == 13: break
# 後始末
cam.release()
cv2.destroyAllWindows() 

そして、コマンドラインから実行してみよう。

# Windowsの場合
python camera.py
# macOSの場合
python3 camera.py

プログラムを実行すると、ウィンドウが表示され、そこにWebカメラの画像が表示される。それで、[Enter]キーを押すと、プログラムが終了する。

  • コマンドを実行してWebカメラの映像を確認しているところ

    コマンドを実行してWebカメラの映像を確認しているところ

プログラムを確認しよう。(*1)の部分では、cv2.VideoCapture()を実行して、Webカメラからの入力を開始する。引数に指定している0はカメラの番号で、二つ以上カメラがある場合、この値を変えることでカメラを切り替えることができる。(*2)のread()メソッドを実行すると、カメラから実際に画像を取得できる。そして、(*3)のcv2.imshow()を使うと、画像を出力ウィンドウに表示できる。

動きを検出する監視カメラを作ろう

次に、カメラから得た画像を、連続で比較して、動きがあれば、コンソールに動きがあったことを通知し、画像をファイルに保存するプログラムを作ってみよう。以下のプログラムを「camera-kansi.py」という名前で保存しよう。

import cv2
# 保存パスの指定
save_path = "./"
def main():
    # カメラのキャプチャを開始
    cam = cv2.VideoCapture(0)
    # フレームの初期化 --- (*1)
    img1 = img2 = img3 = get_image(cam)
    th = 300
    num = 1
    while True:
        # Enterキーが押されたら終了
        if cv2.waitKey(1) == 13: break
        # 差分を調べる --- (*2)
        diff = check_image(img1, img2, img3)
        # 差分がthの値以上なら動きがあったと判定 --- (*3)
        cnt = cv2.countNonZero(diff)
        if cnt > th:
            print("カメラに動きを検出")
            cv2.imshow('PUSH ENTER KEY', img3)
            # 写真を画像 --- (*4)
            cv2.imwrite(save_path + str(num) + ".jpg", img3)
            num += 1
        else:
            cv2.imshow('PUSH ENTER KEY', diff)
        # 比較用の画像を保存 --- (*5)
        img1, img2, img3 = (img2, img3, get_image(cam))
    # 後始末
    cam.release()
    cv2.destroyAllWindows() 

# 画像に動きがあったか調べる関数
def check_image(img1, img2, img3):
    # グレイスケール画像に変換 --- (*6)
    gray1 = cv2.cvtColor(img1, cv2.COLOR_RGB2GRAY)
    gray2 = cv2.cvtColor(img2, cv2.COLOR_RGB2GRAY)
    gray3 = cv2.cvtColor(img3, cv2.COLOR_RGB2GRAY)
    # 絶対差分を調べる --- (*7)
    diff1 = cv2.absdiff(gray1, gray2)
    diff2 = cv2.absdiff(gray2, gray3)
    # 論理積を調べる --- (*8)
    diff_and = cv2.bitwise_and(diff1, diff2)
    # 白黒二値化 --- (*9)
    _, diff_wb = cv2.threshold(diff_and, 30, 255, cv2.THRESH_BINARY)
    # ノイズの除去 --- (*10)
    diff = cv2.medianBlur(diff_wb, 5)
    return diff

# カメラから画像を取得する
def get_image(cam):
    img = cam.read()[1]
    img = cv2.resize(img, (600, 400))
    return img
main()

プログラムを実行するには、コマンドラインから以下のように実行する。

# Windowsの場合
python camera-kansi.py
# macOSの場合
python3 camera-kansi.py

すると、真っ黒い画面が表示されるだろう。そして、小さな動きがあったときには、画面に動きがあった場所が白く表示される。大きく動きがあると画面がカラー画像に差し替わる。その際、コンソールに「カメラに動きを検出」と表示し、ファイルに画面を保存する。

  • 画面に動きがあった部分を白く表示する

    画面に動きがあった部分を白く表示する

  • 画面に大きな動きがあるとカラー画像で表示し、ファイルに保存する

    画面に大きな動きがあるとカラー画像で表示し、ファイルに保存する

ここでは、動きを検出するのに、三枚の画像を利用している。これは、移動物体の検出(動体検知)の手法としては有名なもので、『フレーム間差分法』というアルゴリズムを利用している。

手法としては、画像をグレイスケール(白黒256階調)に変換した後、三枚の画像について、それぞれ差分画像を作成する。そして、差分画像の論理積を計算する。さらに、画像を白黒二値画像に変換する。すると、動きがあった部分が白くなり、動きがない部分が黒くなる。

具体的なプログラムを確認しよう。プログラムの(*1)では、最初に、動きがあったかどうか判定する比較用の三枚の画像(img1, img2, img3)を初期化している。次に、(*2)の部分では、check_image()関数で差分を調べる。(*3)では差分画像を調べ、白色の部分がしきい値(th)の値以上であれば(*4)で写真を保存する。(*5)では、比較用の画像を保存する。

プログラムの(*6)以降の部分では、画像に動きがあったかどうかを調べる。まず、グレイスケールに変換し、(*7)で三枚の画像の絶対差分を調べる。(*8)で論理積を調べ、(*9)で白黒二値かし、(*10)でノイズを除去し、それを関数の戻り値とする。

まとめ

以上、今回は、OpenCVを利用して、自作の監視カメラを作る方法を紹介した。最近では、監視カメラもずいぶん安くなってきているが、自作すれば、監視カメラの動作をカスタマイズできる。今回は、保存のタイミングでファイルに画像を保存したが、LINEやメールで通知するなど、いろいろとやり方があるだろう。今回紹介したように、コメントを除けば、50行未満のプログラムでも、それなりの監視カメラが作れた。今回のプログラムを叩き台にして、自作監視カメラ作成に挑戦してみよう。

自由型プログラマー。くじらはんどにて、プログラミングの楽しさを伝える活動をしている。代表作に、日本語プログラミング言語「なでしこ」 、テキスト音楽「サクラ」など。2001年オンラインソフト大賞入賞、2005年IPAスーパークリエイター認定、2010年 OSS貢献者章受賞。技術書も多く執筆している。