File size: 1,292 Bytes
41e0dae
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
import cv2
import numpy as np

def _read_png_rgba(path):
    png = cv2.imread(path, cv2.IMREAD_UNCHANGED)
    if png is None or png.shape[2] != 4:
        raise ValueError("Hairstyle PNG must be RGBA with transparency.")
    return png

def auto_align(png_rgba, mask, landmarks=None):
    mh, mw = mask.shape[:2]
    ys, xs = np.where(mask > 0)
    if len(xs) == 0 or len(ys) == 0:
        return cv2.resize(png_rgba, (mw, mh))
    x0, x1 = xs.min(), xs.max()
    y0, y1 = ys.min(), ys.max()
    tw, th = int((x1 - x0) * 1.1), int((y1 - y0) * 0.7)
    tw = max(1, min(tw, mw))
    th = max(1, min(th, mh))
    aligned = cv2.resize(png_rgba, (tw, th))
    canvas = np.zeros((mh, mw, 4), dtype=np.uint8)
    y = max(0, y0 - int(0.25 * th))
    x = max(0, x0 - int(0.05 * tw))
    y2, x2 = min(mh, y + th), min(mw, x + tw)
    canvas[y:y2, x:x2] = aligned[:(y2 - y), :(x2 - x)]
    return canvas

def _alpha_blend(base_bgr, overlay_rgba):
    bgr = base_bgr.copy()
    alpha = overlay_rgba[:, :, 3:4] / 255.0
    rgb = overlay_rgba[:, :, :3]
    return (alpha * rgb + (1 - alpha) * bgr).astype(np.uint8)

def apply_hairstyle(img_bgr, style_path, mask, landmarks=None):
    png = _read_png_rgba(style_path)
    aligned = auto_align(png, mask, landmarks)
    return _alpha_blend(img_bgr, aligned)