Nodes/ComfyUI CV/cv2.boxFilter
ComfyUI Node

cv2.boxFilter

The same blur as cv2.blur, plus the option to *sum* instead of average

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.boxFilter
  • src
  • ksize
  • anchor
  • result
◄ddepthsame as input►
◄normalizetrue►
◄borderTypeBORDER_DEFAULT►

With normalize left on, cv2.boxFilter is literally the same operation as cv2.blur: the mean of a rectangular window. So why does the node exist in your menu? Because of the two switches cv2.blur doesn't have - turn normalization off and you get the windowed sum, and the ddepth dropdown lets that sum live in a wider type than the input. That's not a blur any more. That's a local-accumulation primitive, and it's cheap.

It ships in comfyui_cv, the pack that wraps ~470 raw cv2.* functions (forked from geroldmeisinger's opencv-comfyui, rewritten on ComfyUI's V3 node API). One caveat the author states himself: the pack is heavily LLM-assisted and the raw wrappers are uncurated - you're getting the OpenCV call with ComfyUI sockets, so the OpenCV docs are your second reference.

How it works

A box filter is a sliding-window sum over a (w, h) rectangle, separable and implemented with an integral image, so it's constant-time in kernel size. One pass over the image precomputes prefix sums; every window after that is four adds. A 101×101 box filter on a 4K frame costs about the same as a 3×3.

Normalized (default), each window is divided by its area - a mean, i.e. a box blur, and the reason it's O(1) is also the reason it looks slightly hazy and boxy compared to a Gaussian. Unnormalized, you get the raw sum, and a 5×5 window over 8-bit pixels can reach 25×255 = 6375 - which overflows uint8 and wraps. That's the entire story of this node's ddepth dropdown.

Inputs and outputs

src decides the output format: it's a match type, so IMAGE in → IMAGE out, MASK in → MASK out, NPARRAY stays NPARRAY (and a LATENT is processed in latent space, frame 0 as a float32 [H,W,C] array with values untouched).

  • src (required) - the input.
  • ddepth (required, default "same as input") - the output depth. Options run same as input, CV_8U, CV_8S, CV_16U, CV_16S, CV_32S, CV_32F, CV_64F; "same as input" maps to OpenCV's -1. This is the field you must change when you switch normalization off - a wide type means your sums don't wrap. CV_32F is the usual pick.
  • ksize (required, default (0,0)) - one composite CV_TUPLE, (w, h). Type it in the widget or drive it from CV Tuple. Zero is not a valid kernel.
  • anchor (optional, default (-1,-1)) - kernel center. Leave it.
  • normalize (optional, default true) - divide by the window area, or don't.
  • borderType (optional, default BORDER_DEFAULT) - how pixels outside the frame are extrapolated; the author's tooltip notes BORDER_WRAP isn't supported.

One output, result, echoing src's format.

What each mode is good for

Normalized is mask feathering and cheap softening - see post-processing for why a blur is also the base layer of an unsharp mask (blur a copy, subtract, add the difference back scaled; "sharpen" is never anything more than that). It's also the fastest big-radius smear you have, which is what makes it good enough for a glow pass if you don't want to pay for a Gaussian.

Unnormalized with a float depth is the interesting one: a local density map. Box a bright mask and you get "how much bright stuff is in this neighbourhood", which is a one-node background estimate or a poor man's adaptive threshold. Big windows are free, so this is a genuinely fast way to get a coarse heat map of where things are in a frame - then send it to Preview CV Array in heatmap mode.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv

Restart, or Manager → search "comfyui_cv". Python ≥ 3.12, recent ComfyUI on the V3 node API, and the pack's single real dependency:

pip install "opencv-contrib-python-headless~=5.0.0.93"

Installing a non-contrib opencv-python wheel on top of that silently empties the shared cv2 and the contrib nodes disappear; tools/repair_opencv_contrib.py in the pack diagnoses and repairs it. No models needed.

Common issues

The image looks like a psychedelic mess. You turned normalize off and left ddepth on "same as input", so your windowed sums are wrapping around inside uint8. Set ddepth to CV_32F.

Everything is black. Either ksize is (0,0) (which OpenCV rejects with an assertion rather than a black image, so this is less likely than it sounds) or you set a wide ddepth and something downstream is treating the float array as an image. A CV_32F array with values in the thousands is not displayable - normalize it, or threshold it.

The blur is lopsided. ksize is (w, h); swap the numbers.

It's identical to cv2.blur and you feel cheated. It is, default for default. The difference is the two options above, and if you don't need them, cv2.blur (or the pack's cv2.GaussianBlur) is the friendlier-looking node.

Categoryimage/CV/low-level/cv2 B

Inputs (6)

NameTypeDefaultDescription
srcCOMFY_MATCHTYPE_V3input image. 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.
ddepthCOMBOsame as inputthe output image depth (-1 to use src.depth()).
ksizeCV_TUPLE0,0blurring kernel size. 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.
anchoroptCV_TUPLE-1,-1anchor point; default value Point(-1,-1) means that the anchor is at the kernel center. One value with 2 components (x, y) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place.
normalizeoptBOOLEANtrueflag, specifying whether the kernel is normalized by its area or not. Preset to the OpenCV default (True).
borderTypeoptCOMBOBORDER_DEFAULTborder mode used to extrapolate pixels outside of the image, see #BorderTypes. #BORDER_WRAP is not supported.

Outputs (1)

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