Raspberry Pi で簡単おうちセキュリティカメラを 作ってみた
Author : 三平 悠磨
こんにちは、IoT スペシャリストソリューションアーキテクトの三平です。
最近は安価なネットワークカメラ製品が色々販売されていて、セキュリティカメラや見守りカメラとして簡単に利用できるのでとても便利ですね。でも、そういった製品をわざわざ買わなくても、皆様のご自宅に余っている Raspberry Pi と USB カメラを組み合わせるだけで、簡単にクラウド録画対応のおうちセキュリティカメラを作れてしまうんです!
用意するのは Raspberry Pi と USB カメラだけです
この記事では、Raspberry Pi と USB カメラ、Amazon Kinesis Video Streams を用いた簡易的なホームセキュリティカメラシステムを構築します。カメラの映像を常にクラウドにアップロードするかわりに、Raspberry Pi の中で顔検出のアルゴリズムを動かし、検出時のみに動画をアップロードすることで、コストパフォーマンスの良いクラウド録画の仕組みを構築しています。
この記事で作成するシステムのアーキテクチャは下図の通りです。
このシステムは以下のような流れで動作します。
- Raspberry Pi 上で Dlib を利用して顔検出を行い、顔を検出したら Amazon Kinesis Video Streams Producer SDK を起動する
- Amazon Kinesis Video Streams Producer SDK で USB カメラの映像をクラウドへアップロードする (一定時間)
- クラウドへの動画アップロードが終了したら、HLS を使用したストリーミング再生用の URL を取得する
- ストリーミング再生用のURLを Amazon Simple Notification Service (以下 Amazon SNS) を通じてユーザへ通知する
- 通知を受け取ったユーザは、再生用 URL から録画された動画をオンデマンドで再生できる
目次
ご注意
本記事で紹介する AWS サービスを起動する際には、料金がかかります。builders.flash メールメンバー特典の、クラウドレシピ向けクレジットコードプレゼントの入手をお勧めします。
1. Amazon Kinesis Video Streams とは ?
Amazon Kinesis Video Streams を用いると、カメラデバイスからの動画を簡単にクラウドへアップロードし保存でき、分析や機械学習、再生などに利用することができます。カメラデバイス向けの組み込みのSDKや再生用の仕組みを提供しており、複雑な実装などは必要なく、すぐに動画のストリーミングを始めることができます。
また、2019 年 12 月には WebRTC を用いた超低遅延の双方向ストリーミングもサポートし、ユースケースに応じて柔軟にご利用いただけるようになりました。これらは、フルマネージドなサービスとして提供されているので、数百万ものデバイスからの動画ストリーミングのためのスケーラブルなインフラとしてご利用いただけます。
2. Raspberry Pi のセットアップ
このシステムを構築するためには以下のハードウェアが必要です。
- Raspberry Pi (Raspberry Pi 3 Model B+ で動作確認しています)
- 8 GB 以上の microSD カード
- USB カメラ
- 電源アダプターおよび電源用 USB ケーブル
OS は Raspberry Pi OS を利用します。こちらのページから、Raspberry Pi OS (32-bit) with desktop をダウンロードし、microSD カードに書き込んでください。Raspberry Pi のセットアップ方法はこちらのドキュメントに記載があります。
Raspberry Pi を起動し、有線もしくは無線でインターネットへ接続ができたら、Raspberry Pi のターミナルを起動して (SSH によるリモート接続でも OK です)、以下のコマンドを実行して必要なライブラリをインストールします。
sudo apt update
sudo apt upgrade
sudo apt install -y automake build-essential cmake libatlas3-base libgstreamer-plugins-base1.0-dev python3-opencv
sudo -H pip3 install boto3 dlib
続いて、Amazon Kinesis Video Streams Producer SDK C++ をダウンロード&インストールします。一連のコマンドを実行するのに30分ほどかかりますので、ビルドの待ち時間にこの後の手順の AWS 側の設定を行っておきましょう。なお、ビルド手順が変更になっている可能性がありますので、最新のビルド手順については Amazon Kinesis Video Streams Producer SDK C++ の README をご参照ください。
cd
git clone --recursive https://github.com/awslabs/amazon-kinesis-video-streams-producer-sdk-cpp.git
mkdir -p amazon-kinesis-video-streams-producer-sdk-cpp/build
cd amazon-kinesis-video-streams-producer-sdk-cpp/build
cmake -DBUILD_GSTREAMER_PLUGIN=ON ..
make
3. Amazon Kinesis Video Streams のセットアップ
本システムを構築する際に利用するリージョンは、Amazon Kinesis Video Streams および Amazon SNS が利用できるリージョンを選択してください。サービスが利用可能なリージョンはリージョン表から調べることが可能です。
Amazon Kinesis Video Streams のコンソールへアクセスします。ビデオストリームを作成をクリックします。
クリックすると拡大します
ビデオストリーム名は raspi-stream などの分かりやすい名前を入力し、右下のビデオストリームを作成をクリックします。なお、デフォルトではアップロードした動画は 1 日だけ保存されますが、必要に応じてデータの保持期間を変更することも可能です (最短 0 時間〜最大 10 年)。
クリックすると拡大します
4. Amazon Simple Notification Service のセットアップ
続いて、Amazon SNS をセットアップします。Amazon SNS のコンソールへアクセスします。左側のメニューのトピックをクリックし、右上のトピックの作成トピックの作成をクリックします。
クリックすると拡大します
raspi-topic などの分かりやすい名前を入力し、右下のトピックの作成をクリックします。
クリックすると拡大します
トピックが作成されたら、詳細内の ARN の値をメモしておきます。画面下部の サブスクリプションの作成 をクリックします。
クリックすると拡大します
Amazon SNS ではプッシュ通知やSMSなどを用いた通知を行うことができますが、この手順ではEメールによる通知を行います。プロトコルは E メール を選択し、エンドポイントに通知先となるご自身のメールアドレスを入力してください。最後に画面右下の サブスクリプションの作成 をクリックします。
クリックすると拡大します
入力したメールアドレスに AWS Notification - Subscription Confirmation という件名のメールが届きますので、本文内の Confirm subscription のリンクをクリックして、サブスクリプションを有効化しておきましょう。
5. Raspberry Pi のプログラムの設定
AWS のマネジメントコンソールでの作業が完了したら、Raspberry Pi に USB カメラを接続し、再び Raspberry Pi のターミナルに戻って、以下のコマンドを実行します。
mkdir ~/surveillance-app
cd ~/surveillance-app
続いて、作成した ~/surveillance-app フォルダに以下のプログラムを main.py として保存します。
# Copyright 2020 Amazon.com, Inc. or its affiliates. All Rights Reserved.
# SPDX-License-Identifier: MIT-0
#
# Permission is hereby granted, free of charge, to any person obtaining a copy of this
# software and associated documentation files (the "Software"), to deal in the Software
# without restriction, including without limitation the rights to use, copy, modify,
# merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
# permit persons to whom the Software is furnished to do so.
#
# THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
# INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A
# PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
# HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
# OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
# SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
#
import datetime
import os
import subprocess
import time
import boto3
import cv2
import dlib
KVS_STREAM_NAME = os.environ["KVS_STREAM_NAME"]
SNS_TOPIC_ARN = os.environ["SNS_TOPIC_ARN"]
KVS_PRODUCER_BUILD_PATH = os.environ["KVS_PRODUCER_BUILD_PATH"]
APP_NAME = "kvs_gstreamer_sample"
RECORD_SEC = 30
EXPIRATION_MIN = 60
EXPIRATION_SEC = 60 * EXPIRATION_MIN
kvs = boto3.client("kinesisvideo")
sns = boto3.client("sns")
detector = dlib.get_frontal_face_detector()
def detect_face():
""" Wait until faces detected using dlib """
camera = cv2.VideoCapture(0)
while True:
_, frame = camera.read()
frame_rgb = cv2.cvtColor(frame, cv2.COLOR_BGR2RGB)
results, _, _ = detector.run(frame_rgb, 0)
if results:
break
camera.release()
return
def upload_video():
""" Upload video using Amazon Kinesis Video Streams Producer SDK C++ """
start = time.time()
kvs_app = f"{KVS_PRODUCER_BUILD_PATH}/{APP_NAME}"
try:
subprocess.run(
[kvs_app, KVS_STREAM_NAME],
cwd=KVS_PRODUCER_BUILD_PATH,
timeout=RECORD_SEC
)
except subprocess.TimeoutExpired:
end = time.time()
print("record finished")
return start, end
print("record interrupted")
return None, None
def get_session_url(start, end):
""" Get HLS streaming session URL """
endpoint = kvs.get_data_endpoint(
APIName="GET_HLS_STREAMING_SESSION_URL",
StreamName=KVS_STREAM_NAME
)['DataEndpoint']
kvam = boto3.client("kinesis-video-archived-media", endpoint_url=endpoint)
url = kvam.get_hls_streaming_session_url(
StreamName=KVS_STREAM_NAME,
PlaybackMode="ON_DEMAND",
ContainerFormat="MPEG_TS",
DisplayFragmentTimestamp="ALWAYS",
Expires=EXPIRATION_SEC,
HLSFragmentSelector={
"FragmentSelectorType": "PRODUCER_TIMESTAMP",
"TimestampRange": {
"StartTimestamp": start,
"EndTimestamp": end,
}
},
)['HLSStreamingSessionURL']
print(f"HLS session URL: {url}")
return url
def notify_url(url, timestamp):
""" Notify HLS streaming session URL via Amazon SNS """
date = datetime.datetime.fromtimestamp(timestamp)
subject = "通知: 顔を検出しました"
message = f"""セキュリティカメラで顔を検出しました。
ストリーム名: {KVS_STREAM_NAME}
日時: {date.strftime('%Y/%m/%d %H:%M:%S')}
再生用URL: {url} ({EXPIRATION_MIN}分のみ有効です)
"""
sns.publish(
TopicArn=SNS_TOPIC_ARN,
Message=message,
Subject=subject
)
def main():
print("start surveillance application")
while True:
detect_face()
print("face detected: start recording")
start, end = upload_video()
if start and end:
url = get_session_url(start, end)
notify_url(url, start)
if __name__ == '__main__':
main()
アプリケーションを実行する際に、AWS のクレデンシャルが必要になります。AWS CLI を利用できる PC などを用いて AmazonKinesisVideoStreamsFullAccess および AmazonSNSFullAccess の権限を持つユーザーで以下のコマンドを実行し、一時的なクレデンシャルを取得します。AWS CLI のインストール方法はこちらのドキュメントをご参照ください。
aws sts get-session-token
以下のような結果が得られます。
{
"Credentials": {
"AccessKeyId": "...",
"SecretAccessKey": "...",
"SessionToken": "...",
"Expiration": "2020-09-15T00:39:31Z"
}
}
Raspberry Pi のターミナルに戻って、以下のコマンドで環境変数を設定します。
export AWS_ACCESS_KEY_ID="上記の AccessKeyId の値"
export AWS_SECRET_ACCESS_KEY="上記の SecretAccessKey の値"
export AWS_SESSION_TOKEN="上記の SessionToken の値"
export AWS_DEFAULT_REGION="選択したリージョン (例: ap-northeast-1)"
また、先ほどの手順で作成した AWS のリソースについても環境変数に設定します。
export KVS_STREAM_NAME="作成したAmazon Kinesis Video Streamsのストリーム名(例: raspi-stream)"
export SNS_TOPIC_ARN="先ほどメモしたSNSのトピックのARN (例: arn:aws:sns:region:accountID:raspi-topic)"
そして、Amazon Kinesis Video Streams Producer SDK C++ をビルドしたパスも環境変数に設定しておきます。
export KVS_PRODUCER_BUILD_PATH="$HOME/amazon-kinesis-video-streams-producer-sdk-cpp/build/"
これでアプリケーションを実行するための準備は完了です。
6. アプリケーションの実行
環境変数を設定したターミナルで以下のコマンドを実行して、アプリケーションを実行します
python3 main.py
アプリケーションを起動すると、カメラの画像フレームを取得し、Dlib による顔検出を行います。そして、顔が検出されると以下のようなログが出力され、Amazon Kinesis Video Streams Producer SDK C++ を用いたクラウドへ動画のアップロードが開始されます。
face detected: start recording
30 秒ほどすると録画が終了し、ターミナルには以下のログが出力されます。
record finished
HLS session URL: https://...
同時に、登録したメールアドレスに以下のようなメールが届きます。
セキュリティカメラで顔を検出しました。
ストリーム名: raspi-stream
日時: 2020/10/01 12:32:49
再生用URL: https://... (60分のみ有効です)
再生用 URL を iPhone や QuickTime Player などで開くと、録画された動画をオンデマンドで再生することができます。なお、再生用URLは、発行されてから 60 分だけ有効となるように設定されています。
QuickTime Player で再生している様子 (映っているのは不審者ではなく私です)
以上のように、Raspberry Pi + USB カメラで顔検出を行い、クラウドへ動画をアップロード、E メールで通知を行い、動画をオンデマンドで再生する一連の流れを実現することができました。
7. アプリケーションの常時実行のための設定
先ほどの方法では、環境変数にAWSの一時認証情報をセットすることで、アプリケーションから Amazon Kinesis Video Streams や Amazon SNS を利用できるようにしていましたが、実際にこのシステムを運用することを考えると、毎回環境変数を設定するのは現実的ではありません。
家庭での利用など、カメラの数が限られている場合は、Amazon Kinesis Video Streams と Amazon SNS のみに権限を絞った IAM ユーザーを作成し、IAM ユーザーに紐づく認証情報を環境変数に設定しておくという方法が考えられます。一方で、多数のカメラを利用する場合は、AWS IoT Core でカメラごとに個別のクライアント証明書を発行し、証明書を用いて AWS の一時認証情報を取得するという方法があります。いずれの場合も、IAMユーザーや証明書に紐づくポリシーに与える権限は最小にしておくことで、万が一認証情報が流出した場合の被害を最小にとどめることが可能です。具体的には Amazon Kinesis Video Streams の対象ストリームへのアップロードや HLS でのセッション URL の取得、 Amazon SNS の特定トピックへのメッセージ発行のみの権限を与えるようにします。
また、パスワードの変更や SSH での公開鍵認証の利用など、Raspberry Pi 自体のセキュリティも高めておきましょう。IoT におけるセキュリティの考え方についてはこちらのスライドもぜひご参照ください。
8. 運用コストの見積もり
さて、本システムを運用した場合にどのくらいのコストがかかるかを見積もってみます。見積もりにあたって、以下のような条件を仮定します。
- 1 日あたりの動画のアップロード回数(顔検出回数) : 30 回
- 1 日あたりの動画の再生回数 : 10 回
- Amazon Kinesis Video Streams の動画の保持期間 : 7 日
- 1 回あたりの動画の秒数 : 30 秒
- 動画のビットレート : 1 Mbps (H.264 720p 30fps 程度)
- 利用するリージョン : 東京リージョン
Amazon Kinesis Video Streams の料金を見ると、動画のアップロード、HLS での再生、動画保存に対して費用がかかります。また、HLS での再生時にはデータ転送料金も発生します。先ほどの条件をベースに費用を計算してみると以下のようになります。
- 1 回の動画サイズ : 1 Mbps × 30 秒 × 0.125 bit / byte = 3.75 MB
- 1 ヶ月あたりに取り込まれるデータサイズ : 3.75 MB × 30 回/日 × 30 日/月 ÷ 1000 MB / GB = 3.375 GB
- 1 ヶ月あたりに再生されるデータサイズ : 3.75 MB × 10 回/日 × 30 日/月 ÷ 1000 MB/GB = 1.125 GB
- 1 ヶ月あたりの保存データサイズ : 3.375 GB × 7 日 ÷ 30 日/月 = 0.7875 GB・月
- 1 ヶ月あたりのコスト
- 動画の取り込み : 3.375 GB × 0.01097 USD/GB = 0.03702375 USD
- HLS での再生 : 1.125GB × 0.01536USD/GB = 0.01728 USD
- データ転送 : (1.125 GB - 1 GB) × 0.114 USD/GB = 0.01425 USD (1GB/月の無料利用枠を適用)
- 動画の保存 : 0.7875 GB・月 × 0.02500 USD/GB・月 = 0.0196875 USD
- 合計 : 0.08824125 USD
Amazon SNS の料金を見るとパブリッシュと E メールでの配信に料金がかかります。1 ヶ月あたりの配信回数は、10 件/日 × 30 日/月 = 300 件/月となりますが、パブリッシュは 100 万件/月の無料利用枠、E メールでの配信は 1,000 件/月の無料利用枠があるため、Amazon SNS の利用料金は無料となります。厳密にはデータ転送料金が発生しますが、動画と比べて転送量が小さいため、ここでは省略します。
ということで、これらの料金を合計すると、月あたり約 0.09 USD、わずか 10 円前後でホームセキュリティカメラのシステムを運用することができました。なお、本見積もりは 2020 年 9 月 1 日における東京リージョンでのサービス料金をもとに算出しております。実際にご利用される場合には、上記サービス料金のページから対象リージョンの料金をご確認の上ご利用ください。
9. まとめ
この記事では、Raspberry Pi と USB カメラを用いて、クラウド録画対応のホームセキュリティカメラシステムを構築しました。Amazon Kinesis Video Streams を用いることで、複雑な実装などをしなくても簡単にカメラの映像をクラウドへアップロードし、スマホやアプリからストリーミング再生することができます。
このシステムでは顔を検出した際に動画をアップロードするようにしましたが、例えば個人識別と組み合わせることで知らない人を検出した場合のみに動画を記録したり、笑顔の認識と組み合わせることで日常生活の笑顔の瞬間を自動的にクラウドに保存するといった、様々なバリエーションが考えられます。
アップロードした動画に対してさらに複雑な分析などを行いたい場合は、Amazon Kinesis Video Streams と Amazon Rekognition Video を組み合わせた動画分析を行えるハンズオンも公開しておりますので、ぜひ試してみてください。
筆者紹介
三平 悠磨 (みひら ゆうま)
アマゾン ウェブ サービス ジャパン合同会社
IoT スペシャリスト ソリューションアーキテクト
ソフトウェアエンジニアとして会話 AI やロボット開発を経験しました。AWS では IoT スペシャリストソリューションアーキテクトとして、お客様の IoT 関連案件を支援しています。趣味はバンドと作曲で、プログラミングやテクノロジーを駆使して音楽をもっと楽しくしたいと思っています。
AWS を無料でお試しいただけます