Normalize Image Colors
A training-tool that reads like a photo filter — don't be fooled
- images
- images
The display name is doing a lot of work here. "Normalize Image Colors" sounds like a friendly auto-fix for washed-out renders - like it'll pop the contrast and rescue your muddy output. It won't. Normalize Image Colors is a statistical normalization node: it subtracts a mean from every pixel and divides by a standard deviation. That's it. It's a training-time preprocessing tool that happens to live in the image/color category, and using it as a beauty filter is how people get images that look like they've been through a blender.
What it actually does
The math is pure tensor work, no clamping, no cleverness:
image = (image - mean) / std
Three inputs: images (an IMAGE), mean (FLOAT, default 0.5, range 0–1), and std (FLOAT, default 0.5, range 0.001–1). One IMAGE output. With the defaults, every pixel in [0,1] lands in [-1,1] - that's the classic "center and scale" move that reshapes a dataset's value distribution to what a trainer or a model's input layer expects.
That's the tell. This node lives in ComfyUI's dataset/training pipeline (comfy_extras/nodes_dataset.py), added in late 2025 with the training nodes. Its job is to normalize images before they're used for training, so the batch has a predictable mean and spread. The default 0.5/0.5 is the sensible starting point for images whose data you haven't measured; if you're being rigorous, you'd set mean and std to the actual statistics of your dataset.
Because it's pure tensor math, it handles an entire batch - or a whole video - in one pass, no per-frame looping. Fast, deterministic, no model files.
Where people get burned
There's no clamping. Set std to 0.01 and your pixels fly out to ±50. Preview that and you get pure white soup with black specks; it looks catastrophically broken, because visually it is. The node doesn't care - it's feeding a trainer, not a screen.
It will wreck a generation graph. If you drop this before a VAE encode or an img2img pass, the model gets values way outside the [0,1] range it was trained on, and the result is garbage. Unlike ImageInvert, which keeps everything in range, this node intentionally moves values to a different distribution. If you really must use it in an inference workflow, you need a matching node with reciprocal mean/std on the other side to undo it - and even then you'll see float rounding on the way back.
It does not fix colors. No histogram stretching, no white balance, no contrast curve. If your render came out flat or muddy, this is the wrong node entirely - reach for brightness/contrast or a proper color-matching node instead. The name is aspirational; the behavior is statistics.
When to actually use it
Preparing images for LoRA or fine-tuning training, where you want inputs centered around a target mean. Matching the normalization a specific model was trained with, if you know it. Building a dataset pipeline where every image must have the same value distribution before it hits a trainer. In all three, you're setting mean and std deliberately, not leaving them at default because they looked fine.
Where it lives
Ships with ComfyUI core - no install, no Manager, no model files. You'll find it under Image → Color (or "normalize" in search). It's a genuinely useful node, but only inside the pipeline it was built for. Outside that, the nicest thing you can say about it is that it's a very precise way to ruin a preview.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| images | IMAGE | Image to process. | |
| mean | FLOAT | 0.500–1 | Mean value for normalization. |
| std | FLOAT | 0.500.001–1 | Standard deviation for normalization. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | Processed images |