Nodes/ComfyUI CV/cv2.stackBlur
ComfyUI Node

cv2.stackBlur

Gaussian-looking blur at box-blur speed (and it eats LATENTs)

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
cv2.stackBlur
  • src
  • ksize
  • result

Stack blur is the blur you use when the radius is large and you don't want to pay for it. Instead of multiplying a big Gaussian kernel over the image, it runs a stack of moving averages - the result is a smooth, Gaussian-ish falloff with a triangular core, and the cost per pixel barely moves as the radius grows. On a 41-pixel radius, that difference is the difference between a snappy graph and a coffee break.

In this pack it also happens to be one of the few nodes that will take a LATENT link, which is more interesting than it sounds.

Inputs and outputs

src is the whole story, and it's a type-preserving socket: link an IMAGE and you get an IMAGE back, a MASK comes back a MASK, an NPARRAY stays an NPARRAY. No conversion node on either side. It also accepts a full LATENT - frame 0 is read as a float32 [H, W, C] array with the values untouched, blurred, and handed back as a LATENT. No 0..255 round trip, no quantisation. That's rare here and genuinely useful: a light latent-space blur before decode softens detail and knocks down speckle in a way that doesn't touch your pixel pipeline.

ksize is one (w, h) value - type it in the box or wire it from a CV Tuple node, which is the way to set it when you want the same radius driving three nodes. The two axes can differ, but both must be positive and odd; the tooltip says so and so does OpenCV's error message. The default widget is (0, 0), which is not a kernel, so set it before you run.

Batched IMAGE/MASK inputs are looped frame by frame and re-stacked. A LATENT batch is not batched: you get frame 0, on purpose, because a spatial filter has no meaning across a 4-D [B, C, H, W] tensor.

What it's actually for

Two jobs. First, softening: it's the cheap alternative to a Gaussian wherever the exact kernel doesn't matter - background plates, glow passes, defocus-ish look for composites, smoothing a denoised plate before you diff against it. The pack's denoise playground (09_denoise_playground.json) puts it next to median, Gaussian, bilateral and NL-means on the same noisy photo, and feeding it straight from a Gaussian blur's output, which tells you the author treats the two as substitutes.

Second, and the one I'd reach for it for in a mixing graph: mask feathering. Link a MASK, get a MASK back, and a hard binary mask becomes a soft gradient edge you can hand to an inpaint or composite step. Blurring a mask is the cheapest way to stop visible seams, and this node does it without either a conversion pair or a Gaussian's sigma arithmetic.

Installing it

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
cd comfyui_cv && pip install "opencv-contrib-python-headless~=5.0.0.93"

Or Manager → search ComfyUI CV → install → restart. Python ≥ 3.12 plus a ComfyUI recent enough to have the V3 node API; without those the pack's nodes don't appear at all. The OpenCV build has to be contrib - every distribution shares one site-packages/cv2, so a stray pip install opencv-python empties the contrib submodules (the pack ships tools/repair_opencv_contrib.py, --check then --apply). Curated against 5.0.0.93.

Where people get burned

An even number in ksize throws (-215) ... must be positive and odd. Leaving it at (0, 0) throws too. And the ergonomic one: people convert IMAGE → NPARRAY out of habit and then convert back, when this node would have taken the IMAGE directly - that's what the "echoes the src input's format" note means, and it's a general pattern for a dozen wrappers in this pack.

One more honest note on the pack itself: these wrappers are auto-generated and the author states they're LLM-written, uncurated, and not to be trusted in production without reading the source. Upstream OpenCV 5.0 documentation is the reference for the underlying algorithm.

Categoryimage/CV/low-level/cv2 S

Inputs (2)

NameTypeDefaultDescription
srcCOMFY_MATCHTYPE_V3input image. The number of channels can be arbitrary, but the depth should be one of CV_8U, CV_16U, CV_16S or CV_32F. The image output(s) echo this input's format. A LATENT link is processed in latent space: frame 0 becomes a float32 [H,W,C] array (any channel count), values untouched. Arithmetic ops (add, multiply, etc.) also accept a full LATENT batch ({samples: [B,C,H,W]}) — the whole batch flows through when both inputs have the same batch size. Accepts a ComfyUI IMAGE/MASK directly (frame 0 of a batch) or an NPARRAY. Arithmetic ops (add, multiply, etc.) process the full IMAGE batch when both inputs have the same batch size.
ksizeCV_TUPLE0,0stack-blurring kernel size. The ksize.width and ksize.height can differ but they both must be positive and odd. One value with 2 components (w, h) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place.

Outputs (1)

NameTypeDescription
resultCOMFY_MATCHTYPE_V3Echoes the 'src' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY.