Color Match (Reference)
Make your image borrow another photo's color, the principled way
- image
- reference
- image
You've got a shot whose colors you love - a reference - and a target image that needs to take on its character. Most people reach for a teal-and-orange slider and eyeball it. Color Match (Reference) does it for real: it shifts the target's color distribution toward the reference's, statistically, instead of guessing.
It's one of the most-used nodes in the Darkroom pack (the AKURATE/Darkroom/Grading subcategory), and it shows up a lot in colorist-style workflows where you want a specific film or cinematic look without recreating it by hand.
How it works
The match happens in LAB color space - the perceptually uniform one, where "distance between colors" means roughly what your eye means by it. Then it picks between four transfer algorithms via the method dropdown:
- reinhard - mean/std transfer. Fast, stable, and the safe default. Best when the reference is one cohesive tone.
- wasserstein - sliced optimal transport via iterative advection. Handles multi-modal distributions (a reference with several distinct color populations) better than reinhard.
- forgy - K-means palette matching with Gaussian-weighted soft assignment. Builds an 8-color palette (tune with
n_colors) and remaps to it. Needs sklearn, which ships with most ComfyUI installs. - kantorovich - closed-form Gaussian linear transport. The mathematically fanciest option, and it needs
pip install POTto exist at all.
These algorithms are adapted from the MIT-licensed rajawski/gradia project, and the author keeps the attributions honest in the source.
The inputs that matter
You'll set three things and ignore the rest at first:
image- the target you're grading (this is the one that changes).reference- the image whose color character you want.method- start withreinhard; trywassersteinif the reference has multiple strong color regions.intensity- the blend between original (0) and full match (1). Default is 0.8, and that's a sane place to start; a full 1.0 match often overreaches on skin.
The optional n_colors, n_slices, sample_size, and seed are per-method tuning knobs - n_colors for forgy's palette, n_slices for wasserstein's advection iterations, sample_size for how many pixels get sampled during fitting, and seed so you can reproduce a run.
Output is a single image, which wires straight into the rest of your grade.
Where people get burned
- Kantorovich silently downgrades. If POT isn't installed, the node logs a warning and falls back to reinhard. You'll get a result either way - just not the one you asked for. Install it with
pip install POTif you want that method. - Don't put it in a LUT bake chain. Color Match is reference- and content-adaptive, like Auto White Balance: it reads the whole image to decide the transform, so it can't be baked into a per-pixel .cube. Same reason it's absent from the README's bake-allowed list.
- Intensity is your friend. A hard 1.0 match can blow out the target's own character. Dial back to 0.5–0.7, then stack a gentle tone curve on top.
Installing the pack
Darkroom is a 54-node suite (this node lives in it), so you install the whole thing once:
cd ComfyUI/custom_nodes
git clone https://github.com/jeremieLouvaert/ComfyUI-Darkroom.git
pip install -r ComfyUI-Darkroom/requirements.txt
Or search "Darkroom" in ComfyUI Manager and let it handle the dependencies - it needs scipy, opensimplex, rawpy, exifread, and Pillow. Restart ComfyUI and every node shows up under AKURATE/Darkroom/. No API keys, no model downloads, and it runs happily on CPU since it's pure numpy/scipy.
The classic ComfyUI dependency gotcha applies: if Manager installs it into an environment that already has conflicting scipy, you may need to re-run pip install -r by hand. But this pack is lightweight compared to most - the heavy optional dependency (POT) is only for that one color-match method.
Inputs (8)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | The image to grade (target) | |
| reference | IMAGE | The image whose colour character to match | |
| method | COMBO | reinhard | reinhard: fast mean/std. wasserstein: multi-modal OT. forgy: palette K-means (sklearn). kantorovich: Gaussian OT (POT). |
| intensity | FLOAT | 0.800–1 | Blend between original (0) and full match (1) |
| n_colorsopt | INT | 84–16 | Forgy only: palette size |
| n_slicesopt | INT | 204–200 | Wasserstein only: advection iterations |
| sample_sizeopt | INT | 500005000–500000 | Wasserstein/Kantorovich/Forgy: pixels sampled for fitting |
| seedopt | INT | 420–4294967295 | Random seed (determinism) |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | IMAGE | — |