RaspberryPi 3 Model B+でIoT監視カメラをつくる(その6 プログラムの修正)
Contents
RaspberryPi(ラズパイ)でIoT監視カメラ
RaspberryPi 3 Model B+とカメラ(Raspberry Pi Camera Module V2)とモーションセンサー(HC-SR501)で動きがあった時だけ録画するIoT監視カメラを作成したときの備忘録の6回目。
今回は3回目の記事のプログラムに多少の変更を加えたので別記事として残しておくことにした。
ちなみに前回までのプログラムについてはこちらを参照。
過去関連記事
1回目はRaspberryPiとカメラ、モーションセンサーとの接続に関するこちらの記事を参照。
2回目はGoogleDriveにアクセスする為のGoogle Developersの設定とLINEにメッセージを送信するためのLINE Notifyでのアクセストークンの発行に関する記事。
3回目はPythonのプログラムの説明の記事。
4回目はプログラムの起動環境、CLI起動とプログラムの自動起動に関する記事。
5回目のケースの外箱を製作した時の記事はこちら。
全体構成図
繰り返しになるがIoT監視カメラの全体構成図を載せておく。
モーションセンサーで動きを検知してカメラで撮影した映像をクラウド(GoogleDrive)にアップロード※してLINEで伝える仕組みになっている。
※今まではh364形式の映像ファイルをアップロードしていた。
ハードウェア
使用したハードウェアは以下の通り。
Raspberry Pi 3B+
尚、この時はRaspberry Pi 3B+ で作成したが今なら Raspberry Pi 4B で作成するのが良いと思う。
後述するプログラムはラズパイ4でも問題なく動作した。
カメラモジュール
モーションセンサー
変更点
プログラムの変更点は以下の通り。
- 映像の上部にタイムスタンプを表示するようにした
- ファイル形式をh264からmp4に変換した後にGoogle Driveにアップロードするようにした
今まではファイル名の一部に日付時刻を使っていたので映像に敢えて日付時刻を表示する必要は無いかと思ってのだが使っているうちにやはり映像にもタイムスタンプが合ったほうが分かりやすいと思い直したので追加表示することにした。
また映像ファイルはラズパイカメラでの標準的なファイル形式(拡張子がh264)で保存してGoogleDriveにアップロードしていたが再生できるプレイヤーが少なく、特にスマートフォンで再生させるためには別途アプリをインストールする必要があったので「それならばラズパイ側でmp4形式に変換してからアップロードしよう」と思い変更する事にした。
GPACのインストール
事前にラズパイにGPAC※をインストールする。
※GPACはオープンソースのマルチメディアフレームワーク。GPACのMP4Boxを使ってh264からmp4に変換を行う
sudo apt-get install gpac
プログラム
# -*- coding: utf-8 -*-
"""
Created on Sun Jul 28 09:32:20 2019
@author: Souichirou Kikuchi
2019/11/04 映像上部に日付・時刻を追加表示
2019/11/22 h264からmp4へファイル変換
"""
from picamera import PiCamera
from time import sleep
from pydrive.auth import GoogleAuth
from pydrive.drive import GoogleDrive
from concurrent.futures import ThreadPoolExecutor # スレッド処理
import RPi.GPIO as GPIO
import datetime as dt
import os
import json
import requests # LINEメッセージ
import subprocess # MP4Boxコマンド実行の為
SC_CAMERA_PIN = 5 # ピンの名前を変数として定義
MAX_REC_TIME = 3600 # 最長録画時間(秒数)
SAVE_DIR = "./video/" # ファイル保存用ディレクトリ
INITIAL_FILE= "./cert/initial.json" # 初期設定ファイル
LINE_URL = "https://notify-api.line.me/api/notify" # LINEメッセージ用URL
DRIVE_LINK = "https://drive.google.com/open?id=" # LINEに表示するGoogleDriveへのリンク
INTERVAL = 0.5 # 監視間隔(秒)
AN_TEXT_SIZE = 24 # 録画画像上部に表示される注釈文字のサイズ
GPIO.setmode(GPIO.BCM) # ピンをGPIOの番号で指定
GPIO.setup(SC_CAMERA_PIN, GPIO.IN, pull_up_down=GPIO.PUD_DOWN) # GPIOセットアップ
class SecurityCameraClass: # セキュリティカメラのクラス
def __init__(self):
with open(INITIAL_FILE) as f: # 初期設定ファイルの読み込み
jsn = json.load(f)
self.folder_id = jsn["folder_id"] # folder_idの読み込み
self.token = jsn["line_token"] # LINE用tokenの読み込み
self.location = jsn["location"] # 監視カメラ設置場所
self.camera = PiCamera()
# self.camera.annotate_text = self.location
# self.camera.annotate_text_size = AN_TEXT_SIZE
self.camera.rotation = 270 # カメラを回転
gauth = GoogleAuth() # GoogleDriveへの認証
gauth.LocalWebserverAuth()
self.drive = GoogleDrive(gauth)
def StartRecording(self): # 録画開始
time_stamp_file = "{0:%Y-%m-%d-%H-%M-%S}".format(dt.datetime.now()) # 日付時刻をセット
time_stamp_disp = "{0:%Y/%m/%d %H:%M:%S}".format(dt.datetime.now()) # 日付時刻をセット
self.save_file_path = SAVE_DIR + "video" + time_stamp_file + ".h264" # ディレクトリ、ファイル名をセット
self.camera.annotate_text = self.location + " " + time_stamp_disp # 映像上部に表示
self.camera.annotate_text_size = AN_TEXT_SIZE
self.camera.start_recording(self.save_file_path) # 指定pathに録画
return True
def StopRecording(self): # 録画終了
self.camera.stop_recording() # 録画終了
executor = ThreadPoolExecutor(max_workers=3) # 同時実行は3つまでスレッド実行
executor.submit(self.OnTheread)
return False
def OnTheread(self): # ファイルのGoogleDriveへのアップロードは時間がかかるので別スレッドで行う
del_file_name = self.save_file_path # 対象pathを保存しておかないと別スレッドなので更新されてしまう
mp4_file_path = os.path.splitext(del_file_name)[0] + '.mp4' # 拡張子をmp4にしたファイル名
file_name = os.path.basename(mp4_file_path) # ファイル名部分を取り出し
# h264形式からmp4に変換
res=subprocess.call("MP4Box -add " + self.save_file_path + " " + mp4_file_path, shell=True)
if res == 0: # 変換が正常終了ならファイルをアップロード
f = self.drive.CreateFile({"title": file_name, # GoogleDrive
"mimeType": "video/mp4",
"parents": [{"kind": "drive#fileLink", "id":self.folder_id}]})
f.SetContentFile(mp4_file_path) # ファイル名指定
f.Upload() # アップロード
os.remove(del_file_name) # アップロード後にファイルは削除
os.remove(mp4_file_path) # アップロード後にファイルは削除
sec_camera.LineMessage() # LINEにメッセージを送信
def LineMessage(self): # LINEに録画検知しましたメッセージを送信する
headers = {"Authorization" : "Bearer " + self.token}
message = "録画検知しました " + DRIVE_LINK + self.folder_id
payload = {"message" : message}
requests.post(LINE_URL, headers=headers, params=payload)
def CloseCamera(self): # カメラクローズ
self.camera.close()
#main
try:
if __name__ == "__main__":
os.chdir(os.path.dirname(os.path.abspath(__file__))) # カレントディレクトリをプログラムのあるディレクトリに移動する
sec_camera = SecurityCameraClass()
rec = False # 録画中フラグ OFF
start_detect = dt.datetime.now() # 検知開始時刻
while True:
rec_time = dt.timedelta(seconds=0)
if GPIO.input(SC_CAMERA_PIN) == GPIO.HIGH: # 検知
if rec == False: # 録画 OFFなら
start_detect = dt.datetime.now() # ビデオスタート時刻
rec = sec_camera.StartRecording() # 録画開始
rec_time = dt.datetime.now() - start_detect # 録画時間を計算
if rec_time.total_seconds() >= MAX_REC_TIME: # 録画最大時間を超えた時
rec = sec_camera.StopRecording() # 録画終了
start_detect = dt.datetime.now() # ビデオスタート時刻
rec = sec_camera.StartRecording() # 録画開始
else: # 未検知
if rec == True: # 録画 ON なら
rec = sec_camera.StopRecording() # 録画終了
start_detect = dt.datetime.now() # ビデオスタート時刻リセット
# print("GPIO",GPIO.input(SC_CAMERA_PIN)," rec=",rec," 録画秒数",rec_time.total_seconds())
sleep(INTERVAL)
except KeyboardInterrupt:
pass
GPIO.cleanup()
sec_camera.CloseCamera()
主な変更点
映像上部に日付時刻を表示
クラスのコンストラクタでアノテーション(注釈)テキストとサイズを指定していたのをコメントアウト(41行目)。
# self.camera.annotate_text = self.location
# self.camera.annotate_text_size = AN_TEXT_SIZE
代わりにStartRecording時にアノテーションテキストとサイズを指定する(49行目)。
time_stamp_file = "{0:%Y-%m-%d-%H-%M-%S}".format(dt.datetime.now()) # 日付時刻をセット
time_stamp_disp = "{0:%Y/%m/%d %H:%M:%S}".format(dt.datetime.now()) # 日付時刻をセット
self.save_file_path = SAVE_DIR + "video" + time_stamp_file + ".h264" # ディレクトリ、ファイル名をセット
self.camera.annotate_text = self.location + " " + time_stamp_disp # 映像上部に表示
self.camera.annotate_text_size = AN_TEXT_SIZE
h264からmp4に変換
拡張子をmp4にしてファイル名を生成してMP4Boxコマンドで変換する(65行目)。
mp4_file_path = os.path.splitext(del_file_name)[0] + '.mp4' # 拡張子をmp4にしたファイル名
file_name = os.path.basename(mp4_file_path) # ファイル名部分を取り出し
# h264形式からmp4に変換
res=subprocess.call("MP4Box -add " + self.save_file_path + " " + mp4_file_path, shell=True)
修正は以上。
その他
その後、上記のプログラムに更に修正を加えた。
GoogleのTensorFlowを使って映像を機械学習でObject Detection(物体検出)してモノが写っている時だけ動画ファイルをクラウドの保存するようにした。
その時の記事はこちら。
最近のコメント