Color Transfer
Give one image another image's palette, without wrecking the lighting
- source_image
- target_image
- mask
- image
"Surely there's a node for this." That's what you think the first time you have a render that's come out too cyan and a warm reference photo you'd love it to match. There is a node - this one - and it's smarter than the plain mean-and-standard-deviation color match you'll find scattered through other packs.
Color Transfer takes a source_image and a target_image, and makes the target wear the source's palette. Same composition, same lighting, different colors. Reach for it when you want a batch of renders to share one mood, when a prop texture has to blend into a scene it wasn't made for, or when you have a hero reference and want a generation to stop fighting it.
How it works
The mechanism is genuinely palette-based, not a global tint. It pulls the no_of_colors dominant colors out of the source (default 6), segments the target into color regions, pairs source and target palette colors by luminance, and swaps each region's color in. Then the strength dial decides how much of the target's original luminance survives the swap - that's the trick that keeps the result from going flat and plastic. A final gamma / contrast / brightness pass runs on top, and blur_radius / blur_amount control how the recolored regions blend at their edges.
There's an optional mask input, and it's worth knowing about: pass a MASK and the palette is only sampled from that part of the source. Want the target to take its greens from the grass and ignore the sky? Mask the grass.
The inputs you'll actually touch
no_of_colors(default 6) - the size of the extracted palette. Too low and you get a posterized, banded look; bump it toward 10-16 for photographic sources.strength(default 1, range 0-2) - luminance preservation. This is the dial you'll actually fidget with.gamma/contrast/brightness- the post pass; defaults are fine most of the time.
The output is a single image, ready to wire anywhere an IMAGE goes.
Installing it
The node ships in GeraldWie's ComfyUI-I2I-slim pack (a slimmer fork of ManglerFTW's ComfyI2I, minus the ComfyShop paint editor). Easiest route is ComfyUI Manager:
Manager → Install Custom Nodes → search "ComfyUI-I2I-slim" → Install → Restart
or the manual way:
cd ComfyUI/custom_nodes
git clone https://github.com/GeraldWie/ComfyUI-I2I-slim
cd ComfyUI-I2I-slim
pip install -r requirements.txt
One warning about that requirements file: it lists tensorflow and scikit-image, but the shipped code never imports either - they're leftovers. Installing the full list wastes a couple of gigabytes on a framework you don't need. The code actually runs on numpy, torch, torchvision, opencv and PIL. No model downloads needed for this node.
Common issues
- Posterized output -
no_of_colorsis too low. Raise it. - Result looks washed out - that's
strengthdrifting the luminance too far; pull it toward 1 or above to retain the target's lighting. - The original ComfyI2I color transfer was hard-coded to CUDA and simply broke on Apple Silicon - users were hand-editing
cudatompsin the source. This fork routes throughdevice = 'cuda' if torch.cuda.is_available() else 'cpu', so it works on a Mac out of the box.
One honest caveat: this fixes hue, not light direction. If your pasted region still looks foreign after a transfer, the missing piece is usually shadows - that's a different node's job.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| source_image | IMAGE | — | |
| target_image | IMAGE | — | |
| no_of_colors | INT | 60–256 | — |
| blur_radius | INT | 20–100 | — |
| blur_amount | INT | 20–100 | — |
| strength | FLOAT | 1.00–2 | — |
| gamma | FLOAT | 1.00.1–2 | — |
| contrast | FLOAT | 1.00–3 | — |
| brightness | FLOAT | 1.00–100 | — |
| maskopt | MASK | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |