Raspberry Piで最強の防犯カメラを作ってみる(動画記録・配信、動体検知・Line通知、顔検知・顔認証、Alexa搭載)[2/6]

スマートホーム
スポンサーリンク
このエントリーをはてなブックマークに追加

やりたいこと(再掲)

最終的にやりたいことは、以下の5つの機能を持つ「最強の防犯カメラ」を作ることです。機能①〜機能③は、市販されている多くの防犯カメラでも持っている機能ですが、機能④や機能⑤の顔認証機能を持つ監視カメラはまだ多くないと思います。

 機能①.動画を24時間撮影し、カメラ本体に動画で記録する
 機能②.動画をWebブラウザや他の機器から参照できるようにライブ配信する
 機能③.動体を検知したら、静止画をLineに通知する
 機能④.家族の顔を認証したら、静止画をLineに通知する
 機能⑤.家族の顔を認証したら、◯◯さんおかえり!!と喋る

家に帰ると、顔を見て「○○さん、おかえり!!」と言ってくれる辺りが、スマートハウスに一歩づ近づいている気がします。

実現に向けた連載

最強の「防犯カメラ」を作成するために、以下のように少しずつに記事を書いていきます(予定)。
 1回目:カメラの設定と動画記録
 2回目:カメラ映像のライブ配信 ←この記事
 3回目:動体検知機能とLineへの通知
 4回目:顔認証機能とLineへの通知
 5回目:Raspberry PiへのAlexaの搭載
 6回目:顔認証後にAlexaで音声通知

2回目:カメラ映像のライブ配信

前回はRaspberry Piのカメラの設定を行って、カメラ映像を動画ファイルに記録することをやってみました。今回は、python用のWebサーバソフトのFlaskを用いて、カメラ映像をライブ配信してPCやスマホのブラウザから見えるようにしたいと思います。

ライブ配信プログラムの作成

防犯カメラの映像をライブ配信するために、以下の4つのファイルを作っていきます。

①base_camera.pyのダウンロード

カメラ映像を簡単にライブ配信するために、先人の知恵を活用させていただきます。今回はmiguelgrinbergさんが公開しているflask-video-streamingの「base_camera.py」のモジュールを活用させていただきます。以下のように、wgetコマンドで「base_camera.py」をダウンロードしましょう。

②base_camera.pyの変更

オリジナルのbase_camera.pyは、クライアントからのリクエストに応じてスレッドを生成し、クライアントとの接続が無くなるとスレッドを停止するようにできています。しかし、このまま利用してしまうと、クライアントからのリクエストが無い時に動画ファイルへの記録が停止してしまうので、Flaskの起動時にスレッドを起動し、Flaskの終了時にスレッドを停止するように、次の2箇所を書き換えます。

1箇所目:66行目と67行目の間に「BaseCamera.thread.daemon = True」を追加

2箇所目:98行目辺りの「if time.time()・・・・」から4行をコメントアウトする。

1箇所目「BaseCamera.thread.daemon = True」によって、親スレッドが終了した場合に子スレッドも終了するようになります。また、2箇所目の変更によって、クライアントの接続がなくなってもスレッドが生き続けるようになります。

③Camera.pyの変更

次に、前回作成した「Camera.py」を以下のように変更します。変更点は次の5箇所です。

1箇所目:BaseCameraをインポートするように「from base_camera import BaseCamera」を追加
2箇所目:CameraクラスはBaseCameraを継承するようにカッコ内に「BaseCamera」を追加
3箇所目:クライアントに画像を返すように「yield cv2.imencode(‘.jpg’, stream.array)[1].tobytes() 」を追加
4箇所目:動画の画面表示は不要となるのでコメントアウト
5箇所目:Camera.pyの単独起動も不要なのでコメントアウト

この変更点の特筆すべきところは、先ほどダウンロードしたBaseCameraクラスを継承する点と、ライブ配信用に画像を返す部分です。特に、画像を返す部分では「cv2.imencode()」を使って画像をJPEG形式に変換して渡しています。

④cameraServer.pyの作成

次に、Flaskから呼ばれるメインアプリケーション「cameraServer.py」を以下のように作成します。

このプログラムでは、まずFlaskオブジェクトを作成した上で、「@app.route(‘/’)」からの3行で「/」にアクセスした時に「index.html」を返すようにし、「@app.route(‘/video’)」からの4行で「/Video」にアクセスした時に、カメラから取得した画像を返すようにしています。次の「def gen(camera)」関数の部分は、カメラからの画像データをWhileループで継続的に取得し、Context-Typeを設定してvideo()に返却しています。

プログラムの最後の部分は、自身がメインスレッドの場合(つまりflask runで実行されない場合)に、スレッドを有効にして、上記の「video()」呼び出しカメラから動画を取得するスレッドを開始します。その後「app.run()」を実行してflaskを起動しています。app.runの2つ目の引数は、flaskを立ち上げるポート番号ですので、既に80番ポートをNginxやApacheなどで利用している場合は書き換えてください。

⑤index.htmlの作成

次に「templates」フォルダを作成して、index.htmlを作成します。
※index.htmlは必ず「templates」フォルダを作成して配置する必要があります。

index.htmlの特筆すべきところは、imgタグの中で「/video」を呼び出しているところぐらいかと思います。

以上で、カメラ映像をライブ配信するプログラムの作成は完了です。

ライブ配信のテスト

それでは、作成したプログラムを実行して、ちゃんと映像が配信されるかテストしてみましょう。

①プログラムの実行

プログラムの起動は、rootユーザで以下のコマンドを実行します。今回は、画面に表示しないのでVNCでログインしたコンソールで実行する必要はありませんよ。

プログラムが正常に起動すると、以下のようにカメラスレッドが立ち上がり、続いてFlaskが起動します。

終了させる時は、画面にも表示されていますが「CTRL+C」キーを押します。

②ブラウザから確認

それでは、PCのブラウザを立ち上げ「http://<Raspberry PiのIPアドレス>/」にアクセスしてみましょう。
以下のように、防犯カメラの映像がライブ配信されると思います!!私の環境では、0.2秒程度の遅延はあるものの、ほぼリアルタイムでカメラの映像が見えています。

Raspberry Pi起動時に自動起動する

最後に、Raspberry Piの起動後にSSHでログインしてプログラムを手動で実行するのは面倒なので、systemdにサービス登録して、Raspberry Piの起動時に自動的に監視カメラのプログラムが実行されるようにします。

①cameraServer.shの作成

systemdに登録するシェルスクリプト「cameraServer.sh」を以下のように作成します。

Systemdからの起動の場合環境変数が読み込まれないので、環境変数をいろいろ記述(不要なのもあるかもしれません)して、先ほど作成した「cameraServer.py」をフルパスで記述して実行できるようにします。

②cameraServer.shの確認

シェルスクリプトを作成したら、実行権限を付与して、ちゃんと起動できるか確認してみます

③flask.serviceの確認

上で作成したシェルスクリプトを呼び出すSystemd用のファイルを「/etc/systemd/system/flask.service」に作成します。

④サービスの起動確認

それでは、Systemctlコマンドを用いて、以下のようにサービスを起動してみてください。サービスがちゃんと起動したかは、Systemctlコマンドに「status」オプションを付けると確認できます。

ちなみに、サービスを停止させるときは「systemctl stop flask.service」で停止できます。

⑤サービスの自動起動設定

最後に、Raspberry Pi起動時に自動的にサービスを起動させるために、Systemctlコマンドに「enable」オプションをつけて実行します。

⑥再起動して確認

それでは、Raspberry Piを再起動して、防犯カメラのサービスが自動的に起動するか確認してみてください。また、ブラウザからアクセスして映像が見えるかも確認してくださいね。

おわりに

今回はカメラで撮影した動画をライブ配信することをやってみました。次回は、防犯カメラに動体検知機能を追加し、動体を検知したらLineに通知がくるようにしてみたいと思います。

連載記事

 1回目:カメラの設定と動画記録
 2回目:カメラ映像のライブ配信
 3回目:動体検知機能とLineへの通知 ←次はこれ
 4回目:顔認証機能とLineへの通知
 5回目:Raspberry PiへのAlexaの搭載
 6回目:顔認証後にAlexaで音声通知

関連記事

記事が参考になったら、ブログランキングに協力(クリック)して貰えると嬉しいです。

昼間はIT企業に勤めてますが、プライベートでは「育児×家事×IoT」をテーマに家のスマートホーム化に取り組んでいます。Androidアプリも作っているので使って下さい。質問・コメントは、↓のコメント蘭でもFacebookメッセンジャーでもどちらでも大丈夫です。
E-mail:naka.kazz.d@gmail.com

naka-kazzをフォローする
スマートホーム開発者向け
スポンサーリンク
naka-kazzをフォローする
スマートホーム×DIY

コメント

  1. root@raspberrypi:/home/pi/camera# python cameraServer.pyを実行する
    ImportError:No module named base_cameraというエラーメッセージが出ます。

    • 記事をお読みいただきありがとうございます。「①base_camera.pyのダウンロード」の箇所でダウンロードした「base_caera.py」を「cameraServer.py」と同じフォルダに置いていますでしょうか?
      _

  2. ご丁寧にご回答くださりありがとうございます。上記の問題は解決しました。Desktopに移動し実行しましたら解決はしたのですが新しいImportError:No module named camera のエラーが出てきました。ラズパイとカメラは接続済みです。
    どうすればよろしいでしょうか?
    お忙しい中、よろしくお願いします。

    • お返事遅れすいません。問題解決したとのこと、良かったです。「No module named camera」のエラーですが、camera.pyがCameraServer.pyと同じフォルダにある事をご確認下さい😊

  3. ご丁寧にご回答くださりありがとうございます。
    Traceback (most recent call last):
    File “cameraServer.py”, line 3, in
    from camera import Camera
    File “/home/pi/camera/camera.py”, line 7, in
    from base_camera import BaseCamera #<–1箇所目
    ImportError: No module named base_camera

    のエラーが出てきました。ラズパイとカメラは接続済みです。
    どうすればよろしいでしょうか?
    お忙しい中、よろしくお願いします。

    • 2つ前のご質問と同じかと思われますが、base_camera.pyは同じフォルダにありますでしょうか?

  4. お忙しい中申し訳ありませんが
    自分もcameraServer.pyの実行が上手くいきません。原因はなんでしょうか。

    ホスト:~ $ ls
    Bookshelf Desktop camera ダウンロード テンプレート ドキュメント ビデオ 音楽 画像 公開
    ホスト:~ $ cd camera/
    ホスト:~/camera $ ls -l
    合計 40
    -rw-r–r– 1 pi pi 3659 7月 27 22:24 base_camera.py
    -rw-r–r– 1 pi pi 3655 7月 27 22:14 base_camera.py~
    -rw-r–r– 1 pi pi 5845 7月 27 22:23 camera.py
    -rw-r–r– 1 pi pi 5639 7月 27 22:09 camera.py~
    -rw-r–r– 1 root root 792 7月 27 22:55 cameraServer.py
    -rw-r–r– 1 root root 793 7月 27 22:52 cameraServer.py~
    drwxr-xr-x 2 pi pi 4096 7月 27 22:28 templates
    ホスト:~/camera $ python cameraServer.py
    Traceback (most recent call last):
    File “cameraServer.py”, line 28, in
    video()
    TypeError: video() takes exactly 1 argument (0 given)

    • ブログをお読みいただきありがとうございます。一般ユーザ(piユーザ)で実行されているようですので、rootユーザで実行してみたらどうでしょうか?
      $ su
      password: <--rootユーザのパスワードを入れる # python cameraServer.py

  5. 再度、お忙しい中申し訳ありません。
    cameraServer.pyの実行が上手くいきません。

    root@pi:/home/pi/camera# python cameraServer.py
    Traceback (most recent call last):
    File “cameraServer.py”, line 3, in
    from Camera import Camera
    File “/home/pi/camera/Camera.py”, line 7
    from base_camera import BaseCamera  #<–1箇所目
    ^
    SyntaxError: invalid syntax

    全て同じフォルダにあるのですがうまく行きません。
    何度も申し訳ないですが、よろしくおねがいします。

    • シンタックスエラーと出ているので「#<–1箇所目」のコメント部分の削除をお試しいただけますか?

  6. お忙しいところ、恐れ入ります。
    私もpython cameraServer.pyを走らせても、

    Traceback (most recent call last):
    File “cameraServer.py”, line 2, in
    from flask import Flask, render_template, Response
    ImportError: No module named flask

    とエラーが出て、動きません.

    何が悪いのでしょうか?ご教授お願いします。

    • ブログをお読みいただきありがとうございます。
      お使いの環境にFlaskがインストールされていないことが原因かと思われます。
      「pip install Flask」とコマンドを入力してFlaskをインストールすることを試してみて頂けますでしょうか?

      • 早速のご返答ありがとうございます。

        pip および Flask をインストールしてみましたが、より、長いエラーが表示され、仕方

        なく最初からやりなおしました。以前は raspios buster lite をダウンロードした

        ために動かなかった様で、raspios busterを試したら、ちゃんと動きました。ありが

        とうございました。しかし残念ながら動画は何秒かaviで保存されているのですが、ブ

        ラウザで、モニターすることができません。

        Internal Server Error
        The server encountered an internal error and was unable to complete your request. Either the server is overloaded or there is an error in the application.

        と表示されてしまいます。

        お忙しいところ誠に恐れ入りますが、何かヒントをお教え願いますでしょうか?

        よろしくお願いします。

      • 申し訳ありませんでした。自己解決しました。

        templates フォルダを誤ってtmplate フォルダでつくっていました。

        動画配信できました。ありがとうございました。

  7. 参考にさせていただいております。

    カメラが720p@60fpsなので、720p@60fpsで撮像し配信は60fpsである必要はないのですが、録画画像は60fpsの画像で保存したいのですが、可能でしょうか?

    変更したところは以下になります。

    Camera.py

    28行目の解像度のことろを
    camera.resolution = (1280, 720)
    camera.framerate = 60.0

    35,51行目のフレームレートと解像度を変更
    out = cv2.VideoWriter(save_file_name, fourcc, 60.0, (1280,720))

    上記の変更をしたのですが、保存画像が60fpsの動画で保存されていません。

    また、データ量が多くなるのでH264で保存したく、以下のように変えたのですが
    うまくいきませんでした。
    fourcc = cv2.VideoWriter_fourcc(*’H264′)

    何かわかりましたらご教示ください。

    • ブログに訪問いただきありがとうございます。720p@60fpsでの録画ということですが、60fpsはRaspberry Piの性能上けっこう厳しいと思われます。さらにH264での圧縮となるとさらに厳しいです。Raspberry Pi 4Bをお使いであればH264圧縮の部分は30fpsであればハードウェアで圧縮できますので、ハードウェア圧縮を使えば、少しは改善されるかもしれません。

  8. ありがとうございます。
    v4l2-ctlでカメラのフォーマットを確認するとH264の出力があったので、カメラの出力をそのまま取り込んだらいけないかな?と思っていましたがやはり無理なのでしょうか?

    あと、記事のように640x480で20fpsで保存したのですが、保存されている動画データのフレームレートが20fpsにならないのですが、どこかチェックしたらよい部分などありますか?

    お忙しいところ申し訳ありませんが、よろしくお願いします。

    • RaspberryPiの機種を書いていませんでした。
      Raspberry Pi 4Bの8GBを使用しています。

      よろしくお願いします。

      • すみません。間違えました。
        Raspberry Pi 4Bの4GBの方を使っていました。

        あと録画ファイルですが640×480でも7~8fpsぐらいしか出ていません。
        どこか設定するところがあるのでしょうか?
        お手数をおかけしますが、よろしくお願いします。

    • お返事が大変遅れました。すいません。H264に対応したカメラであれば、H264で直接読み込んでも良いと思います。フレームレートが20fpに満たないのは、Pythonのプログラムのループが20回/秒回っていない事が原因か、もしくはv4l2から読み込むモードがYUYVになっていませんでしょうか?。

      • 返信が遅くなり申し訳ありません。
        いろいろ試していて30fps出るようになりました。なぜできるようになったのかわかりませんが。
        おそらくカメラのモード設定がうまく出来ていなかったのかもしれません。
        ありがとうございました。

  9. 以下のエラーで起動できません原因わかるでしょうか?
    →エラーで囲んだところ

    pi@raspberrypi:~/camera $ systemctl status flask.service
    Warning: The unit file, source configuration file or drop-ins of flask.service changed on disk
    ● flask.service – Flask for CameraServer
    Loaded: loaded (/etc/systemd/system/flask.service; disabled; vendor preset: enabled)
    Active: active (running) since Mon 2020-09-21 16:41:06 JST; 1h 6min ago
    Main PID: 2478 (cameraServer.sh)
    Tasks: 9 (limit: 3738)
    CGroup: /system.slice/flask.service
    ├─2478 /bin/bash /home/pi/camera/cameraServer.sh
    ├─2479 sudo python /home/pi/camera/cameraServer.py
    └─2484 python /home/pi/camera/cameraServer.py

    → エラー
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: self._init_preview()
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: File “/usr/lib/python2.7/dist-packages/p
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: self, self._camera.outputs[self.CAMERA
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: File “/usr/lib/python2.7/dist-packages/p
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: self.renderer.inputs[0].connect(source
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: File “/usr/lib/python2.7/dist-packages/p
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: prefix=”Failed to enable connection”)
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: File “/usr/lib/python2.7/dist-packages/p
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: raise PiCameraMMALError(status, prefix
    9月 21 16:41:08 raspberrypi cameraServer.sh[2478]: PiCameraMMALError: Failed to enable connec
    → エラー

    • ブログをお読みいただきありがとうございます。カメラを開く時にエラーになっているようです。実行ユーザはrootになっていますでしょうか?

  10. ブログ通りにcameraServer.shを入力したのですが、確認のときに
    「./cameraServer.sh: 行 7: python: コマンドが見つかりません」というエラーが出てしまいました。
    このエラーの解決方法を教えてください。

    • ブログをお読みいただきありがとうございます。cameraServer.sh内の「export PATH:」の行が間違っている可能性があります。「:」と「;」など、ご確認いただけますでしょうか?

      •  解決できました。ありがとうございます。
         これからもこのブログを読んで防犯カメラを完成させたいと思います。

  11. ②のブラウザから確認でPCからアクセスしたいと思うのですが、 
    「http://<Raspberry PiのIPアドレス>/」にアクセス出来ません。
    何かやらなければいけないことがありましたら、教えてください。

  12. ④のプログラム実行で
    「python cameraServer.py」
    を実行すると、
     「cameraServer.py line 29, in
    app.run(host=”0.0.0.0″,port80)」
    というエラーが出てしまうのですが、解決策を教えてください。

    • ブログをお読みいただきありがとうございます。エラーの全文が分からないので、なんともですが。rootユーザで実行していますでしょうか?ポート80を使うのでルートユーザでの実行が必要です。

  13.  質問があるのですが、
     ライブ配信の映像を他の端末で確認するときに、ラズパイが接続しいるWiFiのみで配信を見ることができる仕組みを教えてください。

    • 一般的なWifiルータ(ラズパイが接続しているWifiの親機)は,プライベートIPアドレスというものを払い出しています。このプライベートIPアドレス(192や172から始まる)は、そのWifiルータの電波が届く範囲でのみ有効なIPアドレスになるので、ラズパイが接続しているWifiの中でしか配信を見ることができません。

タイトルとURLをコピーしました