動体撮影に特化した監視カメラの作成方法

動く物体を検知して写真撮影をする監視カメラ

こんにちは。

AI coordinatorの清水秀樹です。

OpenCVを使えば動体撮影に特化した監視カメラを作成することができるのではないかと考え、実装に作成してみました。

当記事はその内容の紹介になります。

 

この監視カメラが実装できれば、無駄にストレージ容量を消費することなく動く物体を撮影することができるようになるので便利ですね。

しかも、その写真を撮影した時に連絡できるシステムを構築すれば、色々な用途に使えそうな気がします。

ラズパイでmotionを使った記事の紹介は多いのですが、OpenCVを使った記事が少なかったので記事にしてみました。

 

最近ではラズパイで簡単にカメラを使用することができるようになりました。

つまり、少しのプログラミング知識があれば好きなところに小型の監視カメラを設置できるわけです。

1万円あれば、恐らく実装可能です。

今度チャレンジしてみようかと考えています。

 

でも悪いことには使用しないように。

 

活用は自己責任でお願い致します。

 

仕組みの説明

どんな仕組みで写真撮影をするのかを簡単に説明します。

どうやって動いている物体を検出するのかというと、カメラ映像のフレーム間差分を利用して動いている物体を特定します。

以前紹介した記事とほぼ同じ仕組みですね。

カメラ映像から動く物体の輪郭検出が簡単にできた話

 

フレーム間差分が発生したら、動いている物体があると判断させます。

その差分部分を四角で囲み、写真を出力する仕組みで構築してみました。

 

ただこの仕組みの欠点は、カメラの前に動く物体が居続けると、永遠と撮影し続けてしまうという点です。

その解決策として、インターバルを設けるようにしています。

写真をとったら次の撮影までに最低2秒必要みたいな、そんなインターバルです。

この辺はお好みで調整してください。

 

ソースコード

# -*- coding: utf-8 -*-
import cv2
import numpy as np
from datetime import datetime

def flame_sub(im1,im2,im3,th,blur):

    d1 = cv2.absdiff(im3, im2)
    d2 = cv2.absdiff(im2, im1)
    diff = cv2.bitwise_and(d1, d2)
    # 差分が閾値より小さければTrue
    mask = diff < th
    # 背景画像と同じサイズの配列生成
    im_mask = np.empty((im1.shape[0],im1.shape[1]),np.uint8)
    im_mask[:][:]=255
    # Trueの部分(背景)は黒塗り
    im_mask[mask]=0
    # ゴマ塩ノイズ除去
    im_mask = cv2.medianBlur(im_mask,blur)

    return  im_mask

if __name__ == '__main__':

    cam = cv2.VideoCapture(0)
    
    #写真撮影用初期パラメータ/2秒以上の間隔で撮影
    last_time = datetime.now()
    interval = 2
    #cam.set(3, 640)  # Width
    #cam.set(4, 380)  # Heigh
    im1 = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
    im2 = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
    im3 = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)

    while True:
        # フレーム間差分計算
        im_fs = flame_sub(im1,im2,im3,5,7)
        cv2.imshow("Motion Mask",im_fs)
        
        #輪郭を検出
        cunts = cv2.findContours(im_fs,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)[1]        
        ret, frame = cam.read()
        
        Photo = False
        
        #四角で囲む/小さい物体無視
        for pt in cunts:
            x,y,w,h = cv2.boundingRect(pt)
            if w < 100: continue
            cv2.rectangle(frame, (x, y), (x+w, y+h),(0, 255, 0), 3)
            
            Photo = True
        
        #撮影は2秒以上の間隔で撮影
        if Photo:
            now = datetime.now()
            fntime = lambda n : int(n.strftime('%S'))
            sec = fntime(now) - fntime(last_time)
            
            #print(fntime(now))
            #print(fntime(last_time))
            
            
            if sec < 0:
                sec = sec * -1
            print(sec)
            
            if sec > interval:
                #動いている物体の画像を保存する
                f = now.strftime('%Y-%m-%d-%H-%M-%S') + ".jpg"
                cv2.imwrite(f,frame)
                last_time = now
                print("save=", f)
        
        cv2.imshow("Input",frame)
        
        im1 = im2
        im2 = im3
        im3 = cv2.cvtColor(cam.read()[1], cv2.COLOR_RGB2GRAY)
        key = cv2.waitKey(10)
        # Escキーが押されたら
        if key == 27:
            cv2.destroyAllWindows()
            break

 

小さい物体の動きを無視したい場合は、以下の条件式で100の数字をさらに小さい数字に変更してください。

この辺は実際に動かしながら調整してみると良いと思います。

#四角で囲む/小さい物体無視
        for pt in cunts:
            x,y,w,h = cv2.boundingRect(pt)
            if w < 100: continue
            cv2.rectangle(frame, (x, y), (x+w, y+h),(0, 255, 0), 3)
            
            Photo = True

 

前述した通りインターバルを2秒取るようにしています。

撮影間隔はこのパラメータを変更してください。

interval = 2

 

DeepLearningを使えばもっとすごい監視カメラが作れそう

物体検出といえばDeepLearningです。

例えば、特定の人物の画像をDeepLearningで学習させて、その人物が検出できたら連絡させる監視カメラなんてのも作成できます。

 

う〜ん、世の中には既にありそうなシステムですね。

 

自分で作るのは無理!でも作って欲しいという方は連絡ください。

筆者も作れそうな気がしています。

お値段は相談ベースで。(笑)

 


その他の物体検出記事はこちらから

 

それではまた。

あなたにオススメの記事

コメント

  1. この記事へのコメントはありません。

  1. この記事へのトラックバックはありません。

PAGE TOP