cv2.solve
Solving Ax = B Inside Your ComfyUI Graph
- src1
- src2
- bool
- nparray
Sooner or later a geometry workflow stops being "apply this transform" and becomes "find the transform". Fitting a plane to 3D points, recovering a homography-like map from matched correspondences, solving for camera parameters, blending weights under constraints - they all reduce to a linear system A·X = B. cv2.solve is the general-purpose solver, and it's exposed here as a node in ComfyUI CV (bmad4ever/comfyui_cv).
The reason to use this rather than doing the algebra outside the graph: the A and B you're solving usually come from the graph. Points from a matcher, a camera matrix from the calibration nodes, a measurement matrix assembled from several frames - once those exist as NPARRAYs, this node closes the loop in place.
Inputs
src1- the left-hand sideA. NPARRAY only; no IMAGE link is accepted, because this is a matrix, not a picture.src2- the right-hand sideB. Same restriction. Shapes must agree withA(Bmay carry multiple right-hand sides as columns).flags(optional) - which decomposition to use. This is the only real decision on the node.
The flag list is OpenCV's DecompTypes, and the two you'll actually pick:
DECOMP_LU(the default) - LU with partial pivoting. Fast, and correct for a square, non-singularA. It returnsfalsein the output when the system is singular, which is the honest answer rather than a matrix of NaNs.DECOMP_SVD- singular value decomposition. Slower, but it handles rank-deficient and over-determined systems and gives you the least-squares / pseudo-inverse solution. When you have more equations than unknowns - ten correspondences, six unknowns - this is the flag you want, and it's the one people discover afterDECOMP_LUreturnsfalseon a perfectly reasonable problem.
Also available: DECOMP_CHOLESKY (symmetric positive-definite systems - the fast path when you know you have one), DECOMP_EIG (symmetric systems, eigen-decomposition), DECOMP_QR, and DECOMP_NORMAL, which reformulates the problem as the normal equations AᵀA·X = AᵀB - the least-squares route for an over-determined system when you're happy to square the conditioning.
Outputs
Two sockets, in cv2's own naming:
bool- did it converge / was the system solvable?falseis a real possibility withDECOMP_LUon a degenerateA. Branch on it rather than consuming a bad solution.nparray- the solutionX.
That's the interface. The work is in building A and B, and the pack gives you the pieces: CV Points and Parse Matrix to type a matrix, CV Scalar for constant vectors, CV Concat Arrays and CV Stack Feature Classes to assemble rows, CV Matrix Multiply and cv2.transpose to form products, CV Cast Array to get everything into a consistent float dtype before you call this.
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 V3-API ComfyUI, no models.
Where people get burned
DECOMP_LU on a non-square system. An over-determined A (the usual shape when fitting something to noisy measurements) isn't LU's job. Switch to DECOMP_SVD instead of squinting at the failure.
dtype mismatches. Markers like CV_CastArray exist because these raw wrappers are unforgiving: an int32 A and a float32 B will not quietly promote themselves the way you'd like. Cast everything to float32 or float64 first.
Ignoring the bool. The returning socket is easy to leave dangling, and it's the only thing standing between you and a false result you then warp an image with. If the graph continues to a warp or a projection, route the flag into a fallback path.
"Why is this node in a ComfyUI pack at all?" Because the pack auto-generates wrappers for OpenCV's top-level functions rather than curating a playlist - hence ~470 of them, including general numerics that mostly matter as support for the geometry nodes. And note the README's standing caveat: this is a personal, AI-assisted project with no production guarantee, so verify results you intend to rely on. For a linear solve, the verification is easy: plug X back into A·X with cv2.gemm and compare with B.
Inputs (3)
| Name | Type | Default | Description |
|---|---|---|---|
| src1 | NPARRAY | input matrix on the left-hand side of the system. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| src2 | NPARRAY | input matrix on the right-hand side of the system. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| flagsopt | COMBO | DECOMP_LU | solution (matrix inversion) method (#DecompTypes) |
Outputs (2)
| Name | Type | Description |
|---|---|---|
| bool | BOOLEAN | — |
| nparray | NPARRAY | — |