Brand color check for AI images: Delta E in Python before publishing

Prompts cannot guarantee a brand hex. Measure the nearest palette color in a generated image with CIE76 Delta E and block misses. Code for Sume output.

5 min readSume
All posts

To check an AI image against a brand color, reduce the picture to a handful of dominant colors, convert both them and your hex to CIELAB, and take the smallest Delta E between the brand color and any dominant color. A value under roughly 10 is close for most uses and under 2 is hard to tell apart by eye; set your own bar and block anything above it. Naming a hex in a prompt only nudges a model, so measuring the result is the dependable control.

Run the check on the files you get back from Sume. The request has no color-management parameter, so the only way to know what you got is to look at the pixels.

What do the Delta E numbers mean?

CIE76 is the simple Euclidean distance in Lab space. It is crude for saturated colors but cheap and adequate for a gate.

Rough CIE76 Delta E reading, read 2026-10-04
Delta ETypical perceptionGate
0 to 2Hard to tell apartPass
2 to 10Close, noticeable side by sidePass for backgrounds, review for logos
10 to 50Clearly differentFail
50 and upA different colorFail

What is the script?

It uses Pillow to find five dominant colors, NumPy for the sRGB to Lab conversion with a D65 white point, and no other libraries.

import sys
import numpy as np
from PIL import Image

M = np.array([[.4124, .3576, .1805], [.2126, .7152, .0722], [.0193, .1192, .9505]])
W = np.array([.95047, 1.0, 1.08883])

def lab(rgb):
    c = np.asarray(rgb, dtype=float) / 255
    c = np.where(c > .04045, ((c + .055) / 1.055) ** 2.4, c / 12.92)
    t = (c @ M.T) / W
    f = np.where(t > .008856, np.cbrt(t), 7.787 * t + 16 / 116)
    return np.array([116 * f[1] - 16, 500 * (f[0] - f[1]), 200 * (f[1] - f[2])])

def nearest(path, hexcolor):
    img = Image.open(path).convert("RGB").resize((128, 128))
    pal = img.quantize(colors=5).getpalette()[:15]
    cols = [pal[i:i + 3] for i in range(0, 15, 3)]
    b = [int(hexcolor.lstrip("#")[i:i + 2], 16) for i in (0, 2, 4)]
    return min(np.linalg.norm(lab(c) - lab(b)) for c in cols)

if __name__ == "__main__":
    d = nearest(sys.argv[1], sys.argv[2])
    print(f"Delta E {d:.1f}", "pass" if d < 10 else "fail")

What should happen on a fail?

Regenerate with a larger n and keep the candidates that pass. Sume bills each completed image, so a rejected image still cost money; track the pass rate the way the approved-image cost post tracks pick rate. If the color matters on a flat area, a model that accepts reference images can be given a swatch as an input_references entry, and for exact hexes in logos or UI, composite the color yourself after generation.

What are the limits of this check?

Quantizing to five colors can merge a small brand mark into its surroundings, so crop to the area where the color must appear before measuring. Delta E also ignores the display: sRGB values in a file look different on a calibrated print proof. Treat the number as a gate for the digital file, not a proof of printed color.

Sources

Related posts

More in Use cases

All Use cases posts

Written by Sume