Spaces:
Running
Running
| import random | |
| import math | |
| import cv2 | |
| import numpy as np | |
| from PIL import Image, ImageDraw | |
| class Particle: | |
| def __init__(self, canvas_w, canvas_h, effect_type): | |
| self.canvas_w, self.canvas_h = canvas_w, canvas_h | |
| self.effect_type = effect_type | |
| self.reset() | |
| def reset(self): | |
| self.x = random.uniform(0, self.canvas_w) | |
| self.y = random.uniform(-50, self.canvas_h + 50) | |
| self.size = random.uniform(2, 6) | |
| self.speed = random.uniform(0.5, 2.5) | |
| self.wind = random.uniform(-0.5, 0.5) | |
| self.opacity = random.uniform(100, 255) | |
| self.rotation = random.uniform(0, 360) | |
| self.rot_speed = random.uniform(-3, 3) | |
| self.wobble = random.uniform(0, math.pi * 2) | |
| def update(self): | |
| self.y += self.speed | |
| self.x += self.wind + math.sin(self.wobble) * 0.3 | |
| self.wobble += 0.02 | |
| self.rotation += self.rot_speed | |
| if self.y > self.canvas_h + 50: | |
| self.reset() | |
| if self.x < -50: | |
| self.x = self.canvas_w + 50 | |
| if self.x > self.canvas_w + 50: | |
| self.x = -50 | |
| def draw_snowflake(draw, x, y, size, opacity): | |
| r = int(size * 3) | |
| color = (255, 255, 255, int(opacity)) | |
| draw.ellipse([x - r, y - r, x + r, y + r], fill=color) | |
| for angle in [0, math.pi / 3, math.pi * 2 / 3]: | |
| ex, ey = x + math.cos(angle) * r * 1.5, y + math.sin(angle) * r * 1.5 | |
| draw.line([x, y, ex, ey], fill=color, width=max(1, int(size))) | |
| def draw_leaf(draw, x, y, size, opacity, rotation): | |
| leaf_colors = [(180, 60, 30), (200, 120, 20), (220, 160, 40), (160, 80, 20)] | |
| color = random.choice(leaf_colors) + (int(opacity),) | |
| r = int(size * 5) | |
| img = Image.new('RGBA', (r * 2, r * 2), (0, 0, 0, 0)) | |
| leaf_draw = ImageDraw.Draw(img) | |
| leaf_draw.ellipse([r * 0.2, r * 0.5, r * 1.8, r * 1.5], fill=color) | |
| img = img.rotate(rotation, expand=False) | |
| draw._image.paste(img, (int(x - r), int(y - r)), img) | |
| def draw_raindrop(draw, x, y, size, opacity): | |
| color = (180, 200, 240, int(opacity)) | |
| r = int(size * 1.5) | |
| draw.ellipse([x - r, y - r * 3, x + r, y + r * 3], fill=color) | |
| def draw_sparkle(draw, x, y, size, opacity): | |
| gold = (255, 215, 0, int(opacity)) | |
| r = int(size * 2) | |
| draw.ellipse([x - r, y - r, x + r, y + r], fill=gold) | |
| for angle in range(0, 360, 45): | |
| rad = math.radians(angle) | |
| ex, ey = x + math.cos(rad) * r * 2, y + math.sin(rad) * r * 2 | |
| draw.line([x, y, ex, ey], fill=gold, width=max(1, int(size * 0.8))) | |
| def draw_dust(draw, x, y, size, opacity): | |
| color = (200, 190, 170, int(opacity)) | |
| r = int(size * 1.2) | |
| draw.ellipse([x - r, y - r, x + r, y + r], fill=color) | |
| def apply_effect(frame, particles, effect_type): | |
| img = Image.fromarray(cv2.cvtColor(frame, cv2.COLOR_BGR2RGBA)) | |
| overlay = Image.new('RGBA', img.size, (0, 0, 0, 0)) | |
| draw = ImageDraw.Draw(overlay) | |
| draw._image = overlay | |
| for p in particles: | |
| p.update() | |
| opacity = max(10, min(255, p.opacity * (1 - (p.y / (p.canvas_h + 50))))) | |
| if effect_type == "snow": draw_snowflake(draw, p.x, p.y, p.size, opacity) | |
| elif effect_type == "leaves": draw_leaf(draw, p.x, p.y, p.size, opacity, p.rotation) | |
| elif effect_type == "rain": draw_raindrop(draw, p.x, p.y, p.size, opacity) | |
| elif effect_type == "sparkle": draw_sparkle(draw, p.x, p.y, p.size, opacity) | |
| elif effect_type == "dust": draw_dust(draw, p.x, p.y, p.size, opacity) | |
| img = Image.alpha_composite(img, overlay) | |
| return cv2.cvtColor(np.array(img), cv2.COLOR_RGBA2BGR) | |
| EFFECTS = ["snow", "leaves", "rain", "sparkle", "dust", "flame", "heat", "oldfilm", "none"] |