Contrast Analysis
Flat, lifeless render? Here's the number that proves it
- image
- contrast_score
- contrast_map
"Low contrast" is easy to feel and hard to argue about. Contrast Analysis makes it measurable: it scores how well an image uses its tonal range, either across the whole frame or region by region, and gives you a heatmap of where the contrast lives. It's the pack's answer to flat, milky renders that look like the tone curve was ironed flat.
It comes from ThatGlennD's ComfyUI-Image-Analysis-Tools, and it's one of the more configurable nodes there - two combos and a block size to think about before you trust the number. Worth the thirty seconds, because the default setting isn't right for every job.
How it works
Two separate axes combine:
method- the scope. Global scores the entire image at once. Local divides it into blocks and scores each one. Hybrid (default) averages the two.comparison_method- the formula applied. RMS (default) is the standard deviation of intensities: a general "how much tonal variance is there" measure that suits natural gradients and soft light. Michelson is(max − min) / (max + min): sensitive to bold differences in bright areas, the pick for dramatic lighting. Weber is(max − mean) / mean: contrast relative to background intensity, which is good at catching weak local contrast in low light.
The contrast_score output is a single float that depends on both choices - so don't compare a Global/RMS score against a Local/Weber score and read meaning into the difference. Pick one recipe and stick to it across your comparisons.
The contrast_map output is the visual half: a magma heatmap, brighter = higher local contrast, with a colorbar. One honest limitation from the source: the map only renders for Local and Hybrid methods. If you leave method on Global and visualize_contrast_map on, you get a black placeholder image rather than a map - switch to Local or Hybrid if you want the heatmap.
The input that matters
- block_size (8–128, default 32, steps of 8): only used by Local/Hybrid. Small blocks (16) expose fine tonal variation - great for spotting texture that's been compressed flat. Large blocks (64+) read broader patterns and run faster.
Where it earns its keep
- Flagging flat renders before you waste an upscale pass on them - upscaling can't invent tonal range that isn't there.
- Comparing samplers, CFG values, or LoRA lighting behavior with a number instead of a side-by-side stare.
- Building an automated "too dull, reroll" gate in a batch pipeline.
Pair it with the RGB Histogram Renderer from the same pack: the histogram shows you where the tones sit, this node tells you how much spread they have. Together they're the tonal half of the toolkit, next to the Clipping Analysis node for the damage end of the curve.
Install
Manager (search "Image Analysis") or manually:
cd ComfyUI/custom_nodes
git clone https://github.com/ThatGlennD/ComfyUI-Image-Analysis-Tools
cd ComfyUI-Image-Analysis-Tools
pip install -r requirements.txt
Restart ComfyUI. Requirements: numpy, opencv-python, matplotlib, scikit-learn, Pillow, torch - no models, no downloads.
Common gotchas
- Pack doesn't appear: the suite imports scikit-learn at module load (via the Color Harmony Analyzer), so a missing scikit-learn kills every node. Windows portable:
python_embeded\python.exe -m pip install scikit-learn. comfy_apiimport error: update ComfyUI - the pack needs the newer node API.- Black
contrast_map: checkmethod- Global mode doesn't produce a map. - First frame only: batches score frame 0; process video frames individually.
The one trap beginners hit: treating a low contrast score as always bad. A foggy-morning shot should score low on contrast and be exactly right. Measure it, understand what your target recipe produces, then flag the deviations - not the low scores themselves.
Inputs (5)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | — | |
| method | COMBO | Hybrid | 3 options: Global, Local, Hybrid |
| comparison_method | COMBO | RMS | 3 options: Michelson, RMS, Weber |
| block_size | INT | 328–128 | — |
| visualize_contrast_map | BOOLEAN | true | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| contrast_score | FLOAT | — |
| contrast_map | IMAGE | — |