作りたいもの
DiscordBotで起動したり、停止したりできる動体検知カメラを作りたい。
DiscordBotを使用することで、外出先からでもコントロール可能なカメラが作成できる。
実際のプログラム
Discord Botの機能としては、監視カメラの起動、停止、画像の確認ができれば良いので、まずは監視カメラのプログラムを作成する。
detect.py
#!/usr/bin/python3 import datetime import cv2 as cv import os save_dir = '画像の保存先' fn_suffix = '.jpg' cap = cv.VideoCapture(0) cap.set(cv.CAP_PROP_FRAME_WIDTH, 1280) cap.set(cv.CAP_PROP_FRAME_HEIGHT, 720) DELTA_MAX = 255 DOT_TH = 10 MOTHON_FACTOR_TH = 0.10 avg = None while True: ret, frame = cap.read() motion_detected = False dt_now = datetime.datetime.now() dt_format_string = dt_now.strftime('%Y-%m-%d %H:%M:%S') f_name = dt_now.strftime('%Y-%m-%d_%H-%M-%S') + fn_suffix gray = cv.cvtColor(frame, cv.COLOR_BGR2GRAY) if avg is None: avg = gray.copy().astype("float") continue cv.accumulateWeighted(gray, avg, 0.6) frameDelta = cv.absdiff(gray, cv.convertScaleAbs(avg)) thresh = cv.threshold(frameDelta, DOT_TH, DELTA_MAX, cv.THRESH_BINARY)[1] motion_factor = thresh.sum() * 1.0 / thresh.size / DELTA_MAX motion_factor_str = '{:.08f}'.format(motion_factor) cv.putText(frame,dt_format_string,(25,50),cv.FONT_HERSHEY_SIMPLEX, 1.5,(0,0,255), 2) cv.putText(frame,motion_factor_str,(25,710),cv.FONT_HERSHEY_SIMPLEX, 1.5,(0,0,255), 2) if motion_factor > MOTHON_FACTOR_TH: motion_detected = True if motion_detected == True: #print('DETECTED') cv.imwrite(save_dir + f_name, frame) #画像の最大保存数を決める(50枚) files = os.listdir(save_dir) if len(files) >= 51: #print('REMOVED') files.sort() os.remove(save_dir + files[0]) k = cv.waitKey(1000) if k == 27: break cap.release() cv.destroyAllWindows()
次にdetect.pyをサービス化する。
念のためdetect.pyとDETECT.serviceには最高権限を与える。
/usr/lib/systemd/system/DETECT.service
[Unit] Description=Motion Detect Camera [Service] ExecStart=/home/pi/python/detect.py Restart=always Type=simple [Install] WantedBy=multi-user.target
次に撮影した画像を確認できるプログラムを作成する。
全ての画像をDiscordに送信するのは時間と通信量が消費されすぎるので、一枚のコラージュ画像を作成して送信するようにする。
下記のプログラムは、すでに監視カメラ画像が50枚存在する事を前提にしているため、事前に監視カメラ画像を適当に増やしておく。
collage.py
import os from PIL import Image, ImageDraw directory = "/nas/motion_detection/" #監視カメラ画像の保存先 files = os.listdir(directory) files.sort() images = [i for i in files if i.endswith('.jpg') == True] #画像の最大保存数50枚の場合 ##最大横幅(3200)÷(320)=10 ##最大縦幅(900)÷(180)=5 ###コラージュ画像 => 監視カメラの画像(横10枚×縦5枚) expected_size_collage = (3200, 900) #コラージュ画像のサイズ expected_size_image = (320, 180) #監視カメラ画像のサイズ(リサイズする) collage = Image.new("RGBA", expected_size_collage, color=(255,255,255,255)) file_count = 0 for h in range(0, expected_size_collage[1], expected_size_image[1]): for w in range(0, expected_size_collage[0], expected_size_image[0]): file_name = images[file_count] path = directory + file_name image = Image.open(path).convert("RGBA") image_width = image.size[0] image_height = image.size[1] width_factor = image_width / expected_size_image[0] height_factor = image_height / expected_size_image[1] if width_factor != height_factor: factor = min(width_factor, height_factor) expected_width = round(factor * expected_size_image[0]) expected_height = round(factor * expected_size_image[1]) start_width = round((image_width - expected_width) / 2) start_height = round((image_height - expected_height) / 2) end_width = expected_width + round((image_width - expected_width) / 2) end_height = expected_height + round((image_height - expected_height) / 2) image = image.crop((start_width, start_height, end_width, end_height)) image = image.resize(expected_size_image) collage.paste(image, (w, h)) file_count += 1 collage.save("コラージュ画像の保存先")
最後にDiscordBotのプログラムを作成する。
bot.py
#!/usr/bin/python3 import discord from discord.ext import commands import datetime import requests import datetime import subprocess, shlex webhook = "Discord Webhook URL" intents = discord.Intents.default() intents.message_content = True bot = commands.Bot( command_prefix=commands.when_mentioned_or("!"), debug_guilds=[サーバーID], intents=intents ) client = discord.Client() channel = チャンネルID @bot.event async def on_ready(): print('[INFO] <' + str(datetime.datetime.now().replace(microsecond=0)) + '> Bot is active') class detect_btn(discord.ui.View): def __init__(self, timeout=180): super().__init__(timeout=timeout) #監視カメラを起動する @discord.ui.button(label="Start", style=discord.ButtonStyle.green) async def start(self, button: discord.ui.Button, interaction: discord.Interaction): args = shlex.split("sudo systemctl start DETECT.service") ret = subprocess.call(args) await interaction.response.send_message("Start") #監視カメラを停止する @discord.ui.button(label="Stop", style=discord.ButtonStyle.red) async def stop(self, button: discord.ui.Button, interaction: discord.Interaction): args = shlex.split("sudo systemctl stop DETECT.service") ret = subprocess.call(args) await interaction.response.send_message("Stop") #保存された画像をコラージュして送信する @discord.ui.button(label="Callage", style=discord.ButtonStyle.blurple) async def collage(self, button: discord.ui.Button, interaction: discord.Interaction): await interaction.response.defer() args = shlex.split("sudo python3 python/collage.py") ret = subprocess.call(args) with open('コラージュ画像の保存先', 'rb') as f: file_bin = f.read() dht_img = { "favicon" : ("collage.jpg", file_bin), } res = requests.post(webhook, files=dht_img) await interaction.followup.send('Finish') @bot.slash_command(name="detect") async def help_slash(interaction: discord.Interaction): """motion detection camera""" await interaction.response.send_message(view=detect_btn()) bot.run("TOKEN")
0 件のコメント:
コメントを投稿