import sys, os sys.path.insert(0, "services/recolor") import numpy as np import cv2 from PIL import Image from fabric_recolor.segmentation.birefnet import BirefnetMatteSegmenter from fabric_recolor.labcolor import rgb_to_lab from fabric_recolor.masks import (alpha_hysteresis, clean_binary, largest_component, fill_small_holes, _silhouette_bands) seg = BirefnetMatteSegmenter() seg._load() 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, seg.max_side / max(h0, w0)) image = Image.fromarray(rgb).resize((round(w0*scale), round(h0*scale)), Image.BILINEAR) matte = seg._matte(image) matte = alpha_hysteresis(matte, ramp_px=max(4, round(8*scale))) mask = clean_binary((matte >= seg.matte_threshold).astype(np.uint8), min_area_frac=0.002) mask = largest_component(mask) mask = fill_small_holes(mask, max_hole_frac=0.01) arr = np.asarray(image) lab = rgb_to_lab(arr) med = np.median(lab[mask>0], axis=0) cnts,_ = cv2.findContours(mask, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE) hull = np.zeros_like(mask) for c in cnts: cv2.fillPoly(hull, [cv2.convexHull(c)], 1) bg = (1-mask).astype(np.uint8) defect = (bg & (hull>0)).astype(np.uint8) outside = (bg & (hull==0)).astype(np.uint8) gray = cv2.cvtColor(arr, cv2.COLOR_RGB2GRAY).astype(np.float32) grad = np.hypot(cv2.Sobel(gray, cv2.CV_32F,1,0,ksize=3), cv2.Sobel(gray, cv2.CV_32F,0,1,ksize=3)) g_int = float(np.median(grad[mask>0])) k = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (13,13)) n, lab_c, stats, _ = cv2.connectedComponentsWithStats(defect, connectivity=8) print(f"== {name} maskcov={mask.mean():.4f} grad_int={g_int:.1f}") for i in range(1, n): area = stats[i, cv2.CC_STAT_AREA] if area < max(32, int(0.0003*mask.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])) print(f" defekt {i}: area={100*area/mask.size:.2f}% dE={d_e:.1f} d_out={d_out:.1f} rimpx={rim.sum()} grad_ratio={g/max(g_int,1):.2f} bbox=({stats[i,0]},{stats[i,1]},{stats[i,2]}x{stats[i,3]})")