cv2.addWeighted
Crossfade, sharpen, and composite with one node
- src1
- src2
- result
out = α·src1 + β·src2 + γ, saturating. Five numbers and two images, and you've just built a crossfade, an unsharp mask, an exposure-and-contrast adjustment, and a premultiplied alpha composite.
This is the node used most often in the pack's own example workflows - it shows up in roughly forty of them, from frame interpolation to denoise playgrounds - and it's the one I'd point a beginner at first, because a single well-chosen pair of weights replaces a surprising amount of guesswork.
How it works
Each input is scaled by its weight, the two are added, and gamma is added to the sum before the saturating cast. Order doesn't matter for the arithmetic; the saturation at both ends of the range is what keeps you out of wraparound territory.
As always with these wrappers: an IMAGE link arrives as uint8 BGR, 0–255. So contrast lives in α/β (multipliers) and brightness lives in γ (additive offset). On an IMAGE that's a 0–255 world - the pack's own examples mix a rotation back in at 0.7 / 0.3, and luma-style blends around 1.2 for contrast plus a +10-ish gamma are the classic knobs.
LATENT is supported, values untouched, and the whole-batch path works - so you can blend two latent batches at 0.7/0.3 with no quantization.
Inputs and outputs
src1(COMFY_MATCHTYPE_V3) - first array; decides the echoed output format.alpha(FLOAT) - weight ofsrc1.src2(NPARRAY,IMAGE,MASK,LATENT) - second array, same size and channel count.beta(FLOAT) - weight ofsrc2.gamma(FLOAT) - constant added to the sum.dtype(optional) - output depth (same as inputkeepssrc1's).- result - echoes
src1's format.
All three numeric widgets default to 0. α=β=0 means a black image (γ=0 too, so literally zeros). That's the number-one "why is my image black" in this node. Put real values in before you debug anything else.
Recipes worth memorising
- Crossfade / dissolve:
α + β = 1- e.g. 0.7 / 0.3. Keep the sum at 1 or you change the brightness as well as the mixture. - Unsharp mask:
addWeighted(sharp, 1 + a, blur, −a, 0). α above 1, negative β, and the difference between the two images is added back scaled. Radius is set by the blur you made (cv2_GaussianBlur), amount bya. The pack ships this as a CV Sharpen subgraph. - Exposure and contrast:
addWeighted(img, 1.2, black_or_img2, 0, 10)- multiply for contrast, gamma for brightness. Negative gamma is a legitimate way to darken; the saturating cast clips at 0 rather than wrapping. - Premultiplied composite: scale the foreground's colour channels by the matte, the background by (1 − matte), then add. Two
cv2_multiplycalls and oneaddWeighted, or the pack's curated blend nodes if you'd rather not hand-roll it. - Signed-difference visualisation:
absdiffoutput plus γ = 128 lifts the difference into mid-grey so you can see both polarities.
Install
ComfyUI Manager → comfyui_cv (ComfyUI CV), or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Restart ComfyUI. Python ≥ 3.12 and a recent ComfyUI built on the V3 node API; behaviour is curated against OpenCV 5.0.0.93. The contrib wheel is the declared dependency - a plain opencv-python installed over it silently strips the contrib submodules and hides nodes.
Where people get burned
Zeros. Covered above; it's the trap this node sets.
Mismatched sizes. src2 must be the same size and channel count as src1. Resize first (cv2_resize or the curated CV Transform) - this is the most common error with mixed-resolution sources.
Scalars only. α and β are single numbers, not per-channel or per-pixel. If you want a spatially varying blend you want a weight map: cv2_blendLinear takes weights1/weights2, and the pack's Multi-Band Blend and Feather Blend subgraphs exist for exactly that.
Brightness drift in a crossfade. If α + β ≠ 1 you're changing exposure while you blend, and it reads as a flash. It's a feature for fades to black (β = 0), a bug for tweens.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| src1 | COMFY_MATCHTYPE_V3 | first input array. 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. | |
| alpha | FLOAT | 0.0000-1e+38–1e+38 | weight of the first array elements. |
| src2 | NPARRAY,IMAGE,MASK,LATENT | second input array of the same size and channel number as src1. 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. | |
| beta | FLOAT | 0.0000-1e+38–1e+38 | weight of the second array elements. |
| gamma | FLOAT | 0.0000-1e+38–1e+38 | scalar added to each sum. |
| dtypeopt | COMBO | same as input | optional depth of the output array; when both input arrays have the same depth, dtype can be set to -1, which will be equivalent to src1.depth(). |
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. |