# /// script # requires-python = ">=3.10" # dependencies = ["numpy", "opencv-python"] # /// """ @effect zoom @version 1.0.0 @author artdag @description Zooms into the center of the frame. Values > 1 zoom in (magnify), values < 1 zoom out (shrink with black borders). @param factor float @range 0.1 5 @default 1.0 Zoom factor. 1 = unchanged, 2 = 2x magnification, 0.5 = half size. @param center_x float @range 0 1 @default 0.5 Horizontal center of zoom (0 = left, 1 = right). @param center_y float @range 0 1 @default 0.5 Vertical center of zoom (0 = top, 1 = bottom). @example (effect zoom :factor 1.5) @example ;; Pulse zoom on bass (effect zoom :factor (bind bass :range [1.0 1.5] :transform sqrt)) @example ;; Zoom to corner (effect zoom :factor 2 :center_x 0 :center_y 0) """ import numpy as np import cv2 def process_frame(frame: np.ndarray, params: dict, state: dict) -> tuple: """ Zoom a video frame. Args: frame: Input frame as numpy array (H, W, 3) RGB uint8 params: Effect parameters - factor: zoom multiplier (default 1.0) - center_x: horizontal center 0-1 (default 0.5) - center_y: vertical center 0-1 (default 0.5) state: Persistent state dict (unused) Returns: Tuple of (processed_frame, new_state) """ factor = params.get("factor", 1.0) center_x = params.get("center_x", 0.5) center_y = params.get("center_y", 0.5) if factor is None or factor <= 0.01: factor = 1.0 if factor == 1.0: return frame, state h, w = frame.shape[:2] # Calculate crop region for zoom in new_w = int(w / factor) new_h = int(h / factor) if new_w <= 0 or new_h <= 0: return frame, state # Calculate crop offset based on center x_start = int((w - new_w) * center_x) y_start = int((h - new_h) * center_y) # Clamp to valid range x_start = max(0, min(x_start, w - new_w)) y_start = max(0, min(y_start, h - new_h)) # Crop and resize back to original dimensions cropped = frame[y_start:y_start + new_h, x_start:x_start + new_w] result = cv2.resize(cropped, (w, h), interpolation=cv2.INTER_LINEAR) return result, state