cv2.scaleAdd
Alpha×A + B, and Why the Default alpha of 0 Looks Broken
- src1
- src2
- result
cv2.scaleAdd does one line of arithmetic: dst = alpha*src1 + src2. That's it. No model, no kernel, no magic - just the two-term linear combine that shows up constantly once you stop thinking only in terms of generation and start matching plates, subtracting backgrounds, or building a frame from parts.
You'd reach for it when only one of the two inputs needs a coefficient: subtract a dark frame scaled by some factor, add a dimmed copy of a previous frame for an echo/ghost trail, tint one layer of a composite before summing, add a flat offset derived from a measured level. Its sibling cv2.addWeighted gives you two free weights and is the better tool for a crossfade; scaleAdd is the case where one side is plain.
Inputs and outputs that matter
Three inputs, and the batch handling is the reason this node is nicer than a generic math node:
src1- the primary input, and the one that determines the output's type. IMAGE in, IMAGE out; MASK in, MASK out; NPARRAY in, NPARRAY out. It's a MatchType socket, like core's Resize.alpha- the scale factor onsrc1. It defaults to 0. A brand-new node therefore returnssrc2untouched and looks like it's doing nothing at all. Set this first, before you go hunting for the bug.src2- the second array, same size and type assrc1.
Both image inputs accept a full IMAGE or MASK batch, and when both sides carry the same batch size the whole batch is processed together rather than silently collapsing to frame 0 - which is how you want a per-frame exposure match or a video-scale accumulation to behave.
One output: result, echoing src1's format. No bridge nodes, no manual CV Array → Image conversion - that's the convenience of these type-preserving wrappers.
How it works, and the one real trap
Underneath it's OpenCV element-wise arithmetic with saturate-cast into the output type. If your inputs are uint8 - which is what an IMAGE link resolves to when it enters the low-level nodes - then the result is clipped to 0..255 and the fraction gets rounded away. Multiply by 0.5 and you lose low-order detail; multiply by 2 and everything bright blows out to white. Negative values clamp to 0 rather than wrapping, which is at least predictable.
So the trap is the boring one: decide what headroom you need before this node, not after. If the arithmetic must stay signed or fractional, work in float space - send the images through Image → CV Array with float32 (0-1) and do the combine there, or cast an existing array with CV Cast Array.
The second, smaller trap is alpha's default again: 0 is a legitimate OpenCV default for a general linear-combination function, but in node form it reads as "this node is broken." It isn't. Type a number.
Install
Manager → search ComfyUI CV, or from a shell:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart ComfyUI afterwards. This pack needs Python ≥ 3.12 and a ComfyUI recent enough to ship the V3 node API - an older install will fail to register the nodes rather than degrade gracefully.
Where people get burned
The shared site-packages/cv2. opencv-python, opencv-python-headless and their contrib counterparts all install into the same place. Put a non-contrib wheel on top of the contrib one and the shared binary quietly becomes core-only; contrib-backed nodes then vanish from the node menu with no error message in the log. tools/repair_opencv_contrib.py --check diagnoses it, --apply repairs it. This is the single most common way to break the pack.
Mismatched batch sizes. The full-batch path only engages when both inputs have the same batch size; otherwise you fall back to single-frame behaviour and get one output frame where you expected twelve. Check your batches before you blame the math.
Assuming it's a blend mode. alpha*src1 + src2 has no alpha channel semantics and no mask. If you want "blend these two with a mask," that's a masked composite, not arithmetic.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| src1 | COMFY_MATCHTYPE_V3 | first input array. The image output(s) echo this input's format. 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. | |
| alpha | FLOAT | 0.0000-1e+38–1e+38 | scale factor for the first array. |
| src2 | NPARRAY,IMAGE,MASK | second input array of the same size and type as src1. 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. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| result | COMFY_MATCHTYPE_V3 | Echoes the 'src1' input's format: an IMAGE link comes back as IMAGE, MASK as MASK, NPARRAY stays NPARRAY. |