cv2.recoverPose (3/4)
The uncalibrated shortcut, and when it lies to you
- E
- points1
- points2
- pp
- mask
- retval
- R
- t
- mask
The variant with no camera matrix
Three of the four cv2.recoverPose overloads want intrinsics. This one doesn't: recoverPose(E, points1, points2, focal, pp, mask) swaps the 3×3 cameraMatrix for a focal length and a principal point, and rebuilds K internally as fx = fy = focal with that principal point.
Which raises the obvious question - where did K go? Answer: E is only meaningful in normalized camera coordinates, so what this overload really lets you do is hand over points in whatever coordinate space you have (pixels, usually) and state the two assumptions you're willing to make: square pixels with one focal length, and a principal point you name.
The author's own tooltip on focal says it plainly: "Focal length in pixels for the assumed camera (fx = fy = focal, principal point pp). 1.0 (the default) means the points are already in normalized camera coordinates." So the default is not "some reasonable focal length" - it's the identity, and it's only correct if a previous step already normalized your points.
Inputs
- E - 3×3 essential matrix, from cv2.findEssentialMat (estimating it in normalized coordinates is exactly how the uncalibrated path is meant to be used).
- points1, points2 - matched point sets, NPARRAY only. This node's sockets don't take images; they're numeric arrays.
- focal - pixels. Defaults to 1.0, which as above means "already normalized". If you're in pixels, put your real focal in.
- pp - principal point, a CV_TUPLE, defaulting to
(0, 0). For pixel-space points that default is wrong in a way that quietly biases the pose: you usually want the image centre, e.g.(960, 540)for a 1920×1080 frame. CV Tuple is the node that authors this value. - mask - optional inlier mask for the points.
Outputs: retval (inliers used), R (3×3 rotation), t (3×1 unit translation), mask (N×1 uint8 inliers that also survived the chirality check).
Why you'd use it - and the honest case against
The pitch is "skip calibration". That's real: for drone shots, archived footage, stock video of a scene you'll never see again, knowing fx within 10% is enough to get a directionally correct pose, and monocular geometry can't fix scale anyway.
But the honest version is: for monocular visual odometry in this pack you rarely need either raw variant, because CV Recover Pose (Essential Matrix) asks for a camera_matrix up front and gives you a found flag, and CV Visual Odometry (Sequence) runs the whole match → pose → compose chain over a clip with failure tolerance. Both want calibration, and calibration is cheap: a printed chessboard, CV Calibrate Camera (Chessboard), done once.
So the realistic uses of this variant are:
- You have points already in normalized coordinates (say, from your own preprocessing) and no K in the graph, and you want the identity behaviour with no matrix to fake up.
- You want to test how sensitive a pose estimate is to focal length - run the same pair at 1.2× the true focal and watch
retvaland the mask change. That's a legitimate diagnostic, and it's the kind of thing these raw wrappers are actually good for.
A CV_TUPLE for pp and a plain float for focal make the experiment cheap to run.
The failure modes that aren't obvious
Assuming pp = (0,0) means "centre". It doesn't. It means the top-left corner of the image in the pinhole model's coordinates - which is a different camera from the one that took your photos. The pose comes out tilted. Set the centre explicitly.
Assuming focal is "focal length in mm". It's pixels. A 50 mm lens on a 36 mm-wide sensor at 1920 px is roughly 1920 * 50/36 ≈ 2667, not 50.
Assuming the answer is metrically right. t is a unit vector. It was a unit vector in variants 1 and 2 as well; the only thing that changes here is how you got there.
Install
ComfyUI Manager → search "ComfyUI CV" (author bmad4ever), or:
cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"
Python ≥ 3.12 and a recent ComfyUI with the V3 node API. Restart ComfyUI, then reload the page - node definitions are fetched on page load, so a fresh install won't show up in the search box until you do.
One dependency footnote
If some other pack has since installed plain opencv-python over the contrib build this pack depends on (opencv-contrib-python-headless~=5.0.0.93), the contrib submodules go empty and nodes from contrib-only modules disappear. SfM-adjacent nodes live closer to core cv2 than the RAPID ones do, so you'll usually be fine - but if a cv2 node of any kind suddenly reports an unknown-attribute error, that's the first thing to check:
python ComfyUI/custom_nodes/comfyui_cv/tools/repair_opencv_contrib.py --check
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| E | NPARRAY | The output essential matrix. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| points1 | NPARRAY | Array of N 2D points from the first image. The point coordinates should be floating-point (single or double precision). A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| points2 | NPARRAY | Array of the second image points of the same size and format as points1 . A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here. | |
| focalopt | FLOAT | 1.0000-1e+38–1e+38 | Focal length of the camera. Note that this function assumes that points1 and points2 are feature points from cameras with same focal length and principal point. Preset to the OpenCV default (1.0). |
| ppopt | CV_TUPLE | 0,0 | principal point of the camera. One value with 2 components (x, y) - it travels as a whole, so it cannot arrive half-connected. Wire it from 'CV Tuple' or type the components in place. |
| maskopt | NPARRAY,IMAGE,MASK | Input/output mask for inliers in points1 and points2. If it is not empty, then it marks inliers in points1 and points2 for the given essential matrix E. Only these inliers will be used to recover pose. In the output mask only inliers which pass the chirality check. This function decomposes an essential matrix using and then verifies possible pose hypotheses by doing chirality check. The chirality check means that the triangulated 3D points should have positive depth. Some details can be found in . This function can be used to process the output E and mask from . In this scenario, points1 and points2 are the same input for findEssentialMat.: 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 (4)
| Name | Type | Description |
|---|---|---|
| retval | INT | — |
| R | NPARRAY | — |
| t | NPARRAY | — |
| mask | NPARRAY | — |