import sys, os sys.path.insert(0, "services/recolor") import numpy as np import cv2 from PIL import Image from fabric_recolor.labcolor import rgb_to_lab from fabric_recolor.masks import _silhouette_bands OUT = "tmp/masks_v9" for name in ["detail", "packshot_front", "hero"]: rgb = np.asarray(Image.open(f"data/media/assets/{ {'detail':'20/20282cb1bd8a58596050b99b9f29e079145a7bcc45ea46b8523ae2389801fbdc','packshot_front':'79/7987376a67865864247263e5028a83950a2fd900740bbe339fab1ff8e6b3fbb2','hero':'f0/f06282d9ba621d137d7c978cf931792ffbcb6b5c9764cf94e964f83ded13ddcf'}[name] }.png").convert("RGB"), dtype=np.uint8) # maska nowa (alfa) w skali pełnej; symulujemy skalę segmentacji 1600 h0, w0 = rgb.shape[:2] scale = min(1.0, 1600 / max(h0, w0)) im = np.asarray(Image.fromarray(rgb).resize((round(w0*scale), round(h0*scale)), Image.BILINEAR)) a = np.asarray(Image.open(f"{OUT}/{name}.mask.png").convert("L"), dtype=np.float32)/255.0 a_small = cv2.resize(a, (im.shape[1], im.shape[0]), interpolation=cv2.INTER_LINEAR) mb = (a_small > 0.5).astype(np.uint8) # aproksymacja maski po wypełnieniu # reprodukuj defekty PRZED wypełnieniem: użyj starego sidecara stem = {'detail':'data/media/assets/20/20282cb1bd8a58596050b99b9f29e079145a7bcc45ea46b8523ae2389801fbdc', 'packshot_front':'data/media/assets/79/7987376a67865864247263e5028a83950a2fd900740bbe339fab1ff8e6b3fbb2', 'hero':'data/media/assets/f0/f06282d9ba621d137d7c978cf931792ffbcb6b5c9764cf94e964f83ded13ddcf'}[name] old = np.asarray(Image.open(stem+".mask.png").convert("L"), dtype=np.float32)/255.0 old_small = cv2.resize(old, (im.shape[1], im.shape[0]), interpolation=cv2.INTER_LINEAR) mb_old = (old_small > 0.5).astype(np.uint8) lab = rgb_to_lab(im) med = np.median(lab[mb_old>0], axis=0) cnts,_ = cv2.findContours(mb_old, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) hull = np.zeros_like(mb_old) for c in cnts: cv2.fillPoly(hull, [cv2.convexHull(c)], 1) bg = (1-mb_old).astype(np.uint8) defect = (bg & (hull>0)).astype(np.uint8) outside = (bg & (hull==0)).astype(np.uint8) k = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13,13)) n, lab_c, stats, _ = cv2.connectedComponentsWithStats(defect, connectivity=8) print(f"== {name} (skala seg {im.shape[1]}x{im.shape[0]})") for i in range(1, n): area = stats[i, cv2.CC_STAT_AREA] if area < max(32, int(0.0003*mb_old.size)): continue comp = lab_c == i d_e = float(np.linalg.norm(lab[comp].mean(axis=0)-med)) rim = cv2.dilate(comp.astype(np.uint8), k).astype(bool) & (outside>0) d_out = float(np.linalg.norm(lab[comp].mean(axis=0)-lab[rim].mean(axis=0))) if rim.sum()>=16 else -1 dec = "FILL" if (d_e<=28 and (rim.sum()<16 or d_out>d_e)) else "skip" print(f" defekt {i}: area={100*area/mb_old.size:.2f}% dE={d_e:.1f} d_out={d_out:.1f} rimpx={rim.sum()} -> {dec}")