← 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")