← back to Nova Recolor

batch_recolor.py

61 lines

import os, re, glob, sys
import numpy as np
import cv2

SRC = '/Users/macstudio3/Pictures/novasuede-ruby.jpg'
PICS = '/Users/macstudio3/Pictures'

def slugify(fname):
    stem = os.path.splitext(fname)[0].rstrip('. ')
    stem = re.sub(r'^Novasuede-\.?', '', stem, flags=re.I)
    parts = re.split(r'[-\s]*T3[A-Z0-9]+W', stem, maxsplit=1, flags=re.I)
    color = parts[0]
    color = re.sub(r'[\s.]+', '-', color.strip())
    color = re.sub(r'[^\w-]+', '', color)
    color = re.sub(r'-+', '-', color).strip('-').lower()
    return color

def center_crop(img, frac=0.7):
    h, w = img.shape[:2]
    ch, cw = int(h*frac), int(w*frac)
    y0, x0 = (h-ch)//2, (w-cw)//2
    return img[y0:y0+ch, x0:x0+cw]

def lab_reinhard(src_bgr, tgt_bgr):
    src_lab = cv2.cvtColor(src_bgr, cv2.COLOR_BGR2LAB).astype(np.float32)
    tgt_lab = cv2.cvtColor(tgt_bgr, cv2.COLOR_BGR2LAB).astype(np.float32)
    s = src_lab.reshape(-1, 3)
    t = tgt_lab.reshape(-1, 3)
    s_mean, s_std = s.mean(0), s.std(0)
    t_mean, t_std = t.mean(0), t.std(0)
    out = (src_lab - s_mean) * (t_std / (s_std + 1e-8)) + t_mean
    out = np.clip(out, 0, 255).astype(np.uint8)
    return cv2.cvtColor(out, cv2.COLOR_LAB2BGR)

src = cv2.imread(SRC, cv2.IMREAD_COLOR)
assert src is not None, f"could not read {SRC}"

targets = sorted(glob.glob(os.path.join(PICS, 'Novasuede*.jpg')))
print(f"found {len(targets)} targets")

results = []
for t_path in targets:
    fname = os.path.basename(t_path)
    color = slugify(fname)
    if not color:
        print(f"SKIP (no color): {fname}")
        continue
    tgt = cv2.imread(t_path, cv2.IMREAD_COLOR)
    if tgt is None:
        print(f"SKIP (unreadable): {fname}")
        continue
    tgt_c = center_crop(tgt, 0.7)
    out = lab_reinhard(src, tgt_c)
    out_path = os.path.join(PICS, f'novasuede-{color}.jpg')
    cv2.imwrite(out_path, out, [cv2.IMWRITE_JPEG_QUALITY, 92])
    tgt_lab_mean = cv2.cvtColor(tgt_c, cv2.COLOR_BGR2LAB).astype(np.float32).reshape(-1,3).mean(0)
    results.append((color, fname, tgt_lab_mean))
    print(f"OK  {fname:55s} -> novasuede-{color}.jpg   tgt LAB mean [{tgt_lab_mean[0]:5.1f} {tgt_lab_mean[1]:5.1f} {tgt_lab_mean[2]:5.1f}]")

print(f"\ndone: {len(results)} recolored")