Nodes/ComfyUI-ColorConsistencyHSL/HSL Color Consistency Advanced
ComfyUI Node

HSL Color Consistency Advanced

Your Klein edit came back with a warm cast — this node drags it back in one pass

By overcloud81·Created 6 months ago·Updated 5 months ago· 10
HSL Color Consistency Advanced
  • reference
  • target
  • external_mask
  • IMAGE
mode亮度+色相+饱和度
anchor_mode统计匹配
luma_spaceLAB L通道
align_cornerstrue
interpolationbilinear
force_match_sizefalse
luma_strength1.00
strength1.00
protect_strength0.00
feather_radius10
auto_maskfalse
mask_threshold0.10

If you've edited a photo with FLUX.2-Klein and wondered why everything came back with a slightly warmer, slightly off color temperature - it's not you, it's the model. That shift is reproducible and documented on both fp8 and fp16 Klein, and the community fix has long been "histogram/color match it back against the source." This node is that fix, done properly in LAB color space and generalized past Klein: drop in your original as reference, your edited image as target, and it re-matches luminance, hue, and saturation so the edit keeps its content but stops wearing the model's color fingerprint.

It's a single-input-single-output postprocessor that lives in the image/postprocessing menu and works with any editing, enhancement, or upscaling workflow - its pitch, and it holds. No models to download, no API key, no VRAM cost to speak of. Pure per-pixel math on images you already have.

How it actually works

The node converts both images to CIELAB, then turns the a/b color channels into polar form: hue becomes an angle, saturation a magnitude. That's the trick that makes it different from a dumb "match the RGB average" node - it can manipulate brightness, hue, and saturation as independent knobs without cross-contamination.

For each knob you get two philosophies. Statistical matching renormalizes mean and standard deviation, so the target adopts the reference's color "personality" while keeping its own local contrast and texture. Pixel-perfect just copies the reference value at every pixel - exact, but only sensible when content hasn't moved between the two images.

The four anchor_mode choices combine the two:

  • statistical match - mean/std on every channel you select
  • pixel-perfect - hard per-pixel copy
  • luminance stat + color exact - brightness renormalized, hue/saturation copied. This is the Klein sweet spot
  • color exact - pixel-perfect hue/saturation, luminance left completely alone. Great when you only want the cast fixed

Luminance stats can run on the perceptual LAB L channel or physical linear RGB luminance (luma_space); hue/saturation always live in LAB. When a mask is present, it computes stats over the stable (non-edited) pixels only, so a local edit won't pollute the whole-image color model.

The inputs that matter

You'll actually touch about half of them. reference and target are the two images. Then:

  • mode - which channels to match: luminance, hue, saturation, or any combination
  • anchor_mode - the matching philosophy above
  • luma_strength - how hard to apply luminance matching (0 = leave it, 1 = full)
  • strength - global blend of the whole corrected result over the target
  • protect_strength - how much of the original edited image survives inside the edit region
  • auto_mask / external_mask / feather_radius - how the edit region gets detected (auto = difference threshold, external = a mask you paint) and feathered

The single output is a corrected IMAGE, wired into a Save node or further postprocessing. For Klein edits the README's recommended combo is mode = luminance+hue+saturation, anchor_mode = luminance stat + color exact, luma_strength = 0.5, protect_strength = 0.3, feather_radius = 15 - a solid starting point.

Installing it

Two ways, same result:

# ComfyUI Manager (easiest): search "Color Consistency HSL" and hit install

# Or by hand:
cd ComfyUI/custom_nodes/
git clone https://github.com/overcloud81/ComfyUI-ColorConsistencyHSL

Then restart ComfyUI - it appears as "HSL Color Consistency Advanced". One dependency: scipy, used only for mask feathering. It's declared in the pack's pyproject, but the code degrades gracefully - if scipy is missing, feathering silently disables and the node still works. Worth a pip install scipy if you're going to feather. (The README's clone URL literally says yourusername - ignore it, the repo above is real.)

Gotchas worth knowing

The UI is bilingual, based on your ComfyUI language setting. An English ComfyUI shows English dropdowns (luminance+hue+saturation, statistical match...); a Chinese locale shows Chinese. If you see 亮度 etc., that's the locale, not a broken install.

Auto-mask can fight a global cast fix. auto_mask marks everything that differs from the reference - and a global warm cast differs everywhere, so the mask goes mostly white, then protect_strength re-blends the shifted original back in. For a whole-image cast, leave auto_mask off and let it correct globally; bring it in only when guarding a genuinely edited region.

Hue is an angle, and the statistical path averages it like a scalar. Near-red hues (the ±π wraparound) can average to something wrong. The color exact variants sidestep this entirely by copying, which is part of why they're the recommended path.

force_match_size is quieter than it looks. If reference and target differ in resolution, the reference gets scaled to target size unconditionally - the flag only controls whether you see a console warning. Sizes are always aligned, so mismatched inputs won't error - unlike mismatched batch counts, which raise a ValueError.

Categoryimage/postprocessing

Inputs (15)

NameTypeDefaultDescription
referenceIMAGE
targetIMAGE
modeCOMBO亮度+色相+饱和度7 options: 亮度, 色相, 饱和度, 亮度+色相, 亮度+饱和度, 色相+饱和度, +1
anchor_modeCOMBO统计匹配色彩精确:色相和饱和度像素级精确,亮度不变 / Color exact: pixel-perfect hue/saturation, luminance unchanged
luma_spaceCOMBOLAB L通道亮度统计匹配的空间(仅当亮度参与匹配时有效) / Space for luminance statistical matching (only when luminance is matched)
align_cornersBOOLEANtrue对齐四角,True可减少像素偏移 / Align corners, True reduces pixel shift
interpolationCOMBObilinear缩放插值方式 / Interpolation method for scaling
force_match_sizeBOOLEANfalse强制尺寸一致(不一致时自动缩放) / Force size match (auto-scale if different)
luma_strengthFLOAT1.000–1亮度统计匹配强度(仅亮度参与统计匹配时有效) / Strength of luminance statistical matching (only when luminance is matched statistically)
strengthFLOAT1.000–1整图混合强度 / Global blend strength
protect_strengthFLOAT0.000–1编辑区域保留原图的比例 / Proportion of original image retained in edit area
feather_radiusINT100–100蒙版羽化半径(像素) / Mask feather radius (pixels)
auto_maskBOOLEANfalse启用自动蒙版 / Enable auto mask
mask_thresholdFLOAT0.100–1自动蒙版阈值 / Auto mask threshold
external_maskoptMASK

Outputs (1)

NameTypeDescription
IMAGEIMAGE