#!/usr/bin/env python3
"""Cut out 9 items from the 3x3 white-bg grid image, save PNGs with alpha."""
import numpy as np
from PIL import Image, ImageFilter
from collections import deque

SRC = '/root/.hermes/image_cache/img_5692f1c30ecb.jpg'
OUT = '/root/.hermes/image_cache/zrd_cutouts/'

im = Image.open(SRC).convert('RGB')
W, H = im.size
arr = np.array(im).astype(np.int16)

rows = [(181, 416), (499, 765), (850, 1098)]
cols = [(19, 321), (357, 667), (702, 1003)]

def flood_bg(mask):
    """mask: bool array, True = near-white candidate. Return bg bool (connected to border)."""
    h, w = mask.shape
    bg = np.zeros((h, w), dtype=bool)
    dq = deque()
    for x in range(w):
        if mask[0, x]: bg[0, x] = True; dq.append((0, x))
        if mask[h-1, x]: bg[h-1, x] = True; dq.append((h-1, x))
    for y in range(h):
        if mask[y, 0]: bg[y, 0] = True; dq.append((y, 0))
        if mask[y, w-1]: bg[y, w-1] = True; dq.append((y, w-1))
    while dq:
        y, x = dq.popleft()
        for dy, dx in ((1,0),(-1,0),(0,1),(0,-1)):
            ny, nx = y+dy, x+dx
            if 0 <= ny < h and 0 <= nx < w and mask[ny, nx] and not bg[ny, nx]:
                bg[ny, nx] = True
                dq.append((ny, nx))
    return bg

for ri, (y0, y1) in enumerate(rows):
    for ci, (x0, x1) in enumerate(cols):
        pad = 14
        bx0, by0 = max(0, x0-pad), max(0, y0-pad)
        bx1, by1 = min(W, x1+pad), min(H, y1+pad)
        cell = im.crop((bx0, by0, bx1, by1))
        c = np.array(cell).astype(np.int16)
        # near-white background candidate: all channels bright & low saturation-ish
        white = (c[:,:,0] > 225) & (c[:,:,1] > 225) & (c[:,:,2] > 225) & (np.abs(c[:,:,0]-c[:,:,2]) < 30)
        bg = flood_bg(white)
        # shadows: soften pixels near bg edge (grayish) — treat mild gray connected to bg as bg too
        gray = (np.abs(c[:,:,0]-c[:,:,1]) < 12) & (np.abs(c[:,:,1]-c[:,:,2]) < 12) & (c.mean(axis=2) > 150)
        bg2 = flood_bg(white | gray)
        alpha = (255 - bg2.astype(np.uint8)*255).astype(np.uint8)
        # feather edge: blur alpha a touch
        a = Image.fromarray(alpha, 'L')
        a = a.filter(ImageFilter.GaussianBlur(1.2))
        # also trim near-white fringe on opaque edges: shift alpha slightly by eroding? keep simple
        rgba = cell.convert('RGBA')
        rgba.putalpha(a)
        # autocrop to content bbox with small margin
        bbox = rgba.getbbox()
        if bbox:
            xa, ya, xb, yb = bbox
            m = 6
            xa, ya = max(0, xa-m), max(0, ya-m)
            xb, yb = min(rgba.width, xb+m), min(rgba.height, yb+m)
            rgba = rgba.crop((xa, ya, xb, yb))
        name = f'item_r{ri+1}c{ci+1}.png'
        rgba.save(OUT + name)
        # stats
        op = np.array(rgba)[:,:,3]
        print(name, rgba.size, 'opaque%%=%.1f' % ((op>200).mean()*100))
print('done')
