Nodes/NN-custom-nodes/Contrast Adjust (Ref)
ComfyUI Node

Contrast Adjust (Ref)

Match one image's contrast to another, automatically

By bandifiu·Created about a month ago·Updated about a month ago· 0
Contrast Adjust (Ref)
  • image
  • ref_image
  • image
multiplier1.00

The classic problem: you've generated a batch of images that should all have the same mood, and a couple came back flat while one came out punchy. Hand-tuning each one is misery. NNContrastAdjustRef (display name "Contrast Adjust (Ref)") does what you'd otherwise do by eye - it takes the contrast statistics from a reference image and applies them to your image, automatically.

What it is

A reference-based contrast matching node from the bandifiu/ComfyUI-NN-custom-nodes pack. Per the README it's for "style matching, consistent image batches, reference-based workflows." You feed it an image to adjust and a ref_image to learn from, and it transfers the reference's luminance contrast onto the target.

How it works

This is the classic Reinhard-style statistics transfer, but done in luminance space only - the whole point is that it adjusts contrast without shifting color. The mechanism, straight from the source:

  1. Convert both images to luminance using the ITU-R BT.709 weights (0.2126 red, 0.7152 green, 0.0722 blue).
  2. Compute each image's luminance mean and standard deviation.
  3. Derive a contrast ratio: the reference's standard deviation divided by the target's. If the reference is punchier, the ratio is > 1 and contrast gets stretched; if it's flatter, contrast gets compressed.
  4. Apply the same uniform scaling to all three color channels, then shift the mean to the reference's mean.

The clever bit is that step 3–4 happens in RGB space using a luminance-derived scalar, so you get a real contrast match without the color bleed that naive per-channel transfers cause. Everything is clamped to [0, 1], so highlights and shadows clip gracefully instead of going outside gamut.

That multiplier input is the knob you'll actually care about. It ranges 0–2, default 1, and interpolates how much of the match to apply: 0 means no change, 1 means the full transfer, up to 2 lets you overshoot past the reference for an exaggerated look. This is the difference between "match my batch to this image" and "make my batch punchier than my reference."

The inputs

  • image - the one being adjusted.
  • ref_image - the one providing the statistics. Optional, and important: if you leave it unconnected, the node just passes image through unchanged. No reference, no work.
  • multiplier - strength of the match, 0–2, default 1.

Single image output, batch-compatible, wired straight into a preview or the save chain.

When to use it

This is the underrated member of the color-matching family. Where the KB's post-processing doc points at spacepxl's Color Match Image for full mean/std color transfer, this node does the narrower, safer job of contrast-only matching - which is precisely what you want when the color is fine but the punch is inconsistent. Three concrete uses:

  • Batch consistency: grade every frame of a video or every image in a series to the same reference.
  • Style matching: borrow the contrast curve of a reference shot you like the look of.
  • Reference workflows: when a second image is your target mood, this gets you closer than a contrast slider ever will.

If the problem is color casts rather than contrast, this isn't the node - that's channel work (NNImageAdjustColor) or a full color-match node.

Installing

Part of bandifiu/ComfyUI-NN-custom-nodes:

cd ComfyUI/custom_nodes
git clone https://github.com/bandifiu/ComfyUI-NN-custom-nodes

Restart ComfyUI (or Manager → search "NN-custom-nodes"). No models, no downloads - torch/numpy/pillow only. GPL-3.0, V3 backend API, no classic NODE_CLASS_MAPPINGS.

One practical note: the transfer uses whole-image statistics, so a reference with very different content (a dark scene matched to a bright one) will shift your mean more than you might want. If that happens, back multiplier off to ~0.5 rather than abandoning the node - partial transfer is usually the sweet spot anyway.

CategoryNN/image

Inputs (3)

NameTypeDefaultDescription
imageIMAGE
ref_imageoptIMAGE
multiplieroptFLOAT1.000–2

Outputs (1)

NameTypeDescription
imageIMAGE