# /// script # requires-python = ">=3.10" # dependencies = ["numpy", "opencv-python"] # /// """ @effect neon_glow @version 1.0.0 @author artdag @description Neon edge glow effect. Detects edges and applies a glowing colored outline. Great for cyberpunk/synthwave aesthetics synced to music. @param glow_radius float @range 0 50 @default 15 Blur radius for the glow. Bind to bass for pulsing glow. @param glow_intensity float @range 0.5 5 @default 2.0 Brightness multiplier for the glow. @param edge_low float @range 10 200 @default 50 Lower threshold for edge detection. @param edge_high float @range 50 300 @default 150 Upper threshold for edge detection. @param color_r int @range 0 255 @default 0 Red component of glow color. @param color_g int @range 0 255 @default 255 Green component of glow color. @param color_b int @range 0 255 @default 255 Blue component of glow color. @param background float @range 0 1 @default 0.3 How much of the original image shows through (0 = glow only). @example (effect neon_glow :glow_radius 20 :color_r 255 :color_g 0 :color_b 255) @example ;; Pulsing cyan glow on bass (effect neon_glow :glow_radius (bind bass :range [5 30] :transform sqrt)) """ import numpy as np import cv2 def process_frame(frame: np.ndarray, params: dict, state: dict) -> tuple: """ Apply neon glow effect to a video frame. Args: frame: Input frame as numpy array (H, W, 3) RGB uint8 params: Effect parameters - glow_radius: blur radius (default 15) - glow_intensity: brightness (default 2.0) - edge_low: canny low threshold (default 50) - edge_high: canny high threshold (default 150) - color_r/g/b: glow color (default cyan 0,255,255) - background: original visibility (default 0.3) state: Persistent state dict (unused) Returns: Tuple of (processed_frame, new_state) """ glow_radius = int(params.get("glow_radius", 15)) glow_intensity = params.get("glow_intensity", 2.0) edge_low = int(params.get("edge_low", 50)) edge_high = int(params.get("edge_high", 150)) color_r = int(params.get("color_r", 0)) color_g = int(params.get("color_g", 255)) color_b = int(params.get("color_b", 255)) background = params.get("background", 0.3) h, w = frame.shape[:2] color = np.array([color_r, color_g, color_b], dtype=np.float32) # Edge detection gray = cv2.cvtColor(frame, cv2.COLOR_RGB2GRAY) blurred = cv2.GaussianBlur(gray, (5, 5), 0) edges = cv2.Canny(blurred, edge_low, edge_high) # Create colored edge image glow_base = np.zeros((h, w, 3), dtype=np.float32) for c in range(3): glow_base[:, :, c] = edges.astype(np.float32) * (color[c] / 255.0) # Apply blur for glow if glow_radius > 0: ksize = glow_radius * 2 + 1 glow = cv2.GaussianBlur(glow_base, (ksize, ksize), 0) else: glow = glow_base # Intensify glow = glow * glow_intensity # Add sharp edges on top edge_layer = np.zeros((h, w, 3), dtype=np.float32) for c in range(3): edge_layer[:, :, c] = edges.astype(np.float32) * (color[c] / 255.0) * 255 glow = np.maximum(glow, edge_layer) # Blend with original if background > 0: a = frame.astype(np.float32) / 255.0 * background b = glow / 255.0 result = (1 - (1 - a) * (1 - b)) * 255 # Screen blend else: result = glow return np.clip(result, 0, 255).astype(np.uint8), state