77Lifeworkベータ版

77Lifeworkベータ版

IT関係の話(ツール開発・インフラ構築)をメインとして、その他私の趣味や雑記用のブログです。ここに書いた内容が少しでも参考になれば嬉しいです。

RaspberryPi+USBカメラで動きを検出して動画を撮影する方法(動体検知)

はじめに

こんにちは。
今回はRaspberryPiにUSBカメラを接続して動体検知し、カメラで写している範囲に動くものがあった際に画像を撮影するよう設定していきます。

用意したもの

家にあった少し古いRaspberryPiを使用しています。
Raspberry Pi 3 model B+
Logicool USBウェブカメラ

RaspberryPiのOSは Raspbian version10 で、インストールされているPythonのバージョンはPython 3.7.3です。

RaspberryPiへのOSインストール、初期設定は以下の記事に書いています。
www.77-lifework.com

RaspberryPiにUSBカメラを接続してストリーミングで映像を見る場合は以下記事で。
www.77-lifework.com

OpenCVのインストールと操作

今回は画像の撮影のため、Pythonの画像処理ライブラリであるOpenCVをRaspberryPiにインストールし、これを使っていきます。
インストールは簡単です。
RaspberryPiにsshでログインし、以下コマンドを実行しましょう。

pip3 install opencv-python

RaspberryPiにはPython2系とPython3系がインストールされていると思いますが、今回私はPython3系を使用したいので、
「pip3」としています。

インストールが完了したら、コマンドラインで「python3」と入力し、「import cv2」と入力してみます。
すると、私の環境では以下のエラーが出ました。

pi@raspberrypi:~ $ python3
Python 3.7.3 (default, Jul 25 2020, 13:03:44) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/pi/.local/lib/python3.7/site-packages/cv2/__init__.py", line 5, in <module>
    from .cv2 import *
ImportError: libcblas.so.3: cannot open shared object file: No such file or directory

ライブラリが不足しているようなので追加でインストールします。
以下を実行しましょう。

sudo apt-get install libatlas-base-dev

すると、以下のようにOpenCVを正常に読み込むことができました。

pi@raspberrypi:~ $ python3
Python 3.7.3 (default, Jul 25 2020, 13:03:44) 
[GCC 8.3.0] on linux
Type "help", "copyright", "credits" or "license" for more information.
>>> import cv2
>>> 
>>> 

さて、次はOpenCVを使って画像を撮影してみましょう。
とりあえず動作確認のため、以下のようなPythonコードを組みました。

import cv2
from datetime import datetime

def main():
    cam = cv2.VideoCapture(0)

    # カメラデバイスが見つからない場合、終了
    if not cam.isOpened():
        return

    ret, frame = cam.read()

    date = datetime.now().strftime("%Y%m%d_%H%M%S")
    path = "./usbcam-img/" + date + ".png"
    cv2.imwrite(path, frame)

    cam.release()

if __name__ == '__main__':
    main()


上のプログラムを実行すると、そのタイミングで画像を撮影して「path」で指定した場所に保存する動作となります。


動体検知して動画撮影

次はカメラで映している範囲に動きがあったときに撮影するプログラムを組んでみます。
フレームの動きを検知したらそこから数秒間動画を撮影して保存する仕様としました。
フレーム間差分法ってやつです。これは検索するとやり方いっぱい出てきます。

import cv2
import time
from datetime import datetime

def main():

    base_path = "./usbcam-img/"

    cam = cv2.VideoCapture(-1)

    # カメラデバイスが見つからない場合、終了
    if not cam.isOpened():
        return

    fps = int(cam.get(cv2.CAP_PROP_FPS))
    size = (int(cam.get(cv2.CAP_PROP_FRAME_WIDTH)), int(cam.get(cv2.CAP_PROP_FRAME_HEIGHT)))

    while True:
        ret1, frame1 = cam.read()
        ret2, frame2 = cam.read()
        ret3, frame3 = cam.read()
        
        if ret1 and ret2 and ret3:
            #グレースケールに変換
            gray1 = cv2.cvtColor(frame1, cv2.COLOR_BGR2GRAY)
            gray2 = cv2.cvtColor(frame2, cv2.COLOR_BGR2GRAY)
            gray3 = cv2.cvtColor(frame3, cv2.COLOR_BGR2GRAY)


            diff1 = cv2.absdiff(gray2,gray1)
            diff2 = cv2.absdiff(gray3,gray2)


            diff_and = cv2.bitwise_and(diff1, diff2)


            th = cv2.threshold(diff_and, 50, 255, cv2.THRESH_BINARY)[1]


            wh_pixels = cv2.countNonZero(th)


            #閾値を超えたら動画撮影
            if wh_pixels > 500:
                date = datetime.now().strftime("%Y%m%d_%H%M%S")
                print(date + " whitePixels:"+str(wh_pixels))


                fourcc = cv2.VideoWriter_fourcc('m', 'p', '4', 'v')
                out = cv2.VideoWriter(base_path + date + '.mp4',fourcc, fps, size)

                
                for i in range(400):
                    ret_rec, frame_rec = cam.read()

                    if ret_rec:
                        out.write(frame_rec)

                out.release()

            time.sleep(1)

    cam.release()

if __name__ == '__main__':
    main()


上のプログラムを実行し、動作している間にフレームの動きを検知すると以下のようにmp4ファイルが保存されます。
f:id:J-back:20210122233420p:plain:w600


保存された動画ファイルを開くと、以下のように検知した映像が撮影できています。
(実際は動画なんですが、ここでは動画から切り取った写真を貼っています)
f:id:J-back:20210122230618p:plain:w600
f:id:J-back:20210122230636p:plain:w600
f:id:J-back:20210122230653p:plain:w600




今回は以上です。

ここで使ったRaspberryPiとUSBカメラを以下に貼っておきますので、もしよかったら参考にしてみてください。

次は動体検知したタイミングで撮影した動画をスマホにとばすとかやってみたいなー、とか考えてます。