Nodes/ComfyUI-BCNodes/SeedVR2 Resize
ComfyUI Node

SeedVR2 Resize

SeedVR2 Resize — The Input Stage ComfyUI's Own Scale Nodes Can't Reproduce

By 0xBeycan·Created 23 days ago·Updated 3 days ago· 2
SeedVR2 Resize
  • image
  • image
  • reference
◄upscale_factor2.00►
◄downscale_factor0.50►
◄max_resolution4096►
◄emulate_bf16true►

What it is

SeedVR2 won the upscaling argument - not loudly, just by being the thing everyone reaches for when an image is soft rather than small. It's a one-step video restoration model that turned out to be exceptionally good at single frames, and it preserves detail instead of resynthesising a new face on top of yours.

Like most of these models it has an awkward input requirement, and ComfyUI's stock scale nodes can't hit it exactly. That's what this node is: the whole input stage of a SeedVR2 graph - downscale, resize, clamp, pad - in one step, with two outputs that go to two different places. It replaces a chain of nodes you'd otherwise assemble by hand and get subtly wrong.

How it works

The order matters, and it's not the order you'd guess:

  1. Lanczos downscale by downscale_factor (default 0.5; 1 is none). This matches ImageScaleBy(lanczos) exactly - PIL LANCZOS on 8-bit.
  2. Shortest-edge resize to original shortest edge × upscale_factor. This is the part you can't copy with core nodes: it's torchvision's resize with the shortest edge at that resolution, BICUBIC with antialias. ComfyUI's own bicubic is F.interpolate without antialias - a different kernel - and Resize Image rounds the long edge, so neither reproduces it.
  3. Cap - if the longest edge then exceeds max_resolution (default 4096, 0 = no cap), a second resize scales it down to fit.
  4. Clamp to [0, 1], pad to a multiple of 16, and pad the frame count to 4n+1 by repeating the last frame. Both of those are VAE requirements, not aesthetic choices.

Two outputs, and wiring them wrong is the classic mistake here:

  • image - the frames the VAE will encode. Downscaled, resized, clamped, padded, stored as float16 (the VAE encode casts to float16 anyway). Goes to SeedVR2 VAE Encode for video, or VAE Encode (Tiled) for a single image.
  • reference - the colour-correction reference: the same frames resized in float32, stored as float16, cropped to even dimensions, not padded, original frame count. Goes to SeedVR2 PostProcess's original_resized_images.

The reason for a separate reference output at all is that SeedVR2 lifts contrast enough that some people find its output reads as more AI-generated than the input. reference is what the post-process node colour-matches against to pull that back.

Why the downscale default is 0.5

It looks like a mistake and it isn't. The standing community advice for soft or damaged sources is to bring the input down to roughly 0.35 megapixels before upscaling, because when a source is soft rather than small there's no detail at full resolution to recover - you reduce it to match its actual sharpness and let the model rebuild from there. downscale_factor at 0.5 is that idea, built into the input stage.

If your source is genuinely sharp and clean, set it to 1 and see whether the result is better. If it's soft, blurry or compressed, leave it alone.

Install

Manager: search ComfyUI-BCNodes, install, restart. Manual:

cd ComfyUI/custom_nodes
git clone https://github.com/0xBeycan/ComfyUI-BCNodes

No pip install for this node - the pack's requirements.txt (postfx, caption-audit) belongs to two unrelated nodes, and the SeedVR2 VAE and DiT come from the SeedVR2 model side, not from here. Search BCNodes in the node library; these four sit under BCNodes/seedvr2.

Where people get burned

The frame count changes. Padding to 4n+1 adds frames by repeating the last one. Anything downstream that counts frames - a duration, an audio sync, an assumption that output length equals input length - is now off by up to three frames. Don't count frames after this node.

upscale_factor is measured against the original, not the downscaled image. It's the resize resolution computed from the source's shortest edge. People read "2" as "twice what came out of the downscale" and end up with the wrong size in their head, then blame the node for a resolution they didn't expect.

emulate_bf16 changes the pixels. With CUDA available it does the resize in bfloat16 on the GPU, which is what the SeedVR2 pipeline does - so results differ very slightly from a pure float32 resize. If you're chasing a parity test against the native graph, that's the knob; for normal work, leave it on.

Watch your VRAM, not here, downstream. SeedVR2's OOM reputation is real and mostly earned at the decode end, but this node is where you set the size that decides it. Frames go through the GPU four at a time here, so a long clip survives the resize and then dies at the VAE - which is what the pack's other three SeedVR2 nodes exist to prevent.

CategoryBCNodes/seedvr2

Inputs (5)

NameTypeDefaultDescription
imageIMAGE—
upscale_factorFLOAT2.000.01–16Shortest edge of the output = shortest edge of the input × this (the resize resolution, computed from the original image).
downscale_factorFLOAT0.500.01–1Lanczos downscale applied first, like ImageScaleBy(lanczos). 1 = none.
max_resolutionINT40960–16384Cap on the longest edge, 0 = none.
emulate_bf16BOOLEANtrueResize `image` in bfloat16 on the GPU when CUDA is available. Without CUDA the resize runs in float32.

Outputs (2)

NameTypeDescription
imageIMAGEThe frames the VAE encodes: downscaled, resized, clamped, padded to a multiple of 16 and to 4n+1 frames, float16. Wire to VAE Encode.
referenceIMAGEThe colour-correction reference: float32 resize stored as float16, cropped to even, not padded. Wire to SeedVR2 PostProcess.