Nodes/Link Comfy Nodes/Match Colors to Reference
ComfyUI Node

Match Colors to Reference

The color-match node that fixes flicker, because it understands you're working with video

By Mister-Link·Created 10 months ago·Updated 6 days ago· 0
Match Colors to Reference
  • image_target
  • image_ref
  • matched_frames
strength0.88
max_fit_samples60000
per_bin_cap300
bin_L4.0
bin_ab6.0
trim_low0.5
trim_high99.5
seed7

Every color-matching node can do the classic trick: take your image, take a reference, transfer the reference's color statistics onto yours, done. What most of them can't do is handle a sequence without turning it into a strobe light - each frame matched independently to a static reference will wobble, because frame-to-frame noise throws the statistics around. That's the problem this node exists to solve. It's a Reinhard-style Lab color transfer (match per-channel mean and standard deviation), but with a centered temporal window that pools statistics across neighboring frames, so your matched footage stays steady. And it can even run with no reference at all, pulling frames toward their own consensus to kill color drift.

This is squarely the "reach for the cheap deterministic primitive before the expensive generative one" territory - the KB's post-processing doc makes the case that a statistics transfer is instant and deterministic, while re-rolling a generation to fix "the colors are off" is neither. When an inpainted region, an upscaled tile, or a composited subject doesn't sit in its scene's light, this is the honest fix.

How it works

It converts frames to CIE Lab, computes each channel's mean and standard deviation, then maps the target's stats onto the reference's. Doing it per-channel in Lab is what preserves the frame's internal color relationships - it's a global shift and scale, not a per-pixel remap. The video-aware parts are where it gets clever:

  • frame_window (default 9) pools Lab stats over a centered window of frames (9 = this frame plus 4 behind and 4 ahead). The window wraps around the batch, so a looping sequence's last-to-first transition is stabilized like any other seam.
  • With image_ref connected, the pooled stats are the source side: frame t's mapping uses the window consensus instead of its own noisy solo stats, so you get no-lag smoothing (better than an EMA, since it's centered).
  • Without image_ref, the pooled stats are the destination: each frame gets pulled toward its neighbors' consensus. That's self-referential drift removal - handy for footage whose color wanders over time, with no reference needed. Set the window longer than the drift or it just re-anchors locally.
  • Alpha awareness: if your frames have an embedded alpha channel, it weights the statistics so transparent regions (say, a keyed-out background still lurking in RGB) don't skew the mapping. The target's alpha is passed through untouched.

Inputs and outputs

  • image_target (IMAGE) - the frames to fix.
  • strength (0–1, default 1) - blend between original (0) and fully matched (1). Start at 0.6-0.8 for compositing; full strength can over-flatten a frame.
  • frame_window (1–99, odd values, default 9) - the pooling window described above.
  • image_ref (optional IMAGE) - the absolute reference. A batch of 1 applies to all targets; otherwise its batch size must match the target's. Leave unconnected for the self-consensus mode.

Output is matched_frames (IMAGE), same batch size as input.

Installing it

It's part of Link Comfy Nodes:

cd ComfyUI/custom_nodes
git clone https://github.com/Mister-Link/link-comfy-nodes
cd link-comfy-nodes
pip install -r requirements.txt

or ComfyUI Manager → "Link Comfy Nodes", then restart. No model downloads - this one is pure numpy/torch pixel math, which is exactly the point.

Common issues

  • Ref batch size doesn't match target - a multi-frame reference must match the target's batch count; only a single-frame ref broadcasts to everything.
  • No visible change with no reference - with frame_window at 1 and no image_ref, each frame's consensus is itself, so it's a no-op by design. You need a window for the drift-removal mode to do anything.
  • Non-looping footage gets a weird first frame - the window wraps around the batch because the node assumes loops. For non-looping sequences, that wrap makes the first frames borrow statistics from the end of the clip. Keep that in mind before blaming the node.
  • strength 1.0 looks washed out - Lab mean/std transfer flattens contrast by construction; back the strength off.

For matching one still to a reference, plenty of packs do the job. For matching a sequence - or de-drifting a loop without hunting for a reference - this is the one to reach for.

Categorycolor

Inputs (10)

NameTypeDefaultDescription
image_targetIMAGE
strengthFLOAT0.880–1
max_fit_samplesINT600001000–500000
per_bin_capINT3001–10000
bin_LFLOAT4.00.1–50
bin_abFLOAT6.00.1–50
trim_lowFLOAT0.50–49
trim_highFLOAT99.551–100
seedINT70–2147483647
image_refoptIMAGE

Outputs (1)

NameTypeDescription
matched_framesIMAGE