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