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 OUT = "tmp/masks_v9" paths = {'detail':'data/media/assets/20/20282cb1bd8a58596050b99b9f29e079145a7bcc45ea46b8523ae2389801fbdc', 'packshot_front':'data/media/assets/79/7987376a67865864247263e5028a83950a2fd900740bbe339fab1ff8e6b3fbb2', 'hero':'data/media/assets/f0/f06282d9ba621d137d7c978cf931792ffbcb6b5c9764cf94e964f83ded13ddcf'} for name, stem in paths.items(): rgb = np.asarray(Image.open(stem+".png").convert("RGB"), dtype=np.uint8) 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)) 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) gray = cv2.cvtColor(im, cv2.COLOR_RGB2GRAY).astype(np.float32) gx = cv2.Sobel(gray, cv2.CV_32F, 1, 0, ksize=3); gy = cv2.Sobel(gray, cv2.CV_32F, 0, 1, ksize=3) grad = np.hypot(gx, gy) g_int = np.median(grad[mb_old>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} grad_int={g_int:.2f}") 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 g = float(np.median(grad[comp])) g_rim = float(np.median(grad[rim])) if rim.sum()>=16 else -1 print(f" defekt {i}: area={100*area/mb_old.size:.2f}% dE={d_e:.1f} d_out={d_out:.1f} grad={g:.1f} grad_rim={g_rim:.1f} grad_ratio={g/max(g_int,1):.2f}")