Image Retinex Enhancement
MSRCR for the murky, backlit, low-light mess
- input_image
- enhanced_image
You know the photo: shot against a window, everything in shadow, colors murky and flat. Brightness sliders don't fix it because the problem isn't exposure - it's that the scene's illumination varies wildly across the frame. Image Retinex Enhancement applies Multi-Scale Retinex with Color Restoration (MSRCR), a classic computer-vision technique that tries to separate an image into "how it's lit" and "what it actually is," then throws away the lighting and keeps the content. Shadow detail comes out, color comes back, and you get a much more usable source for img2img, a ControlNet preprocessor, or just a finished image that doesn't look like it was shot in a cave.
It's a deterministic OpenCV/numpy pixel operation - milliseconds, no model, no diffusion pass - which is exactly the right category of tool for "fix the source before the pipeline sees it." It pairs naturally with the pack's CLAHE node: Retinex for recovering dynamic range, CLAHE for pulling local detail.
How it works
Retinex is based on the idea that a pixel's brightness is a product of illumination × reflectance. If you can estimate illumination (by blurring heavily), you can divide it out to get the reflectance - the "true" colors of the scene, independent of how dark the light was. Multi-scale means it does this at three blur scales and blends them, so it handles both small and large illumination gradients. Color Restoration is the crucial fix for the classic retinex failure - without it, results come out gray and desaturated; with it, the color ratios are partially re-asserted.
The knobs map onto that mechanism:
gaussian_sigma_small/gaussian_sigma_medium/gaussian_sigma_large(defaults 12 / 60 / 180) - the three illumination-estimation scales. Smaller = more local detail recovery; larger = smoother, more global correction.color_restoration_strength(100) andcolor_restoration_offset(25) - how hard the color restoration pulls; higher = more saturated output.output_gain(1.2) andoutput_offset(-0.5) - the final tone-mapping to get the reflectance back into displayable 0–1 range. This is where you tame the "overprocessed" look: if the result is blown out, lower the gain.
Output is a single enhanced_image at the input's resolution.
Installing it
Part of CorvaeOboro's ComfyUI_illumorae (CC0, no model downloads - pure OpenCV/numpy). ComfyUI Manager → search illumorae, or:
cd ComfyUI/custom_nodes
git clone https://github.com/CorvaeOboro/ComfyUI_illumorae
Common issues
- Output looks over-processed / radioactive - the default
output_gainof 1.2 and offset -0.5 are tuned punchy. Dial gain toward 1.0 and offset toward 0 for a more natural look. This is the dial you'll touch most. - Halos around strong edges - large
gaussian_sigma_*values create halo artifacts at bright/dark boundaries. Shrink the scales for content with hard edges. - Washed-out or gray result -
color_restoration_strengthtoo low, or you're fighting a very low-contrast source. Raise strength toward 150–200, or stack a CLAHE pass after. - It's not magic - MSRCR enhances dynamic range; it can't invent detail that isn't in the shadows (noise gets amplified along with signal). Use it on recoverable sources, and keep the result as input to a generation pass rather than a polished final.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| input_image | IMAGE | — | |
| gaussian_sigma_smallopt | FLOAT | 15.00.1–500 | — |
| gaussian_sigma_mediumopt | FLOAT | 80.00.1–500 | — |
| gaussian_sigma_largeopt | FLOAT | 250.00.1–500 | — |
| color_restoration_strengthopt | FLOAT | 125.00.1–500 | — |
| clip_percentopt | FLOAT | 1.00–49 | — |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| enhanced_image | IMAGE | — |