From c720d564e7e85acfcf5aac58471fa9e20676029d Mon Sep 17 00:00:00 2001 From: Lilac-Rose Date: Fri, 9 Jan 2026 19:24:26 +0100 Subject: [PATCH] added canny edge detection to avatar command --- image/avatar.py | 78 +++++++++++++++++++++++++++++++++++++++++ stats/stats.db-journal | Bin 8720 -> 0 bytes 2 files changed, 78 insertions(+) delete mode 100644 stats/stats.db-journal diff --git a/image/avatar.py b/image/avatar.py index 46e9ed0..5eb0e47 100644 --- a/image/avatar.py +++ b/image/avatar.py @@ -9,6 +9,7 @@ import traceback import os import numpy as np from scipy.ndimage import uniform_filter +import cv2 class AvatarCommands(commands.Cog): def __init__(self, bot): @@ -126,6 +127,83 @@ class AvatarCommands(commands.Cog): out.seek(0) return out.getvalue() + # ---------------------------------------------------------------------- + # /avatar canny_edge + # ---------------------------------------------------------------------- + @avatar_group.command(name="canny_edge", description="Apply Canny edge detection to a user's avatar") + @app_commands.describe( + user="The user whose avatar to process (defaults to you)", + threshold1="Lower threshold for edge detection (default 100)", + threshold2="Upper threshold for edge detection (default 200)", + avatar_type="Choose between server or global avatar" + ) + @app_commands.choices( + avatar_type=[ + app_commands.Choice(name="Server Avatar", value="server"), + app_commands.Choice(name="Global Avatar", value="global") + ] + ) + async def avatar_canny_edge(self, interaction: discord.Interaction, threshold1: int = 100, threshold2: int = 200, user: discord.User = None, avatar_type: app_commands.Choice[str] = None): + await interaction.response.defer(thinking=True) + + user = user or interaction.user + + if threshold1 < 0 or threshold1 > 500: + await interaction.followup.send("threshold1 must be between 0 and 500.", ephemeral=True) + return + + if threshold2 < 0 or threshold2 > 500: + await interaction.followup.send("threshold2 must be between 0 and 500.", ephemeral=True) + return + + if threshold1 >= threshold2: + await interaction.followup.send("threshold1 must be less than threshold2.", ephemeral=True) + return + + try: + avatar = self.get_avatar_url(user, avatar_type) + avatar_url = avatar.with_format("png").with_size(512) + + if not self.session or self.session.closed: + self.session = aiohttp.ClientSession() + + async with self.session.get(str(avatar_url)) as resp: + resp.raise_for_status() + image_bytes = await resp.read() + + edge_bytes = await asyncio.to_thread(self._canny_edge_detection, image_bytes, threshold1, threshold2) + file = discord.File(io.BytesIO(edge_bytes), filename="canny_edges.png") + + await interaction.followup.send( + f"{user.display_name}'s avatar with Canny edge detection:", + file=file + ) + except Exception: + traceback.print_exc() + await interaction.followup.send("An error occurred while processing the image.", ephemeral=True) + + def _canny_edge_detection(self, image_bytes: bytes, threshold1: int, threshold2: int) -> bytes: + # Load image and convert to grayscale + img = Image.open(io.BytesIO(image_bytes)).convert("RGB") + img_array = np.array(img) + + # Convert RGB to BGR for OpenCV + img_bgr = cv2.cvtColor(img_array, cv2.COLOR_RGB2BGR) + + # Convert to grayscale + gray = cv2.cvtColor(img_bgr, cv2.COLOR_BGR2GRAY) + + # Apply Canny edge detection + edges = cv2.Canny(gray, threshold1, threshold2) + + # Convert back to PIL Image + edges_img = Image.fromarray(edges) + + out = io.BytesIO() + edges_img.save(out, format="PNG") + out.seek(0) + return out.getvalue() + # ---------------------------------------------------------------------- # /avatar explode # ---------------------------------------------------------------------- diff --git a/stats/stats.db-journal b/stats/stats.db-journal deleted file mode 100644 index b6ce88416a0928b24e4df2ab8841df3756d3db84..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 8720 zcmeI0zi-n(6vut}VdqDGF?p(VQijG#gjyjc7D6#qM3R=^N@PIR5xcD=|7hZKp#y`< z#2?UwjlB{>|BX&a2=SlLjkBFZx!9zg;aw8>p5OWIeLwGAl-#c$#asM!_)`#s+|_kq zk6nMWF1u{7548V)KyHPKmZ5;0U!VbfB+Bx0zd!=00AHX1pYMwMU)qE z8)$OwgI>StSk%Nv-q;}&KVm092nkOy7INh?CY_xN&6>n|g_*^U59a#W-Dr-7XP;MB zM?$G`BdlMpU9Rn}e5rn0d0V-uj-yxhgK!rJ00AHX1b_e#00KY&2;5B|td%8MQP2gV z3%tFqfyTbhcs*0YX^c^|G<@Is3QU`>6a;e&p=+v*SSOLfpp z4I6raOL4oWse5W4KUZJ04m%p&=Ef;cDx$ovAi;7C^MgOK+0SpC1k{UdoexFd;q7YJ zkP?XxVu=Q^>~q~QeV-hgK5vyciM%gEqCwc-fV(A5*3$1MwX{qsACkVq+vQLbC3$NL zT^z?!rwjX(P@gj-PAKQf&^bIIu4~%5Wy}(_G^f+~{vtSC1UB)h9-KxzlbYev&&v3_ zT&tllkrn4Rp4*@67CA|CjtoJO_a2Gk;^#wpTomPYZD~a&5l+f6F+`@M6m80byeKys zXb`7qQqX>~>&ykS!0B3W)?MP5P4=V`e#}Yo<|g{oolpHV>wcb_Ws)F215I|0aqCdq zZ}-?FUA3pB6BzjBc&