From 21dc32cedcdbcdcedda58c6f833e57a6dd1f301b Mon Sep 17 00:00:00 2001 From: 18ljones Date: Sun, 25 Sep 2022 19:57:46 -0500 Subject: [PATCH] Added $face command for bot to replace faces in picture with other face --- .gitignore | 2 ++ requirements.txt | 6 ++++ src/bot.py | 2 ++ src/faces.py | 31 ++++++++++++++++++ src/lib/{faces.py => faces_util.py} | 50 +++++++++++++++++++---------- 5 files changed, 74 insertions(+), 17 deletions(-) create mode 100644 requirements.txt create mode 100644 src/faces.py rename src/lib/{faces.py => faces_util.py} (77%) diff --git a/.gitignore b/.gitignore index 1776931..677ad60 100644 --- a/.gitignore +++ b/.gitignore @@ -178,3 +178,5 @@ $RECYCLE.BIN/ # End of https://www.toptal.com/developers/gitignore/api/windows,python !/src/lib/ +autogen_buildtime.py +*.png \ No newline at end of file diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..a068949 --- /dev/null +++ b/requirements.txt @@ -0,0 +1,6 @@ +opencv-python +numpy +pillow +pycord +python-dotenv +discord diff --git a/src/bot.py b/src/bot.py index fcef2b6..0acd123 100644 --- a/src/bot.py +++ b/src/bot.py @@ -5,6 +5,7 @@ from datetime import datetime, timezone import donut import soup +import faces import roll import config import asyncio @@ -47,6 +48,7 @@ async def on_message(message): await donut.on_message(message, config, client) await soup.on_message(message, client, config) await excuse.on_message(message) + await faces.on_message(message, client, config) if await roll.on_message(message): return diff --git a/src/faces.py b/src/faces.py new file mode 100644 index 0000000..1c3a0d9 --- /dev/null +++ b/src/faces.py @@ -0,0 +1,31 @@ +import lib.faces_util as faces_util +import os +import discord + +BYTES_IN_MEGABYTE = 1048576 + +allowable_attachment_types = ['image/png', 'image/jpeg'] + +async def on_message(message, client, conf): + if message.content.startswith("$face"): + if len(message.attachments) > 0: + for attachment in message.attachments: + # check if attachment is a picture and is smaller than 8mb + if attachment.content_type in allowable_attachment_types and attachment.size < (8 * BYTES_IN_MEGABYTE): + if attachment.proxy_url != '404': + try: + await attachment.save('attachment_picture.png', use_cached=True) + found, path = faces_util.get_face_replace('attachment_picture.png') + if found: + await message.channel.send(file=discord.File(path)) + else: + await message.channel.send('No face found :(') + if os.path.exists('face_detected.png'): + os.remove('face_detected.png') + except discord.HTTPException as error: + logging.exception(f'{datetime.now(timezone.utc)} Face on_message') + await message.channel.send('Could not download attachment :(') + except discord.NotFound as error: + logging.exception(f'{datetime.now(timezone.utc)} Face on_message') + await message.channel.send('Attachment not found :(') + \ No newline at end of file diff --git a/src/lib/faces.py b/src/lib/faces_util.py similarity index 77% rename from src/lib/faces.py rename to src/lib/faces_util.py index fe3e27e..88cebc8 100644 --- a/src/lib/faces.py +++ b/src/lib/faces_util.py @@ -1,11 +1,14 @@ import cv2 import numpy as np import math +import aiohttp +import os +import config as conf from PIL import Image -face_cascade = cv2.CascadeClassifier('opencv/face_detector.xml') -eye_cascade = cv2.CascadeClassifier('opencv/eye_detector.xml') -smile_cascade = cv2.CascadeClassifier('opencv/smile_detector.xml') +face_cascade = cv2.CascadeClassifier('lib/opencv/face_detector.xml') +eye_cascade = cv2.CascadeClassifier('lib/opencv/eye_detector.xml') +smile_cascade = cv2.CascadeClassifier('lib/opencv/smile_detector.xml') def load_image_rgba(path): og_image = Image.open(path) @@ -72,20 +75,33 @@ def replace_faces(gray, frame, replacement, replacement_dims): return found, frame -img = load_image_rgba('student_small.png') -# img = load_image_rgba('group.png') -student = np.array(img) - -face = load_image_rgba('face.png') -face_dims = [ - [43, 208, 430, 430], - [245, 125, 82, 82], - [98, 131, 87, 87] -] -gray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) -found,img = replace_faces(gray, img, face, face_dims) -cv2.imwrite("face_detected.png", img) -print('Successfully saved') +def get_face_replace(replacing_image): + face_replace = load_image_rgba(conf.face_picture) + attachment_pic = load_image_rgba(replacing_image) + gray = cv2.cvtColor(attachment_pic, cv2.COLOR_RGBA2GRAY) + found,img = replace_faces(gray, attachment_pic, face_replace, conf.face_dims) + + if found: + cv2.imwrite('face_detected.png', img) + return True, 'face_detected.png' + + return False, None + +if __name__ == '__main__': + img = load_image_rgba('student_small.png') + # img = load_image_rgba('group.png') + student = np.array(img) + + face = load_image_rgba('face.png') + face_dims = [ + [43, 208, 430, 430], + [245, 125, 82, 82], + [98, 131, 87, 87] + ] + gray = cv2.cvtColor(img, cv2.COLOR_RGBA2GRAY) + found,img = replace_faces(gray, img, face, face_dims) + cv2.imwrite("face_detected.png", img) + print('Successfully saved') # A video with faces applied for testing purposes # video_capture = cv2.VideoCapture(0)