HDR Exposure Blend
You shot the brackets, now merge them properly
- low_exposure
- high_exposure
- mid_exposure
- blended_hdr
- blend_mask
- blend_info
Most "HDR" nodes in ComfyUI are tone mapping - they take one SDR image and make it look like HDR. HDR Exposure Blend is the other thing: the actual exposure-fusion merge. If you bracketed a shot with a camera, or you synthesised brackets from one frame at different exposures, this takes the highlights from the dark frame and the shadows from the bright one and combines them into genuinely wider range.
That's a real, decades-old technique, not a model. It won't invent a sky. But when the brackets exist, nothing beats it for stability - the same input always produces the same output, and there's no hallucination to review.
How it works
First, every bracket is normalised to one linear scale. That's what the exposure_offset_* inputs do, and it's the part people get wrong (see below). Then a merge method decides how the brackets combine.
Five methods are on offer. Mertens Fusion (the default) is per-pixel contrast/saturation/exposedness weighting - the classic exposure-fusion algorithm, and the one to start with. Exposure Weighted favours original bracket values away from black and clipping, then combines compensated linear values. Luminance Weighted and Shadow/Highlight Mask do what their names suggest, and only those two use transition_smoothness. Laplacian Pyramid is the multi-scale option for stubborn blends.
ghost_removal does two things depending on method: it aligns brackets by global translation up to 64 pixels, and (Mertens only) down-weights pixels that disagree between brackets - which is how you handle a person who moved between frames. Other methods only align.
Outputs are blended_hdr, blend_mask, and blend_info.
The inputs worth setting
Required: low_exposure (the darker bracket - your source of highlight detail) and high_exposure (the brighter bracket - your shadow detail), plus blend_method. Both want linear input; both process every frame in the batch, and a single bracket frame broadcasts across the batch, which is handy when only one plate moved.
Then the optional set: mid_exposure for a third bracket, shadow_weight / highlight_weight / transition_smoothness for the zone methods, the three exposure_offset_* values, and ghost_removal.
The offsets are where the design gets interesting and slightly counterintuitive. exposure_offset_low defaults to -2 and the tooltip explains that the value gets multiplied by 2^-EV - so -2 brightens that bracket by 4×, bringing it onto the same linear scale as the rest. Same logic in reverse for exposure_offset_high at +2. This is the node normalising your brackets, and the sign convention is the opposite of how most people say "the dark one is a stop under."
Install
Manager → search Radiance → Install → restart ComfyUI → refresh the browser. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/fxtd-studios/radiance.git
cd radiance
python -m pip install -r requirements.txt
Windows portable users: run pip with python_embeded\python.exe. No models required for this node - it's all math.
Where people get burned
Wrong offsets give you a washed-out merge, and it's subtle - the blend succeeds, it just looks flat and low-contrast because the brackets are on mismatched scales. Set the offsets from your actual bracket spacing, don't leave them at defaults and hope.
mid_exposure is ignored by three of the five methods. Only Mertens Fusion and Exposure Weighted use it. Wire in a third bracket, pick Shadow/Highlight Mask, and you'll spend an evening wondering why it changes nothing. The tooltip does say so; nobody reads it the first time.
The zone weights are method-specific too. shadow_weight, highlight_weight and transition_smoothness only apply to Luminance Weighted and Shadow/Highlight Mask (and transition_smoothness to Exposure Weighted as well, per its own description). Everything else ignores them silently.
And the same size rule as anywhere in this pack: high_exposure must match low_exposure in resolution and be either the same batch length or a single frame. Mismatches won't always error - they'll just misalign.
Inputs (11)
| Name | Type | Default | Description |
|---|---|---|---|
| low_exposure | IMAGE | Darker bracket, the source of highlight detail. Should be linear; every frame is processed; a single bracket frame broadcasts across the batch. | |
| high_exposure | IMAGE | Brighter bracket, the source of shadow detail. Should be linear and the same size as low_exposure, with matching batch length or one frame. | |
| blend_method | COMBO | Mertens Fusion | How brackets are merged after EV compensation. Mertens: per-pixel contrast/saturation/exposedness weights. Exposure Weighted favours original bracket values away from black and clipping, then combines compensated linear values. |
| mid_exposureopt | IMAGE | Optional middle bracket, compensated by exposure_offset_mid. Used by Mertens Fusion and Exposure Weighted; the other methods ignore it. | |
| shadow_weightopt | FLOAT | 1.00–2 | Relative weight of high_exposure in the shadow zone (low_exposure luma below 0.25). Shadow/Highlight Mask method only. |
| highlight_weightopt | FLOAT | 1.00–2 | Relative weight of low_exposure in the highlight zone (low_exposure luma above 0.75). Shadow/Highlight Mask method only. |
| transition_smoothnessopt | FLOAT | 0.300.05–1 | Width in luma of the crossfade between brackets; higher is softer. Used by Luminance Weighted and Shadow/Highlight Mask only. |
| exposure_offset_lowopt | FLOAT | -2.0-6–0 | EV of low_exposure relative to 0 EV. It is multiplied by 2^-EV (-2 brightens it 4x) so all brackets share one linear scale. |
| exposure_offset_highopt | FLOAT | 2.00–6 | EV of high_exposure relative to 0 EV. It is multiplied by 2^-EV (+2 darkens it 4x) so all brackets share one linear scale. |
| exposure_offset_midopt | FLOAT | 0.0-6–6 | EV of the optional middle exposure relative to 0 EV. Applied as compensation so all three exposures are normalised to the same scale before fusion. |
| ghost_removalopt | BOOLEAN | false | Align brackets by global translation (up to 64 px). Mertens Fusion also down-weights pixels that disagree between brackets (moving objects); other methods only align. |
Outputs (3)
| Name | Type | Description |
|---|---|---|
| blended_hdr | IMAGE | — |
| blend_mask | IMAGE | — |
| blend_info | STRING | — |