CV Matrix To Pose
Turn a 4x4 back into something that can be rendered
- matrix
- rvec
- tvec
- rotation
- scale
- found
There are two ways to express "where the object is" in OpenCV, and they're not interchangeable at the plumbing level. Solvers hand you a 4x4 (or 3x4) rigid transform. Everything you'd use to draw the thing - cv2.projectPoints, CV Rasterize Mesh, CV Camera Pose To 3D View - wants rvec + tvec. This node is the adapter: matrix in, Rodrigues rotation vector and translation out.
Concretely, it's the step between "the matcher found the pose" and "I can see whether the pose is right." CV PPF Pose Estimation, CV ICP Register and CV Register Point Clouds (3D) produce matrices; this turns them into something renderable, so a recovered pose can be checked against - or composited into - the photo it came from. CV Pose To Matrix is the inverse, and the pair are designed as a round trip.
How it works
It takes the rotation block, orthonormalizes it with an SVD, and feeds the result to cv2.Rodrigues. That's not paranoia - a pose that came out of a chain of matrix multiplications is only approximately a rotation, and Rodrigues won't complain about a slightly skewed input, it'll just return a vector that no longer round-trips. Nearest-rotation-by-SVD fixes it. Reflections get caught too: if the determinant comes out negative the last singular vector is flipped, because a reflection isn't a rotation.
A 4x4 homogeneous transform, a 3x4 [R|t], or a bare 3x3 rotation are all accepted. A 3x3 gives you a zero translation.
Inputs and outputs
One required input, matrix. Outputs:
rvec- 3x1 Rodrigues rotation vector. This is whatprojectPointsand the rapid nodes want.tvec- 3x1 translation, in the matrix's own units (no unit conversion happens, and none should).rotation- the orthonormalized 3x3R, if you'd rather do your own math.scale- the mean singular value of the input's rotation block. This is the diagnostic output and most people don't notice it exists. 1.0 means a clean rigid transform. Anything else means your matrix carries a scale (or drift) thatrvec/tveccannot represent and that this node silently divided out. A scale of 1.02 is a solver that drifted; a scale of 100 is a unit mismatch you should fix upstream instead of hiding here.found- False when the matrix was missing, the wrong shape, or non-finite.
Install
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
Manager → ComfyUI CV. Restart. Requires Python ≥ 3.12 and a V3-API ComfyUI; dependency is opencv-contrib-python-headless~=5.0.0.93. No models, no GPU - this is arithmetic.
Common issues
A pose that renders 180° out. If the mesh and the scene normals disagree about which way is out, the recovered pose is inverted and this node can't tell you - it faithfully converts whatever rotation it was handed. The chain is: the mesh must carry sign-correct normals (CV Mesh Vertex Normals, which derives them from triangle winding, rather than a plane fit that can't tell inside from outside), and the axis convention on CV Mesh From 3D Model must match the camera's. Get those two right and this node is a no-op converter.
found=false from a matrix you're sure is there. Check the shape. A flattened 16-element vector, a 2x4, or a matrix that came out of a text parse are the usual culprits. It also returns False for a matrix containing NaN or inf, which is a gift - a diverged solver upstream would otherwise propagate silently into your render.
Rotation looks right, position is wrong. Read scale first, then check units. A mesh authored in centimetres matched against a calibration in metres gives a pose that's correct in direction and wrong in depth, which is exactly the signature of a scale mismatch - and the fix is scale on CV Mesh From 3D Model or CV 3D Object Transform, not here.
Inputs (1)
| Name | Type | Default | Description |
|---|---|---|---|
| matrix | NPARRAY | 4x4 homogeneous or 3x4 [R|t] transform. A 3x3 rotation on its own is accepted too and gives a zero translation. |
Outputs (5)
| Name | Type | Description |
|---|---|---|
| rvec | NPARRAY | 3x1 Rodrigues rotation vector. |
| tvec | NPARRAY | 3x1 translation vector, in the matrix's own units. |
| rotation | NPARRAY | The orthonormalized 3x3 rotation matrix R. |
| scale | FLOAT | Mean singular value of the input's rotation block - 1.0 for a rigid transform. Anything else means the matrix carries a scale (or drift) that rvec/tvec CANNOT represent and that this node has divided out. |
| found | BOOLEAN | False when the matrix was missing, the wrong shape, or non-finite. |