"""
Content-aware image resize using seam carving.
Uses the seam-carving library (li-plus) with optional face protection via MediaPipe.
Args:
sys.argv[1]: input image path
sys.argv[2]: output image path
sys.argv[3]: JSON settings string with keys:
- width (int, optional): target width
- height (int, optional): target height
- protectFaces (bool, optional): enable face detection for protection mask
"""
import json
import sys
def emit_progress(percent, stage):
"""Emit structured progress to stderr for bridge.ts to capture."""
print(json.dumps({"progress": percent, "stage": stage}), file=sys.stderr, flush=True)
def build_face_mask(img_array):
"""Detect faces with MediaPipe and return a boolean keep_mask."""
import numpy as np
try:
import mediapipe as mp
except ImportError:
emit_progress(20, "MediaPipe not available, skipping face protection")
return None
h, w = img_array.shape[:2]
mask = np.zeros((h, w), dtype=bool)
face_detection = mp.solutions.face_detection
detector = face_detection.FaceDetection(model_selection=1, min_detection_confidence=0.5)
try:
results = detector.process(img_array)
if not results.detections:
emit_progress(20, "No faces detected")
return None
for detection in results.detections:
bbox = detection.location_data.relative_bounding_box
x = int(bbox.xmin * w)
y = int(bbox.ymin * h)
bw = int(bbox.width * w)
bh = int(bbox.height * h)
# Add 20% padding around face
pad_x = int(bw * 0.2)
pad_y = int(bh * 0.2)
x1 = max(0, x - pad_x)
y1 = max(0, y - pad_y)
x2 = min(w, x + bw + pad_x)
y2 = min(h, y + bh + pad_y)
mask[y1:y2, x1:x2] = True
emit_progress(20, f"Detected {len(results.detections)} face(s)")
return mask
finally:
detector.close()
def main():
if len(sys.argv) < 4:
print(json.dumps({"success": False, "error": "Usage: seam_carve.py