# -*- coding: utf-8 -*-
"""Đo màu nền gỗ theo MẶT NẠ THỰC TẾ (không phụ thuộc toạ độ cắt tay) — dự án B.
- Mẫu (đã lên màu): pixel GỖ = đỏ/nâu: a* > 6 và L* trong [20, 75]  (loại băng keo vàng nhạt, nền sáng)
- Gỗ mộc: pixel GỖ = trung tính xám: |a*| < 6 và b* < 8 và L* trong [45, 92]  (loại carton b* cao, thanh gỗ đậm L* < 45)
Xuất: JSON + ảnh mặt nạ để soi + percentile (dải sáng–tối của vân)."""
import io, json, os
from datetime import datetime
import numpy as np
from PIL import Image

B = r'C:\Claw 2\Nghien cuu\Du-an-B-He-mau-Stain-Glaze'
OUT = os.path.join(B, 'anh_lo09_nen_mau')
os.makedirs(OUT, exist_ok=True)
MAU = r'C:\Users\admin\AppData\Local\hermes\cache\images\img_d3d125fe9364.jpg'
MOC = r'C:\Users\admin\AppData\Local\hermes\cache\images\img_94ae2ffb4ecc.jpg'


def to_lab_arr(rgb):                      # rgb: HxWx3 uint8
    a = rgb.astype(float) / 255.0
    a = np.where(a <= 0.04045, a / 12.92, ((a + 0.055) / 1.055) ** 2.4)
    M = np.array([[0.4124, 0.3576, 0.1805], [0.2126, 0.7152, 0.0722], [0.0193, 0.1192, 0.9505]])
    xyz = a @ M.T / np.array([0.95047, 1.0, 1.08883])
    f = np.where(xyz > 0.008856, np.cbrt(xyz), 7.787 * xyz + 16 / 116)
    L = 116 * f[..., 1] - 16
    A = 500 * (f[..., 0] - f[..., 1])
    Bb = 200 * (f[..., 1] - f[..., 2])
    return np.stack([L, A, Bb], -1)


def lab_to_rgb_srgb(lab):
    L, A, Bb = lab
    fy = (L + 16) / 116
    fx = fy + A / 500
    fz = fy - Bb / 200
    xyz = np.array([fx ** 3 if fx ** 3 > 0.008856 else (116 * fx - 16) / 903.3,
                    ((L + 16) / 116) ** 3 if L > 8 else L / 903.3,
                    fz ** 3 if fz ** 3 > 0.008856 else (116 * fz - 16) / 903.3]) * np.array([0.95047, 1.0, 1.08883])
    M = np.array([[3.2406, -1.5372, -0.4986], [-0.9689, 1.8758, 0.0415], [0.0557, -0.2040, 1.0570]])
    r = M @ xyz
    r = np.where(r <= 0.0031308, 12.92 * r, 1.055 * np.clip(r, 0, None) ** (1 / 2.4) - 0.055)
    return tuple(int(round(v * 255)) for v in np.clip(r, 0, 1))


def hexs(rgb):
    return '#%02X%02X%02X' % tuple(int(v) for v in rgb)


def phan_tich(ten, path, mask_fn, mo_ta):
    im = Image.open(path).convert('RGB')
    arr = np.asarray(im)
    lab = to_lab_arr(arr)
    m = mask_fn(lab)
    px = lab[m]
    rgb = arr[m]
    if len(px) < 500:
        print('⚠ %s: chỉ %d pixel khớp mặt nạ' % (ten, len(px)))
    med = np.median(px, axis=0)
    p10, p90 = np.percentile(px[:, 0], [10, 90])
    mr = np.median(rgb, axis=0)
    # lưu ảnh mặt nạ (thu nhỏ) để soi lại
    mm = (m.astype(np.uint8) * 255)
    Image.fromarray(mm).resize((im.width // 3, im.height // 3)).save(os.path.join(OUT, 'matna_%s.png' % ten))
    kq = dict(ten=ten, anh=os.path.basename(path), mat_na=mo_ta, so_pixel=int(m.sum()),
              ty_le=round(float(m.mean()) * 100, 1),
              hex=hexs(mr), L=round(float(med[0]), 1), a=round(float(med[1]), 1), b=round(float(med[2]), 1),
              L_p10=round(float(p10), 1), L_p90=round(float(p90), 1),
              rgb=[int(v) for v in mr])
    print('  %-8s %s  L*%5.1f (P10 %4.1f · P90 %4.1f)  a*%+6.1f  b*%+6.1f  · %d px (%.0f%% ảnh)'
          % (ten, kq['hex'], kq['L'], kq['L_p10'], kq['L_p90'], kq['a'], kq['b'], kq['so_pixel'], kq['ty_le']))
    return kq


print('=== ĐO THEO MẶT NẠ ===')
kq_mau = phan_tich('MẪU', MAU,
                   lambda lab: (lab[..., 1] > 6) & (lab[..., 0] > 20) & (lab[..., 0] < 75),
                   'pixel gỗ đã lên màu (a*>6, 20<L*<75)')
kq_moc = phan_tich('MỘC', MOC,
                   lambda lab: (np.abs(lab[..., 1]) < 6) & (lab[..., 2] < 8) & (lab[..., 0] > 45) & (lab[..., 0] < 92),
                   'pixel gỗ mộc trung tính (|a*|<6, b*<8, 45<L*<92)')

res = {'do_luc': datetime.now().strftime('%d/%m/%Y %H:%M'), 'mau': kq_mau, 'moc': kq_moc,
       'phuong_phap': 'trung vị pixel trong mặt nạ màu, sRGB→CIELAB D65. Không quy chiếu thẻ trắng ⇒ '
                      'dùng để SO SÁNH trong từng ảnh; sai lệch tuyệt đối có thể vài đơn vị L*.',
       'delta': {'dL': round(kq_mau['L'] - kq_moc['L'], 1),
                 'da': round(kq_mau['a'] - kq_moc['a'], 1),
                 'db': round(kq_mau['b'] - kq_moc['b'], 1)}}
print('\n  Δ (mẫu − mộc): L* %+.1f  a* %+.1f  b* %+.1f' % (res['delta']['dL'], res['delta']['da'], res['delta']['db']))
print('  dải vân mẫu: L* %.1f–%.1f (độ sâu màu)' % (kq_mau['L_p10'], kq_mau['L_p90']))

p = os.path.join(OUT, '_do_mau_nen_v2_%s.json' % datetime.now().strftime('%Y%m%d'))
json.dump(res, io.open(p, 'w', encoding='utf-8'), ensure_ascii=False, indent=1)
print('\nlưu:', p)
