Initial commit: video effects processing system
Add S-expression based video effects pipeline with modular effect definitions, constructs, and recipe files. Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
This commit is contained in:
91
effects/zoom.py
Normal file
91
effects/zoom.py
Normal file
@@ -0,0 +1,91 @@
|
||||
# /// 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
|
||||
Reference in New Issue
Block a user