Nodes/MKRShift_Nodes/Neutrality Map
ComfyUI Node

Neutrality Map

Find the color cast everyone else is missing

By criskb·Created 7 months ago·Updated 5 months ago· 0
Neutrality Map
  • image
  • mask
  • image
  • mask
  • neutrality_map_info
settings_json{"sat_ceiling":0.18,"luma_floor":0.1,"luma_ceiling":0.92,"cast_gain":1.35,"warmth_bias":0.0,"overlay_opacity":0.82,"show_isolation":false,"mask_feather":12.0,"invert_mask":false}

Color cast diagnosis is the least glamorous part of grading, which is exactly why nobody builds good tooling for it. You squint at a shadow, decide it "looks a bit green," and reach for a channel mixer. x1NeutralityMap is a more honest approach: it finds the pixels that should be neutral - low saturation, mid-luminance surfaces where a cast would show - and shows you what color they actually are. That's your cast, isolated from all the intentionally-colored stuff in the frame.

It's part of MKRShift Nodes' Color/Analyze branch, a small set of scope/analysis nodes that output both a visualization and a mask. What makes NeutralityMap different from a vectorscope is that it doesn't make you read a plot - it paints the answer on the image.

How it works

Under the hood it's a quiet little pipeline: compute saturation and luminance, gate to the pixels that read as near-neutral (below sat_ceiling, within the luma_floorluma_ceiling band), then measure how those pixels diverge from gray. A cast_gain control (default 1.35) exaggerates the divergence so subtle casts become visible, and a warmth_bias slider lets you nudge which direction counts as "wrong" - handy when you're deliberately working warm and only want to see the green.

The controls live in a settings_json string, per this pack's house style. The defaults are tuned for real work: sat_ceiling 0.18 and a luma band of 0.10–0.92 are a sensible "these pixels are probably meant to be gray" window.

Inputs and outputs

Required: image and settings_json. Optional: mask, which limits where the analysis runs - genuinely useful for checking skin tones in isolation, since skin is often the region people want neutralized first.

  • image - the analysis overlay: near-neutral pixels colored by their actual cast, intensity boosted by cast_gain
  • mask - the neutral/cast region as a MASK
  • neutrality_map_info - a STRING summary of the resolved settings

The mask output is the underrated part. Wire it into a x1ColorBalance or a curves node and you can correct the cast only in the region that's actually off, instead of grading the whole frame. That's the professional move, and it's the reason this node earns its place next to the pack's grading tools rather than just being a fancy debug view.

There's also a show_isolation toggle inside the JSON: flip it on and the output shows only the selected region instead of the full frame with an overlay, which makes it much easier to judge whether the selection window is catching the right pixels.

Installing it

Same as every MKRShift node - ComfyUI Manager, search "MKRShift Nodes", or:

cd ComfyUI/custom_nodes
git clone https://github.com/criskb/MKRShift_Nodes

Restart, done. No dependencies beyond the bundled torch/numpy code, no model files, no ffmpeg. The usual caveat applies: the pack is a giant grab-bag, so you're installing a lot of surface area for one analysis node. The Color/Analyze siblings (x1RGBBalanceScope, x1SatLumaScope) are worth grabbing in the same install.

Where people get burned

The classic mistake is cranking cast_gain to 3.0, seeing neon-everywhere, and concluding the image is ruined - the gain exists to exaggerate, not to measure at face value. Read relative differences, not absolutes. And remember warmth_bias cuts both ways: it's how you tell the node "yes, I know it's warm, don't flag that." Skip that and a perfectly intentional golden-hour grade gets flagged as a cast.

CategoryMKRShift Nodes/Color/Analyze

Inputs (3)

NameTypeDefaultDescription
imageIMAGE
settings_jsonSTRING{"sat_ceiling":0.18,"luma_floor":0.1,"luma_ceiling":0.92,"cast_gain":1.35,"warmth_bias":0.0,"overlay_opacity":0.82,"show_isolation":false,"mask_feather":12.0,"invert_mask":false}
maskoptMASK

Outputs (3)

NameTypeDescription
imageIMAGE
maskMASK
neutrality_map_infoSTRING