Nodes/ComfyUI CV/cv2.broadcast
ComfyUI Node

cv2.broadcast

Stretch one value into a full array — without copying a byte

By bmad4ever·Created 4 months ago·Updated 15 days ago· 1
cv2.broadcast
  • src
  • shape
  • nparray

cv2.broadcast takes a small array and pretends it's a big one, by repeating it along the new dimensions with zero strides. No memory is allocated for the repeated part: the same handful of values is read over and over as if it filled the frame. Numpy users know this as broadcasting; OpenCV's version here produces a matrix that behaves like the expanded shape and shares its storage with the original.

It comes from comfyui_cv, the pack that exposes ~470 cv2.* functions as ComfyUI nodes. This one is squarely in the plumbing layer - it moves data shapes around and computes nothing.

What it's for

Two things, and the first is the reason it exists in a graph at all.

Filling a buffer socket. Several of the pack's raw wrappers declare parameters that OpenCV treats as caller-allocated outputs - flow in cv2.calcOpticalFlowFarneback, nextPts in cv2.calcOpticalFlowPyrLK, mean in cv2.calcCovarMatrix, the shape argument you're looking at right here. Those sockets are required NPARRAY inputs, and the schema can't magic them out of thin air: you have to hand the node an array of the right shape, even when the function is only going to overwrite it. cv2.broadcast is one of the cheap ways to produce one - and it's how you size a scratch array without allocating a real one.

Building a constant field. cv2.compare, bitwise_* and friends want a same-size second operand. Where another pack would make you duplicate a frame or use a scalar node, you can broadcast a single pixel to [H, W, C] and get a per-pixel constant array you can compare against, threshold with, or subtract.

Inputs and outputs

  • src (required) - the small array. Accepts an NPARRAY directly, or an IMAGE / MASK (frame 0 of a batch, converted to a plain uint8 array on the way in).
  • shape (required) - the target shape, and it's an NPARRAY, not a string or a tuple: a vector of dimension lengths. That's the odd-but-consistent choice you'll see all over this pack, where anything cv2 calls a "matrix or vector" is a data array rather than a widget. The practical source is the CV Tuple node, whose array output is exactly this - a numeric vector on an NPARRAY socket.

Output is a single nparray. It's not type-preserving, so a MASK you fed in does not come back as a MASK; it comes back as an array, which is either exactly what you wanted (you're doing array maths) or one CV Array → Mask away from what you wanted.

The zero-stride thing is the whole caveat

Because the output is a view rather than a copy, there is no memory cost to "expanding" one pixel to 4000×4000 - and there's no isolation either. A zero-stride array shares every repeated element with the single source value. In a ComfyUI graph, where arrays flow through cv2 calls that read them, that's usually invisible; it is not invisible if something downstream writes into the array, in which case changing one pixel changes all of them, and changing the source changes the whole field.

The pack flags this sensibility itself - it ships a node literally called CV ZeroStride Like, described as an advanced/diagnostic zero-stride broadcast helper. If you're debugging a broadcast that mysteriously changes when an unrelated upstream value moves, that's your explanation.

Install

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

Restart, or ComfyUI Manager → search "comfyui_cv". Requires Python ≥ 3.12, a recent ComfyUI on the V3 node API, and:

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

cv2.broadcast is a 5.x-era entry point, so an older build is a plausible reason for this specific node to be missing while the rest of the pack loads fine.

Common issues

The node isn't in the menu. It's generated at import time from what your installed OpenCV exposes, and entries the build lacks are skipped silently. Check your cv2 version and that you're on the contrib wheel.

"Shape mismatch" or a cv2 assertion. The dimensions you're broadcasting to have to be compatible with src - you can stretch length-1 axes, not invent new data. [H, W, C] from a 1×1×C source works; from an [H, W] source it doesn't.

Nothing connects to shape. You tried to wire an INT or a tuple. It's NPARRAY-only; put a CV Tuple in front of it and take the array output.

The downstream node produces garbage. Very likely a dtype problem rather than a shape one - broadcasting an uint8 array into a float32 consumer (or the reverse) doesn't convert anything, and cv2 will either complain or truncate quietly. CV Scalar lets you choose the element type when you're constructing the source values.

Categoryimage/CV/low-level/cv2 B

Inputs (2)

NameTypeDefaultDescription
srcNPARRAY,IMAGE,MASK - - - 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.
shapeNPARRAY - - - A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.

Outputs (1)

NameTypeDescription
nparrayNPARRAY—