Tone Refiner
Fix the grade, rescue the highlights, upscale, and fake a DOF — in one pass
- image
- latent
- vae
- upscale_model
- depth_map
- refined_image
- refined_latent
The image came back too dark, the highlights are clipped, the white balance is off, and maybe it could stand to be bigger. Tone Refiner (MEC) is the catch-all finishing node that addresses all of that in one shot: deterministic tone + gray-world color correction, optional upscale, and an optional depth-of-field blur. It's the "make it look finished" node at the end of the pack's paint suite.
The one thing to know up front: despite the neural_corrector name, there's no neural network here. It's deterministic image math - black/white-point stretching and gray-world color balancing. "Neural" is branding; the node is fast, predictable, and needs no model.
How it works
neural_corrector (default on) does the tone work. corrector_tone (default 0.6) blends toward the tone-corrected image - black/white-point stretch - and corrector_color (default 0.4) blends toward gray-world color balance (which kills color casts). Two nice touches: highlight_protection rolls off the top 5% to stop clipping, and shadow_lift lifts the bottom 5% on the dark side. The defaults are conservative enough that the result looks "fixed" rather than "graded."
Then the extras:
enable_upscale+upscale_factor(default 1.5) - usesupscale_modelif you connect one (RealESRGAN, 4x-NMKD, whatever), bicubic otherwise.ai_enable_dof+ai_dof_strength+ai_dof_focus_depth- a depth-of-field blur. Connect a realdepth_mapand it's depth-driven; leave it disconnected and you get a fake center-focus radial gradient. It's a stylization, not optics - great for a product shot thumbnail, wrong for anything where real defocus matters.latent/vae/auto_upscale- the latent side. With avaesupplied andauto_upscaletrue (default), it VAE-encodes the refined image intorefined_latentso you can feed the corrected result straight back into a sampler. Skip the VAE andrefined_latentis a zero placeholder.
Outputs: refined_image and refined_latent.
Where it fits
In the suite it's the grade-after-fix stage: Context Inpainter blends the inpaint back, Tone Refiner fixes the tonal drift that inpainting introduced, and the latent output hands the sampler a clean starting point. Standalone, it's a surprisingly useful one-stop for "my image is dark and casty and small" - most of that is the tone correction alone.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/Code2Collapse/ComfyUI-CustomNodePacks.git
pip install opencv-python>=4.7.0 scipy>=1.10.0
or ComfyUI Manager → search "CustomNodePacks", restart, confirm [MEC] Loaded .... No model downloads - the correction is math. If refined_latent comes back as zeros, you either skipped the VAE or auto_upscale is off, and that's the documented behavior, not a bug.
Inputs (16)
| Name | Type | Default | Description |
|---|---|---|---|
| image | IMAGE | Image to refine. | |
| neural_corrector | BOOLEAN | true | Enable deterministic tone + gray-world correction (not a learned model). |
| corrector_tone | FLOAT | 0.600–1 | Blend amount toward the tone-corrected image (0 = original, 1 = full correction). |
| corrector_color | FLOAT | 0.400–1 | Blend amount toward the gray-world color-corrected image. |
| highlight_protection | FLOAT | 0.500–1 | Roll-off applied above 95th-percentile to prevent highlight clipping (0 = none, 1 = strong). |
| shadow_lift | FLOAT | 0.000–1 | Lift shadows below the 5th-percentile (0 = none, 1 = strong; mirrors highlight_protection on the dark side). |
| enable_upscale | BOOLEAN | false | Upscale by upscale_factor; uses upscale_model if provided, bicubic otherwise. |
| upscale_factor | FLOAT | 1.501–4 | Upscale multiplier applied when enable_upscale is True. |
| ai_enable_dof | BOOLEAN | false | Apply depth-based DOF (uses depth_map if connected, else fake center-focus). |
| ai_dof_strength | FLOAT | 1.000–4 | Strength of the DOF blur (also scales the maximum blur radius). |
| ai_dof_focus_depth | FLOAT | 0.700–1 | Focus plane: when depth_map is connected this is the in-focus depth value (0=near,1=far); without depth_map it controls center-focus tightness. |
| latentopt | LATENT | Optional pre-existing latent; passed through when supplied (skips VAE encode). | |
| vaeopt | VAE | VAE used to encode the refined image into refined_latent (when auto_upscale is True). | |
| upscale_modelopt | UPSCALE_MODEL | Optional UPSCALE_MODEL (RealESRGAN / 4x-NMKD / etc.). When connected and enable_upscale is True, used instead of bicubic and resized to upscale_factor. | |
| depth_mapopt | MASK | Optional depth map (0=near,1=far). Drives DOF when connected; replaces the fake center-focus radial gradient. | |
| auto_upscaleopt | BOOLEAN | true | When True (default, back-compat), encode the refined image through the supplied VAE to produce `refined_latent`. Set False to skip the VAE-encode and return a zero placeholder. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| refined_image | IMAGE | Tone- and color-corrected image (optionally upscaled and DOF-blurred). |
| refined_latent | LATENT | VAE-encoded latent of the refined image (zero placeholder when auto_upscale is False). |