from pathlib import Path
import cv2, numpy as np
from PIL import Image, ImageDraw, ImageFilter

src = Path('/Users/bot1/.hermes/profiles/designer3/image_cache/img_fe2de1daf114.jpg')
outdir = Path('/Users/bot1/Volumes/root_for_ai/AI工作区/国博_产品_国宝艺展毛绒盲盒_20260620_2052/work/状元及第_用户参考保真重做_20260620')
outdir.mkdir(parents=True, exist_ok=True)
img = cv2.cvtColor(cv2.imread(str(src)), cv2.COLOR_BGR2RGB)
x1, y1, x2, y2 = 1650, 700, 4100, 3250
crop = img[y1:y2, x1:x2].copy()
h, w = crop.shape[:2]
mask = np.full((h, w), cv2.GC_PR_BGD, np.uint8)
mask[:20, :] = cv2.GC_BGD
mask[-20:, :] = cv2.GC_BGD
mask[:, :20] = cv2.GC_BGD
mask[:, -20:] = cv2.GC_BGD
r, g, b = crop[:, :, 0], crop[:, :, 1], crop[:, :, 2]
hsv = cv2.cvtColor(crop, cv2.COLOR_RGB2HSV)
H, S, V = hsv[:, :, 0], hsv[:, :, 1], hsv[:, :, 2]
green1 = np.logical_and.reduce((H > 65, H < 100, S > 45, V > 35, r < 110))
green2 = np.logical_and.reduce((g.astype(int) > r.astype(int) + 25, g.astype(int) > b.astype(int) + 5, r < 95))
green = np.logical_or(green1, green2)
mask[green] = cv2.GC_BGD
fg1 = np.logical_and.reduce((r > 90, g > 65, b < 190, (((r.astype(int) + g.astype(int)) // 2 - b.astype(int)) > 18)))
fg2 = np.logical_and.reduce((r > 115, g > 45, b < 130, r.astype(int) > b.astype(int) + 25))
fg = np.logical_or(fg1, fg2)
area = np.zeros((h, w), bool)
area[40:2450, 40:2350] = True
mask[np.logical_and(fg, area)] = cv2.GC_PR_FGD
strong1 = np.logical_and.reduce((r > 130, g > 80, b < 145, (((r.astype(int) + g.astype(int)) // 2 - b.astype(int)) > 35)))
strong2 = np.logical_and.reduce((r > 150, g > 130, b < 145, r > 80))
strong = np.logical_or(strong1, strong2)
mask[np.logical_and(strong, area)] = cv2.GC_FGD
bgdModel = np.zeros((1, 65), np.float64)
fgdModel = np.zeros((1, 65), np.float64)
cv2.grabCut(crop, mask, None, bgdModel, fgdModel, 7, cv2.GC_INIT_WITH_MASK)
alpha = np.where(np.logical_or(mask == cv2.GC_FGD, mask == cv2.GC_PR_FGD), 255, 0).astype('uint8')
# Hard-remove the saturated green cloth after GrabCut so the ring hole and the open area above the plush stay transparent.
alpha[green] = 0
residual_green = np.logical_and.reduce((H > 55, H < 105, S > 35, r < 135, g.astype(int) > r.astype(int) + 8))
alpha[residual_green] = 0
kernel = np.ones((3, 3), np.uint8)
alpha = cv2.morphologyEx(alpha, cv2.MORPH_OPEN, kernel, iterations=1)
alpha = cv2.morphologyEx(alpha, cv2.MORPH_CLOSE, kernel, iterations=2)
alpha[green] = 0
alpha[residual_green] = 0
num, labels, stats, cent = cv2.connectedComponentsWithStats((alpha > 0).astype('uint8'), 8)
keep = np.zeros_like(alpha)
areas = []
for i in range(1, num):
    area_i = stats[i, cv2.CC_STAT_AREA]
    if area_i > 500:
        areas.append((int(area_i), int(i), stats[i].tolist()))
areas = sorted(areas, reverse=True)[:5]
for _, i, _ in areas:
    keep[labels == i] = 255
alpha = keep
alpha_pil = Image.fromarray(alpha).filter(ImageFilter.GaussianBlur(0.8))
bb = alpha_pil.getbbox()
rgba = Image.fromarray(crop).crop(bb).convert('RGBA')
alpha_c = alpha_pil.crop(bb)
rgba.putalpha(alpha_c)
path = outdir / '状元及第_用户参考实物抠图_grabcut_含浅黄圆环.png'
rgba.save(path)
white = Image.new('RGB', rgba.size, 'white')
white.paste(rgba, mask=rgba.getchannel('A'))
white_path = outdir / '状元及第_用户参考实物抠图_grabcut_白底预览.jpg'
white.save(white_path, quality=95)
orig = Image.fromarray(crop).crop(bb)
prev = Image.new('RGB', (rgba.width * 2 + 30, rgba.height), 'white')
prev.paste(orig, (0, 0))
prev.paste(white, (rgba.width + 30, 0))
ImageDraw.Draw(prev).text((10, 10), 'left source crop / right grabcut cutout', fill=(0, 0, 0))
prev_path = outdir / '状元及第_用户参考抠图_grabcut_对照预览.jpg'
prev.save(prev_path, quality=95)
print('components kept', areas)
print('CUT', path, rgba.size)
print('PREVIEW', prev_path)
