Np-Urのデータ分析教室

オーブンソースデータなどWeb上から入手できるデータを用いて、RとPython両方使って分析した結果を書いていきます

【お手軽監視カメラ】Raspberry Pi + USBカメラ + Python + Slack で自宅を守るぞ!

最近、利便性は高いけど少し治安の気になる地域への引っ越しを考えていまして…。
自宅に監視カメラがあれば、心置きなく引っ越しを進められるなと思い、Raspberry Pi と USBカメラを使って自作してみることにしました!

エンジニアだったら自分で作って当たり前ですよね!

使用したのは、こちらのRaspberry Pi と

こちらのUSBカメラです。

Raspberry Pi 単体で買えばもっと安いですが、microSDカードやHDMIケーブルなど、必要なものがセットで入っていたので、上記を選びました。

構成

以下のような構成イメージです。

f:id:Np-Ur:20210612105531p:plain
pythonとSlackとRaspberry Pi(ラズパイ)で監視カメラ
  • 定期的にOpenCVで画像を取得
  • フレーム間差分法で移動物体を検知
  • 移動している物体の大きさ(ピクセル数)が、ある閾値以上であれば、異常事態と判断
  • 異常と判断された画像を保存し、Slackへ通知する(file.upload API を使う)

まず、今回購入した Raspberry Pi には Raspbian が 書き込まれた SDカードがあったため、そのまま使います。
そこにPythonとOpenCVの環境を入れます。

Ubuntuに慣れているので、Ubuntuを別途インストールしようかと思いましたが、元から入っているOSでも十分できそうだったので、そのままにしています。
皆さんお好きなOSを入れてもらっていいと思います。

また、OpenCVでカメラ画像の取得や異常確認ができると楽そうだったので、Python + OpenCVを使うことにしました。
Dockerを使って再現性を保つようにしたかったのですが、ラズパイでのDocker使用は結構ハードル高そうだったので断念…。

そして、OpenCVで定期的に画像を取得し、何か異常があれば Slackに通知するという方法をとることにしました。

環境のセットアップ

構成についてイメージができたところで、続いてRaspberry Pi のセットアップに進みましょう!

OS起動

OSイメージが書き込まれたmicroSDカード差し込み、また電源アダプタとHDMIケーブル、またマウスやキーボードをそれぞれ繋ぎます。
電源アダプタを指した時点で、起動すると思います。

Raspbian起動画面
Raspbian起動画面

ユーザーパスワードやwifi等の設定が終わったら、Okです。
今後、いちいち HDMIケーブル・マウスやキーボード繋ぐのは面倒なので、SSHサーバーを有効化して、普段作業するPCからログインできるようにしておくとよいでしょう。

以下を参考に設定しておきましょう。
qiita.com

また、一般的にラズパイを使用する際によくやるセキュリティ対策が以下によくまとまっていたので、一応やっておきましょう。
qiita.com

PythonやOpenCVのインストール

以下のコマンドを実行すれば、一通り必要な環境は揃うはずです。

$ sudo pip install --upgrade pip
$ sudo apt install libavutil56 libcairo-gobject2 libgtk-3-0 libqtgui4 libpango-1.0-0 libqtcore4 libavcodec58 libcairo2 libswscale5 libtiff5 libqt4-test libatk1.0-0 libavformat58 libgdk-pixbuf2.0-0 libilmbase23 libjasper1 libopenexr23 libpangocairo-1.0-0 libwebp6 libatlas-base-dev
$ sudo pip3 install opencv-python==4.1.0.25


以下を実行したときにエラーが出れば、何か必要なライブラリが足りていないということなので、エラー内容をググって試してみてください。

$ python3
>> import cv2
>>


USBカメラの動作確認

USBカメラを接続した状態で、以下をpythonで実行してみてください。

import cv2
capture = cv2.VideoCapture(0)
ret, frame = capture.read()
cv2.imwrite("sample.png", frame )

sample.png という名前でカメラ画像の様子を保存しています。

途中エラーが起こらずに、ちゃんとカメラ映像が保存されていれば成功です。

Slackの設定

続いてSlackの設定です。
異常事態が発生した場合には、Slackに通知を飛ばして、教えてもらいたいです。

テキスト情報のみ送付したい場合は、Incoming Webhooks という Slackが用意してくれている API を使うのが一番やりやすいです。
Incoming Webhooks については、以下で紹介しているので参考にしてください。
www.randpy.tokyo


今回は、せっかくなので画像も一緒にSlackに送信したいので、file.upload API を使うことにします。
Tokenが必要なのですが、以下ページを参考に取得してください。
qiita.com
自分はBot Userとして作成しました。


以下コードの、TOKEN部分に取得したトークン、CHANNEL 部分に送信したいチャンネルのIDを入力してください。

import cv2
import requests
import json

TOKEN = "XXXXXXXX"
CHANNEL = "XXXXXXX"
file_name = "sample.png"

capture = cv2.VideoCapture(0)
ret, frame = capture.read()
cv2.imwrite(file_name, frame)

files = {'file': open(file_name, 'rb')}
param = {
    'token':TOKEN, 
    'channels':[CHANNEL],
    'initial_comment': "initial_comment",
}
r = requests.post(url="https://slack.com/api/files.upload", data=param, files=files)
print(r.json())
capture.release()

無事に実行できていれば、以下のように画像が送信されているはずです。

Pythonスクリプト

前節までで、一通り必要な機能は揃いました。

定期的にUSBカメラの画像を取得し、何か異常・変化があればSlackに送信するという仕組みを整えましょう。

「何か異常・変化が発生した」という点については、様々な画像処理手法を用いることができそうです。今回はフレーム間差分法で移動している物体を検知し、そのピクセル数が一定以上を超えた場合に「何か異常・変化が発生した」とみなすことにします。

フレーム間差分法のPythonコードは、以下サイトを参考にさせていただきました。
algorithm.joho.info

上記サイトのコードをベースに、Slack送信用の関数などを追加したものが以下です。
gist.github.com


動作確認

ここまでできたら、Pythonを実行し、カメラの前で静止したり・移動したりしてみましょう。
なにか動いたときだけ、Slackに画像が送信されていれば成功です!

異常発生時にSlackにラズパイから画像が送信されている様子。file.upload API
異常発生時にSlackにラズパイから画像が送信されている様子。file.upload API

また、異常時の画像をラズパイにも保存しているので、そこも確認してみてください。

まとめ

今回、Raspberry PiにUSBカメラを接続し、PythonとOpenCV環境を入れて異常動作を検知し、それをSlackに送信する監視カメラを作りました。
作った装置は、玄関に設置しています。毎日私が帰宅すると、異常者だとSlackに送信してくれるかわいいやつです。

興味ある方はぜひ試してみてくださいー。