← back to Designerwallcoverings

scripts/artmura-onboard/extract_colors.py

56 lines

#!/usr/bin/env python3
"""Extract dominant color (hex + hue + coarse bucket) from each Artmura swatch image.
Writes data/artmura-colors.json {sku: {hex, hue, bucket}} for the site to merge in."""
import json, os, glob, colorsys
from collections import Counter
from PIL import Image

HERE = os.path.dirname(os.path.abspath(__file__))
IMG = os.path.join(HERE, "..", "..", ".newwall-ref", "artmura", "images")
PKG = json.load(open(os.path.join(HERE, "data", "artmura.json")))

def dominant(path):
    im = Image.open(path).convert("RGB").resize((64, 64))
    # quantize to 16 colors, take the most common that isn't near-pure-white background noise
    q = im.quantize(colors=16).convert("RGB")
    cnt = Counter(q.getdata())
    ranked = cnt.most_common()
    # prefer the most saturated/among top to avoid flat near-white winning on tonal swatches
    def score(item):
        (r, g, b), n = item
        h, s, v = colorsys.rgb_to_hsv(r/255, g/255, b/255)
        # weight count but boost saturated colors so the swatch's character shows
        return n * (0.5 + s)
    (r, g, b), _ = max(ranked[:6], key=score)
    return r, g, b

def bucket(h, s, v):
    if v < 0.18: return "black"
    if s < 0.12 and v > 0.85: return "white"
    if s < 0.14: return "grey"
    deg = h * 360
    if deg < 16 or deg >= 345: return "red"
    if deg < 45: return "orange" if v > 0.5 else "brown"
    if deg < 70: return "gold"
    if deg < 160: return "green"
    if deg < 200: return "teal"
    if deg < 255: return "blue"
    if deg < 290: return "purple"
    return "pink"

out = {}
for p in PKG["products"]:
    sku = p["mfr_sku"]
    cand = sorted(glob.glob(os.path.join(IMG, f"{sku}-1.*")) or glob.glob(os.path.join(IMG, f"{sku}-*.*")))
    if not cand:
        continue
    r, g, b = dominant(cand[0])
    h, s, v = colorsys.rgb_to_hsv(r/255, g/255, b/255)
    out[sku] = {"hex": f"#{r:02x}{g:02x}{b:02x}", "hue": round(h*360, 1),
                "sat": round(s, 3), "val": round(v, 3), "bucket": bucket(h, s, v)}

open(os.path.join(HERE, "data", "artmura-colors.json"), "w").write(json.dumps(out, indent=1))
from collections import Counter as C
print(f"extracted {len(out)} colors")
print("buckets:", dict(C(v["bucket"] for v in out.values()).most_common()))