ColorGrading
Stamp a reference's color palette onto any latent, in one shot
- input
- reference
- LATENT
Color consistency is the silent killer of batch work. You generate twenty variations, one of them is the one, and now you want the other nineteen to share its palette - or you're stitching frames together and the color drifts with every hop. That's exactly the problem this node exists for. It takes a latent, measures the reference latent's color statistics, and rewrites the input's statistics to match. One node, one shot, done.
It's from yasser-baalla/comfyUI-SemanticImageFetch, a tiny three-node pack that nobody's ever really discovered. This node is the "dumb" half of the pack's color matching: a direct latent-to-latent transform, no sampler involved. Its sibling, ColorGradeSampler, does the same math during denoising instead of after - more on that below.
How it works
Read the source and it's a refreshingly small idea. For the reference latent it computes a mean and standard deviation per channel. Then, in adjust_latent, it normalizes each input image's channels (subtract its own per-channel mean, divide by its own std) and rescales them by the reference's std, shifting by the reference's mean. That's the classic mean/std color transfer trick - the same family as Reinhard color transfer - but done directly on the VAE latent instead of on pixels.
Two implementation details matter in practice. The reference stats get averaged across the whole reference batch, and the input is normalized per-image, so each image in your batch gets remapped to the reference's global palette. And because it runs on latents, it lands before the VAE decode: whatever color structure the VAE is about to render gets rebuilt with the reference's distribution. That's the whole trick.
The inputs that matter
Just two, and this is where beginners stumble:
- input - the latent you want recolored. The output of a VAE Encode, a KSampler, or whatever.
- reference - the latent whose color you're matching. Both are LATENTs, not images. The most common mistake is dropping a Load Image into these sockets - it won't connect. You VAE Encode a picture to get a reference latent first.
The output is a LATENT with the reference's color statistics, ready for VAE Decode or further latent processing.
Install
Same as the rest of the pack. ComfyUI Manager → search "SemanticImageFetch", or:
cd ComfyUI/custom_nodes
git clone https://github.com/yasser-baalla/comfyUI-SemanticImageFetch
Restart and you're done. No requirements.txt, no models to download, nothing heavy - it's one nodes.py using ComfyUI's own VAE latent format.
What it can't do
Set expectations now, because this is where people get annoyed. It matches global channel statistics, not lighting, not composition, not localized mood. Give it a reference with a very different luminance distribution and your output can look flat or washed-out - that's the mean/std tradeoff, not a bug. And since stats get averaged over the whole reference batch, mixing wildly different reference images in one batch muddies the result; feed it a single clean reference for predictable output.
It shines where the need is blunt: forcing a batch of variations to share one hero image's palette, or snapping drifting video frames back toward a consistent grade. That last use case is genuinely valuable - color drift between generated segments is a well-worn community pain point, and a stats transfer like this is a cheap, deterministic patch for it. Want the same match applied while sampling instead of after? ColorGradeSampler is the fancy sibling.
Inputs (2)
| Name | Type | Default | Description |
|---|---|---|---|
| input | LATENT | The latent to be color graded | |
| reference | LATENT | The reference latent |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| LATENT | LATENT | — |