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