
作りたいもの
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 件のコメント:
コメントを投稿