Nodes/ComfyUI_FunCode/Color Match FunCode
ComfyUI Node

Color Match FunCode

Instant palette transplants — no re-rolls needed

By kaiery·Created 8 months ago·Updated about a month ago· 0
Color Match FunCode
  • image_ref
  • image_target
  • image
methodmkl
strength1.00
multithreadtrue

When the colors are "off" in a generated image, the default move is to re-roll the generation and hope. Color Match FunCode is the cheap deterministic alternative: it takes a target image and a reference, and moves the target's palette toward the reference's - in a few hundred milliseconds, every time. This is the same family of statistics-based color transfer that underpins most color-grading utilities, wrapped in a ComfyUI node with six methods to pick from.

It's the node to reach for when an outpainted region doesn't match the original, when a composited subject sits in a scene with the wrong light, or when an upscaled tile disagrees with its neighbours. Those are exactly the jobs the post-processing layer's "cheap primitive before expensive generative fix" rule is about: a color match is instant and deterministic; a re-gen is neither.

How it works

Under the hood it uses the color-matcher library (the same one cited in the node's own description) - the classic ColorMatcher().transfer(src, ref, method) call, which aligns the target's color statistics to the reference's using one of several algorithms:

  • mkl (default) - Monge–Kantorovich Linear, a robust full-color transfer that's a solid general-purpose default.
  • hm - histogram matching, per-channel.
  • reinhard - the original Reinhard mean/std transfer; fast and good enough for many jobs.
  • mvgd - multivariate Gaussian distribution matching.
  • hm-mvgd-hm, hm-mkl-hm - histogram-prefixed hybrids that tend to look more natural.

There's no neural network and no model file - this is pure numpy math on the pixels. The strength slider blends between the original and the full transfer (output = original + strength × (result − original)), so 0 is untouched, 1 is the full match, and anything above 1 overshoots deliberately.

Inputs and output

The three required inputs are the whole story:

  • image_ref - the image whose color feel you want.
  • image_target - the image being recolored.
  • method - one of the six above; mkl is the sane default until you have a reason to switch.

Optionals: strength (default 1.0, range 0–10) and multithread (default on, which parallelizes the work across a batch on CPU - a real speedup if you're matching a whole video frame batch).

Output is a single image, ready for a preview node or straight back into your pipeline.

Installing

Same pack, with one extra step: this is the only node in ComfyUI_FunCode that needs the pack's pip dependency, and the node refuses to run without it:

cd ComfyUI/custom_nodes
git clone https://github.com/kaiery/ComfyUI_FunCode
pip install -r requirements.txt   # installs color-matcher

Then restart ComfyUI. No model files, nothing else to fetch.

Common issues

  • "Can't import color-matcher, please install it first" - the exact error you get if you skipped the pip step. Run pip install color-matcher and restart.
  • Batch size mismatch - the reference batch must be either 1 or the same size as the target batch. Feed a single reference and a batch of frames and it applies that one reference to every frame; feed matched pairs and it does per-frame transfer.
  • Colors look washed or blown out - strength above 1 overshoots by design. Drop it back toward 1 (or below) and try hm-mkl-hm if mkl feels too aggressive.

One honest note: the pack is small and fresh, so don't expect a big community consensus on which method "wins." For most composites, default mkl at strength 1.0 looks right, and you're done in the time it took to read this paragraph.

CategoryFunCode/Image

Inputs (5)

NameTypeDefaultDescription
image_refIMAGE
image_targetIMAGE
methodCOMBOmkl6 options: mkl, hm, reinhard, mvgd, hm-mvgd-hm, hm-mkl-hm
strengthoptFLOAT1.000–10
multithreadoptBOOLEANtrue

Outputs (1)

NameTypeDescription
imageIMAGE