SDR to HDR (using Model) [Beta]
Hand the highlights to a net instead of a curve
- model
- images
- video
- images
- video
The pack ships two ways to expand SDR into HDR, and they're different philosophies. The algorithmic SDR to HDR node applies a soft-knee power curve: luminance gets pushed above white by an equation, and you control it with a knee and an exponent. Deterministic, instant, free, and completely blind. This node runs an inverse tone-mapping network over your frames instead, so the expansion is based on what real HDR looks like rather than on a formula. That's the whole value proposition, and it's a real one - a curve can't tell a sky from a piece of paper.
The flip side: "learned" means "opinionated." A model will happily give you a gorgeous sunset and a slightly crunchy forehead in the same clip. If your source has nasty compression or you need repeatable results, the curve node is the more honest tool.
How it works
Frames go through one at a time with a progress bar. Each frame is converted to BT.709 SDR in [0, 1], pushed through the loaded model in float32 on your GPU, and comes back as BT.2020 PQ. From there: decode PQ back to linear light (where 1.0 equals 100 nits), clamp to your peak_nits, and re-encode into whichever transfer curve you asked for. The model always predicts PQ; HLG is derived from it.
You get two outputs. images is the expanded tensor, tagged with its HDR color space so the pack's save nodes pick that up automatically. video is the same frames wrapped as a 10-bit video object, carrying over alpha, audio and frame rate. Feed both and images wins for pixels while video supplies alpha, audio and frame rate - documented, not a bug.
The inputs you'll actually touch
- model comes from Load SDR to HDR Model [Beta]. Run that node first; nothing else produces this type.
- images or video - one required. Same pixels either way, so use
videowhen you care about audio and timing. - peak_nits, default 1000. This is your display target, and it clips: the luminance ceiling is this value, so dropping it below 1000 chops off highlights the model produced. The tooltip is refreshingly direct about the default - HDRTVNet was trained on 1000-nit HDR10. If your panel does 600 nits, keep 1000 and let the display tone-map rather than pre-clipping your own highlights.
- color_space, default
HDR PQ. PQ (HDR10) for PC, phones, web and YouTube; theHDR(HLG) option is the broadcast TV curve. In HLG modepeak_nitsdoes something visibly different - it normalizes the scene into the HLG range instead of just acting as a ceiling.
The other three are marked advanced, and two of them are narrower than they look. condition_scale (4) is the downscale factor for the global condition image, and 4 is what HDRTVNet was trained with. Leave it. condition_smoothing is a temporal EMA across frames - the fix for brightness pumping in video - and it only works on the AGCM-family models: the end-to-end files (HDRTVDM_params*.pth, ITMLUT_params.pth) process each frame independently and return no condition at all. use_refine is likewise conditional: it applies the LE refinement net if one was loaded, so it matters with Ensemble_AGCM_LE.pth and does nothing otherwise.
Where it goes in the graph
Wire images into the pack's Save Image set to AVIF - it detects the HDR color space and writes proper CICP parameters for 10-bit output - or video into Save Video, which switches FFmpeg to 10-bit pixel formats and BT.2020/PQ/HLG tags automatically. Save a plain PNG or JPEG and the color-space tag is gone; the file looks flat and washed out and you spend an evening blaming the model. The container decides whether the HDR signal exists downstream - the same mechanism that governs workflow metadata in PNG chunks.
Install
ComfyUI Manager (search XENodes) or:
cd ComfyUI/custom_nodes
git clone https://github.com/xeinherjer-dev/ComfyUI-XENodes.git xenodes
Restart, then let the loader node pull its model into ComfyUI/models/sdr_to_hdr on first run. The pack installs essentially nothing - requirements.txt is empty and the only declared dependency is imageio-ffmpeg - but the video and AVIF savers want ffmpeg on your PATH, and AVIF metadata embedding uses exiftool.
Common issues
It's slower than you expect, and that's the architecture. One float32 forward pass per frame on your GPU - a 10-second 24fps clip is 240 passes, and the HDRTVDM files are Restormers. If you need speed over polish, ITMLUT_params.pth exists for this.
Output looks dull on your machine. Check the display before the graph. HDR viewed on an SDR screen, or in a player that ignores the tag, looks worse than the SDR original - which is what most people actually experience. Test with a known HDR file first.
The node is missing from the menu on an old ComfyUI - the pack needs a version that has comfy_api.latest. Update rather than fight it.
Inputs (10)
| Name | Type | Default | Description |
|---|---|---|---|
| model | XE_SDR2HDR_MODEL | Model from 'Load SDR to HDR Model [Beta]'. | |
| peak_nits | FLOAT | 1000100–10000 | Output luminance is clipped to this peak. HDRTVNet was trained on 1000-nit HDR10 content. |
| exposure | FLOAT | 0.0-3–3 | Exposure adjustment in EV stops applied in linear HDR space. +1.0 = twice as bright (+1 stop), -1.0 = half as bright. Default 0.0 = pure AI output. |
| lift | FLOAT | 0.000–0.5 | Shadow & midtone brightness lift (floor boost). 0.0 = off. Useful to raise dark or muddy scenes. |
| color_space | COMBO | HDR PQ | Target HDR color space. The model natively predicts PQ; HLG is derived from it. |
| condition_scale | INT | 41–16 | Downscale factor of the global condition image. HDRTVNet was trained with 4. |
| condition_smoothing | FLOAT | 0.000–0.99 | Temporal EMA of the global condition across frames to reduce brightness flicker in video. 0 = off. |
| use_refine | BOOLEAN | true | Apply the LE refinement model if one was loaded. |
| imagesopt | IMAGE | The SDR images or video frames to expand. | |
| videoopt | VIDEO | Optional: The SDR video to expand. |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| images | IMAGE | The expanded HDR images/frames [0, 1]. |
| video | VIDEO | The expanded HDR video (10-bit, compatible with SaveVideo). |