cv2.gemm
Actual matrix multiplication inside a ComfyUI graph
- src1
- src2
- src3
- nparray
cv2.gemm is the general matrix multiply: alpha * src1 @ src2 + beta * src3. Wired up in ComfyUI it's the node that lets a graph do linear algebra - compose a chain of camera transforms into one matrix, build a weighted sum of two systems, check that a decomposition you just ran actually reconstructs what you started with. There is no prompt, no pixel, no model. It's numpy in a trench coat, and ComfyUI has surprisingly little of that.
It's a data node, not an image node
This is worth stating before anything else, because the sockets are unforgiving: src1, src2 and src3 are NPARRAY only. No IMAGE, no MASK, no LATENT - the tooltips say "a data array (points / matrix), NOT an image". If you have pictures and want them multiplied you're in the wrong node; the pack's own CV MatMul (left @ right) is the friendlier curated wrapper for a plain product.
Everything this node touches comes pre-shaped from elsewhere in the pack's geometry and calibration families: CV Parse Matrix, CV Pose to Matrix, the various estimateAffine* nodes and getDerivKernels all emit NPARRAY matrices. This is where you combine them.
The inputs
src1,src2,src3,alpha,betaare all required, andsrc3being required is a mild annoyance: if you only wantsrc1 @ src2, feed it anything of the right type and setbetato 0.alpha- weight of the matrix product.beta- weight ofsrc3.flags- a dropdown with one toggle per transpose flag:GEMM_1_T,GEMM_2_T,GEMM_3_T, pipe-joined in the string (none (0) | GEMM_2_T). Transposingsrc1is how you computeAᵀAorAᵀbwithout a separate transpose node, which is the shape most least-squares work ends up in. The UI renders these as checkboxes; the underlying value stays a string, so it survives in saved workflows and API calls either way.
One output, nparray - the product, same type as the inputs.
Watch the defaults
The widgets open at alpha = 0 and beta = 0. Neither is what you want. Multiply anything by zero and you get a matrix of zeros that travels happily downstream to something that then produces zeros, or a black image, or a pose of nothing - no error, no warning. Set alpha to 1.
The type rule is cv2's: both inputs must share a type, real (CV_32FC1, CV_64FC1) or complex (CV_32FC2, CV_64FC2), and src3 must match. A float32 against a float64 will raise at execution, not at wiring time.
If you need the flags but not the multiply, the pack ships CV GEMM Flags as a standalone authoring node for exactly that string.
Install
Manager → search 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, recent ComfyUI on the V3 node API. This is a plain core-cv2 wrapper with no models and no extra dependencies.
Where people get burned
- The zeros-from-zero-alpha thing above. It's the single most common result of wiring this node.
- Shape mismatch:
gemmdoesn't broadcast.(3,4) @ (3,4)is an error,(3,4) @ (4,3)is a 3×3. If you're used to numpy's convenience this will feel strict, because it is. - These constant-node results cache. An NPARRAY computed from fixed inputs is computed once and then reused across runs - that's ComfyUI's graph caching doing its job, and a node that never declares itself changed will keep serving the old value. If you changed a widget and nothing moved, check you actually changed an upstream value rather than just pressing Run again.
- To see what came out, wire it to
Inspect CV Data(prints shape/dtype/values) orPreview CV Array- a matrix is not a picture, and dropping it on a preview node generally shows you a useless normalised thumbnail.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| src1 | NPARRAY | first multiplied input matrix that could be real(CV_32FC1, CV_64FC1) or complex(CV_32FC2, CV_64FC2). A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| src2 | NPARRAY | second multiplied input matrix of the same type as src1. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| alpha | FLOAT | 0.0000-1e+38–1e+38 | weight of the matrix product. |
| src3 | NPARRAY | third optional delta matrix added to the matrix product; it should have the same type as src1 and src2. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| beta | FLOAT | 0.0000-1e+38–1e+38 | weight of src3. |
| flagsopt | STRING | none (0) | operation flags (cv::GemmFlags) cv2.gemm flags: one of none (0) plus any of GEMM_1_T, GEMM_2_T, GEMM_3_T, pipe-joined (e.g. "none (0) | GEMM_1_T"). In the UI this renders as a dropdown with one toggle per flag. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| nparray | NPARRAY | — |