Files
aza/APP/fotoapp - Kopie/retouch.py

54 lines
1.5 KiB
Python
Raw Normal View History

2026-03-25 14:14:07 +01:00
"""Basic retouching tools: healing / inpainting and skin softening."""
from __future__ import annotations
from typing import Tuple
import numpy as np
from PIL import Image
def heal_spot(
img: Image.Image,
center: Tuple[int, int],
radius: int,
) -> Image.Image:
"""Remove blemish at *center* using OpenCV Telea inpainting."""
import cv2
arr = np.asarray(img.convert("RGB"))
bgr = cv2.cvtColor(arr, cv2.COLOR_RGB2BGR)
mask = np.zeros(arr.shape[:2], dtype=np.uint8)
cv2.circle(mask, center, radius, 255, -1)
result = cv2.inpaint(bgr, mask, inpaintRadius=radius * 2, flags=cv2.INPAINT_TELEA)
result = cv2.cvtColor(result, cv2.COLOR_BGR2RGB)
return Image.fromarray(result)
def soften_skin(
rgb_float01: np.ndarray,
mask: np.ndarray,
strength: float,
) -> np.ndarray:
"""Edge-preserving skin softening (bilateral filter) within *mask* area.
*strength*: 0..100. 0 = no effect.
*mask*: float01 (H, W) typically the person/face mask.
"""
if strength <= 0:
return rgb_float01
import cv2
img8 = np.clip(rgb_float01 * 255, 0, 255).astype(np.uint8)
d = max(3, int(strength / 10))
sigma_color = 30 + strength * 0.7
sigma_space = 30 + strength * 0.7
smoothed = cv2.bilateralFilter(img8, d, sigma_color, sigma_space)
smoothed_f = smoothed.astype(np.float32) / 255.0
alpha = np.clip(mask * min(strength / 100.0, 1.0), 0.0, 1.0)[..., None]
result = rgb_float01 * (1.0 - alpha) + smoothed_f * alpha
return np.clip(result, 0.0, 1.0).astype(np.float32)