Latent Hybrid Upscale
Latent upscaling that protects edges instead of smearing them
- latent
- vae
- donor_latent
- latent
- edge_mask
Plain latent upscaling - the nearest/bilinear resize you get from ComfyUI's stock latent upscale node - is fast, but it doesn't know where your edges are. It'll happily smear a hard line between a subject and its background right along with the smooth gradients. Latent Hybrid Upscale (class WASLatentUpscaleHybrid) is WAS_Extras' answer: it decodes the latent, figures out where the real edges are, and uses that map to protect them while it upscales.
This is one of several nodes the pack's author, WASasquatch, has shipped since retiring the old WAS Node Suite (the sprawling original pack, archived June 2025 and now community-forked). WAS_Extras is the newer, smaller, still-actively-updated home for stuff like this - don't confuse the two if you're hunting for it in ComfyUI Manager.
How it works
The node decodes your latent to pixel space with the vae you feed it, then runs a Canny edge detector (via OpenCV, "if available" per the pack's own README) to build an edge mask - dilated and feathered so it's a soft band around edges rather than a hard line. That mask governs how the upscale blends: near edges it leans on the decoded image-space detail to avoid ringing and haloing; elsewhere it upscales the latent more freely. You can also hand it a donor_latent to blend in instead of relying purely on the computed scale. It has explicit handling for video latents too, with its own tiled-decode controls so a long clip doesn't blow your VRAM at the decode step.
The inputs and outputs that matter
latent,vae- required, the obvious two.scale(default 2, range 1–8) - the one knob you'll actually touch day to day.canny_threshold1/canny_threshold2/canny_l2gradient/pre_blur_sigma_px- tune how aggressively the edge detector fires. Leave at defaults until you see ringing or a mask that's obviously wrong.dilate_radius_px/feather_sigma_px/mask_min/mask_max- grow and soften the edge band, and clamp how strong its influence gets.use_nearest_exact- the resize kernel used away from edges.output_mask_resolution(imageorlatent) - whether the mask output matches your image size or your latent size.video_decode_*group (horizontal_tiles,vertical_tiles,overlap_latent,last_frame_fix,enable_cudnn) - only relevant when your latent is a video batch; these tile the decode step to keep it VRAM-safe.- Optional
donor_latent.
Outputs: latent (the upscaled result, wire straight into your next sampler or VAE decode) and edge_mask (a MASK you can preview to sanity-check what the node thought counted as an edge, or feed into a compositing step).
How to install it
Via ComfyUI Manager: search WAS_Extras, install, restart. Manually:
cd ComfyUI/custom_nodes
git clone https://github.com/WASasquatch/WAS_Extras
Then restart ComfyUI. None of the requirements-file dependencies the README mentions apply to this node - those are for a different file in the pack (the sampler sequencer). This one just needs OpenCV.
Common issues & troubleshooting
Edge mask looks blank or solid. The README is explicit that Canny detection depends on OpenCV being importable - if opencv-python isn't installed in ComfyUI's Python environment, run pip install opencv-python there. Otherwise, your canny_threshold1/canny_threshold2 pair is probably mismatched for your image's contrast; nudge them before assuming the node is broken.
You grabbed the wrong node from a shared workflow. WAS_Extras ships a second, related node - WAS Adaptive Difference Latent Upscale (Damped) - that does a similar-sounding but different job (damping the upscale delta near edges rather than Canny-masking in image space). If a downloaded workflow's behavior doesn't match what's described here, check you actually have WASLatentUpscaleHybrid and not its sibling.
VRAM spikes on video latents. The decode step for a batch of frames is where this bites. Reduce video_decode_horizontal_tiles/vertical_tiles, or increase overlap_latent only if you're seeing seams - it costs more VRAM, not less.
Ringing near hard edges at high scale. Back off dilate_radius_px or raise feather_sigma_px so the protected band is softer and wider rather than a hard cutout.
Inputs (19)
| Name | Type | Default | Description |
|---|---|---|---|
| latent | LATENT | — | |
| vae | VAE | — | |
| scale | FLOAT | 2.001–8 | — |
| pre_blur_sigma_px | FLOAT | 1.000–20 | — |
| canny_threshold1 | INT | 250–1000 | — |
| canny_threshold2 | INT | 1550–1000 | — |
| canny_l2gradient | BOOLEAN | true | — |
| dilate_radius_px | INT | 80–64 | — |
| feather_sigma_px | FLOAT | 6.000–50 | — |
| mask_min | FLOAT | 0.000–1 | — |
| mask_max | FLOAT | 1.000–1 | — |
| use_nearest_exact | BOOLEAN | true | — |
| output_mask_resolution | COMBO | image | 2 options: image, latent |
| video_decode_horizontal_tiles | INT | 21–8 | — |
| video_decode_vertical_tiles | INT | 21–8 | — |
| video_decode_overlap_latent | INT | 40–32 | — |
| video_decode_last_frame_fix | BOOLEAN | false | — |
| video_decode_enable_cudnn | BOOLEAN | true | — |
| donor_latentopt | LATENT | — |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| latent | LATENT | — |
| edge_mask | MASK | — |