Nodes/GPU LayerStyles/GPU LayerStyles ColorMatch
ComfyUI Node

GPU LayerStyles ColorMatch

Make two images agree on colour instead of re-rolling the seed

By lany42·Created 22 days ago·Updated 15 days ago· 0
GPU LayerStyles ColorMatch
  • image
  • image_ref
  • image
◄methodmkl►
◄strength1.00►
◄output_devicecpu►
◄batch_size0►

You outpainted a patch and it's slightly greener than its surroundings. You upscaled a tile and it's warmer than its neighbours. You composited a subject into a new background and it looks pasted on because the light is the wrong colour. None of those are generation problems, and re-rolling the seed for them is the expensive, non-deterministic way to fail. GPULayerStyles_ColorMatch is the deterministic way out: give it a target and a reference and it moves the target's colour statistics onto the reference's.

How it works

Two algorithms, both from Christopher Hahne's color-matcher research code, both reimplemented here as native PyTorch rather than pip-depended on:

  • mkl (Monge-Kantorovich linear) reads the target's and reference's mean and covariance and solves for the colour transform that takes one distribution to the other. Because it only ever looks at statistics, the reference can be any resolution, and each target frame is matched on its own.
  • mvgd builds a per-position system using the reference's pixel layout - that's why it demands the reference match the target's height and width, and why it matches corresponding pixel positions rather than overall distributions. Use it when your reference is a genuinely corresponding image (a frame from the same shot, a mask-aligned pair).

strength is a straight linear blend between the original and the matched result, then clamped. At 1.0 you get the full transform. At 0.5 you get half of it, which is the setting that keeps people out of trouble - a full statistical match is strong, and it will happily flatten a deliberate stylistic grade to match a boring reference.

Inputs and output

  • image - the thing being corrected.
  • image_ref - the reference. Either one frame, applied to every target frame, or a batch the same length as the target, applied frame by frame. Anything else is rejected outright.
  • method - mkl (default) or mvgd.
  • strength - 0 to 1, step 0.01, default 1.
  • output_device and batch_size - the pack's standard execution controls: process in float32 on the compute device, hand back on CPU by default (gpu skips the round trip when the next node is also on-device), and chunk frames at whatever batch_size you set, with 0 meaning start at 64.

One output, image. If the target has an alpha channel it is preserved untouched - only RGB is matched, so a cut-out stays a cut-out.

Where this belongs in a workflow

Three jobs come up constantly, and all three are the same node:

  1. Repair after a regional edit. Inpaint or outpaint, then match the result back to the untouched source. Fixing "the edit came back warmer" with a second generation is a coin flip; this is instant and repeatable. (It's the same medicine the community applies to fp8 colour drift on Flux-class models.)
  2. Tile seam agreement. Upscalers that work tile by tile leave boundaries; matching each tile to a reference tile costs milliseconds.
  3. Composite integration. Match your subject to the background plate before you blend, not after.

If you already run spacepxl's Color Match Image or the upstream LayerStyle Color Adapter node, this is the same class of operation with the pack's batching and device controls attached. The advantage here is video: a 500-frame batch goes through in one node rather than a per-frame list loop.

Install

ComfyUI Manager → search GPU LayerStyles. Or:

cd /path/to/ComfyUI/custom_nodes
git clone https://github.com/lany42/gpu-layerstyles
# restart ComfyUI

Here's the part that surprises people: you do not install color-matcher. The algorithms are vendored as native PyTorch, and pyproject.toml declares no runtime dependencies - no pip step, no models, no API key. The pack wants Python 3.13+ and a current ComfyUI (comfy_api-era). AGPL-3.0-only, with the upstream attribution in the COPYRIGHT file; the original colour-matcher's own licence notices ship alongside.

Where people get burned

mvgd with a mismatched reference is the classic: it errors on unequal height/width, and that error is a feature - silently doing something else would be worse. The other one is over-matching. strength: 1.0 against a reference with a strong cast takes your image all the way to that cast, and for inpaint repair on a graded frame that's often more correction than you asked for. Start at 0.6–0.8 and go up only if the seam is still visible.

Numerical edge cases exist (degenerate flat images, where a covariance has no rank) and the node raises rather than inventing an answer. If you hit "numerical failure", your reference is probably a solid colour patch - give it something with actual texture in it.

CategoryGPU LayerStyles/Color

Inputs (6)

NameTypeDefaultDescription
imageIMAGE—
image_refIMAGE—
methodCOMBOmkl2 options: mkl, mvgd
strengthFLOAT1.000–1—
output_deviceCOMBOcpuReturn output on CPU (default) after float32 processing on ComfyUI's selected compute device. GPU keeps output on that device to avoid transfers between compatible nodes. ComfyUI CPU mode returns CPU output.
batch_sizeINT00–2147483647Frames per processing chunk. 0 starts at up to 64 frames. Positive values can exceed 64, capped by the output length. Allocation failures halve the chunk size for this run; each run starts fresh. Complete inputs and outputs still need memory. Pass smaller batches through the entire workflow to reduce complete-batch memory.

Outputs (1)

NameTypeDescription
imageIMAGE—