Nodes/ComfyUI-BCNodes/SeedVR2 PostProcess
ComfyUI Node

SeedVR2 PostProcess

SeedVR2 PostProcess — The Colour Match That Stops Upscales Looking 'More AI'

By 0xBeycan·Created 23 days ago·Updated 3 days ago· 2
SeedVR2 PostProcess
  • images
  • original_resized_images
  • images
◄color_correction_methodlab►

Why this stage exists at all

SeedVR2 preserves detail rather than inventing it, which is why it beat everything else for restoration work. Its one consistent complaint doesn't come from the model - it comes from one step downstream: it lifts contrast, enough that some users find the output reads as more AI-generated than the input did. The standing community verdict on a disappointing SeedVR2 result is to ask which quant you ran; the second question is whether the colour correction ran at all.

This node is that correction, plus the alignment housekeeping that goes with it. Its job is to line the generated frames up with the original reference and transfer the colour statistics back, so the upscale keeps its added detail without keeping the contrast drift.

How it works

Wire images - what came out of BC_SeedVR2VAEDecode - and original_resized_images - the reference output from BC_SeedVR2Resize. The node then does, in this order: crop the frames to the reference's frame count and size, x × 2 − 1, run the colour transfer on the VAE device, (x + 1) / 2 clamp, take alpha from the reference, and crop to even dimensions.

The colour maths is the same code the native Post-Process SeedVR2 Output node uses, from comfy/ldm/seedvr/color_fix.py, and it stays float32 per frame. color_correction_method picks the transfer: lab (the default), wavelet, adain, or none for no correction at all.

What differs from the native node is only memory. The stock node builds five full-size float32 copies of the clip as it goes - the range conversion, the flattening reshape, the result buffer, and the add/div/clamp chain - and that is what runs a 30-second 1080p clip out of RAM. This one performs the same operations in the same order, one frame at a time, into a single preallocated float16 output. The parity test checks every method against the native node: equal after rounding to float16, maximum difference 2.4e-4 - a sixteenth of an 8-bit step.

One output: images, float16, aligned and corrected.

Choosing a method

Leave it on lab. It's the default, it's what the native node defaults to, and it's the one people compare against when they say a SeedVR2 result looks clean. wavelet and adain are alternatives worth a single A/B on a clip you care about - wavelet in particular is the one to try when a piece of footage has a strong colour cast you'd rather not have averaged away.

none is not a neutral choice. It means no correction, which means you keep SeedVR2's contrast lift as-is. That's the right call if you're doing your own grade downstream with a colour-match or a LUT anyway, and the wrong call if you're wondering why your upscale looks punchier than the original.

Install

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

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

No pip install needed here - the pack's requirements.txt (postfx, caption-audit) only backs the PostFx and Caption Audit nodes. Find it under BCNodes/seedvr2 by typing BCNodes in the node library.

Where people get burned

The reference has to be the same clip. The node crops the generated frames to the reference's frame count and size, so a reference from a different source - a different length, a different crop - silently truncates your output to whatever the reference was. This is why BC_SeedVR2Resize emits reference separately for exactly this socket rather than making you rebuild it.

This is where the padding gets undone, and that's a feature. The resize stage padded frames to a multiple of 16 and the count to 4n+1 because the VAE needs it; the alignment here crops back to the reference's real proportions. So the frame count you get out is not the frame count the decode gave you, and it is the frame count you put in at the top. Count your frames here, not in the middle of the pipeline.

Don't add a colour-match node after it. You've already done the statistics transfer, once, with the reference the model actually saw. A second colour match degrades the result - this is the classic "fix it again" loop that turns a good upscale muddy.

Run the parity test if you're porting a workflow. tests/parity_seedvr2_video.py covers every method against the native node; if you're swapping this in mid-pipeline on a project you've already rendered, that's the cheap way to confirm you got the same picture.

CategoryBCNodes/seedvr2

Inputs (3)

NameTypeDefaultDescription
imagesIMAGEThe generated frames.
original_resized_imagesIMAGEThe reference frames (SeedVR2 Resize `reference`).
color_correction_methodCOMBOlab4 options: lab, wavelet, adain, none

Outputs (1)

NameTypeDescription
imagesIMAGEAligned, colour-corrected frames, float16.