Nodes/ComfyUI CV/cv2.findEssentialMat (3/3)
ComfyUI Node

cv2.findEssentialMat (3/3)

Cv2.findEssentialMat (3/3)

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
cv2.findEssentialMat (3/3)
  • points1
  • points2
  • cameraMatrix1
  • distCoeffs1
  • cameraMatrix2
  • distCoeffs2
  • mask
  • E
  • mask
◄methodRANSAC►
◄prob0.9990►
◄threshold1.0000►

The third and most thorough of the three cv2.findEssentialMat nodes. Where (1/3) takes one camera matrix because both views share intrinsics, this overload takes a separate camera matrix and distortion vector for each camera, and undistorts the points internally before estimating E. If you're working with a two-camera rig - mismatched bodies, a phone and an action cam, a stereo pair with real lenses on both sides - this is the one that isn't lying to you about the optics.

Inputs

points1 and points2 are the matched features from a single matching pass, floating point, at least five points, Nx1x2 or Nx2. Both are data sockets that accept NPARRAY only.

Then the four camera-description inputs: cameraMatrix1 and cameraMatrix2 (3×3 K for each view), plus distCoeffs1 and distCoeffs2 - the distortion coefficient vectors, which OpenCV documents as 4, 5, 8, 12 or 14 elements, with the empty/NULL case meaning "no distortion". All four are required arrays here, which is the practical wrinkle: to say "this camera has no distortion" you have to hand it zeros rather than leave it blank. Parse Matrix with 0,0,0,0,0 gets you a clean 5-element vector, and a real calibration's dist_coeffs drops straight in from CV Calibrate Camera (Chessboard) - which is exactly the case this overload is built for.

The optional knobs are method (RANSAC, or LMEDS), prob (0.999) and threshold (1.0 px - how close a point has to land to its epipolar line to count as an inlier). Notice what's not here: this overload in cv2 has no maxIters parameter, unlike (1/3). If you need to cap iterations you're not the target audience for this node; lower prob or raise threshold instead.

And the same optional mask input as its siblings, which is the C++ output buffer and does nothing useful when fed. Ignore it.

Outputs

E - the 3×3 essential matrix - and mask, the Nx1 uint8 inlier mask. The mask is your quality report, and with two-camera input it's doing double duty: it flags both bad correspondences and points that fall outside where the distortion model is valid (heavy barrel distortion at the frame edges is a common source of outliers that aren't the matcher's fault).

Downstream, E feeds CV Recover Pose (Essential Matrix) for a rotation plus a unit translation with cheirality checking - or cv2_decomposeEssentialMat if you'd rather handle the four candidate decompositions yourself. CV Draw Matches takes the mask and shows you which pairs survived, which is the diagnostic I'd run first on any result that looks off.

When the three overloads disagree

They shouldn't, in the sense that all three estimate the same quantity; they differ in how much you tell them about the camera. (1/3) takes one shared K. (2/3) takes a focal length and principal point. This one takes two complete cameras with distortion. If you have the calibration data, use it - the internal undistortion here is doing work your matches would otherwise push into the estimator as noise. If you don't, (2/3) with the identity assumption (focal 1, pp (0,0), normalized points) is the honest fallback.

The shared caveats hold: a single plane, or a camera that only rotated, is degenerate geometry, and E will still come back looking like a matrix.

Install

cd ComfyUI/custom_nodes
git clone https://github.com/bmad4ever/comfyui_cv
pip install "opencv-contrib-python-headless~=5.0.0.93"

Or install "ComfyUI CV" from ComfyUI Manager and restart. Python ≥ 3.12, V3 node API, and keep the contrib wheel: a plain opencv-python installed over it by some other pack empties the contrib submodules and nodes start vanishing. tools/repair_opencv_contrib.py --check then --apply in the pack directory handles that.

Common issues

"Overload resolution failed." Shape and length. All four camera arrays need to be the shapes cv2 expects (3×3 for K, a column of coefficients for D), and points1/points2 must have equal length and float dtype. Inspect CV Data on each input tells you which one is wrong in seconds.

Everything is an outlier. With distortion vectors attached, this overload is stricter: points from a region where your coefficients don't describe the lens get rejected. If a real calibration gave you 14 coefficients and the fit is poor, going back to a 5-coefficient fit often produces a better essential matrix than stretching the model.

Different result than (1/3) on the same data. Expected - different camera model, different internal undistortion. Pick one and stay with it rather than mixing estimates from both in the same pose chain.

Categoryimage/CV/low-level/cv2 F

Inputs (10)

NameTypeDefaultDescription
points1NPARRAYArray of N (N >= 5) 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.
points2NPARRAYArray 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.
cameraMatrix1NPARRAYCamera matrix for the first camera $K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}$ . A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
distCoeffs1NPARRAYInput vector of distortion coefficients for the first camera $(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])$ of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
cameraMatrix2NPARRAYCamera matrix for the second camera $K = \vecthreethree{f_x}{0}{c_x}{0}{f_y}{c_y}{0}{0}{1}$ . A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
distCoeffs2NPARRAYInput vector of distortion coefficients for the second camera $(k_1, k_2, p_1, p_2[, k_3[, k_4, k_5, k_6[, s_1, s_2, s_3, s_4[, \tau_x, \tau_y]]]])$ of 4, 5, 8, 12 or 14 elements. If the vector is NULL/empty, the zero distortion coefficients are assumed. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
methodoptCOMBORANSACMethod for computing an essential matrix. - for the RANSAC algorithm. - for the LMedS algorithm.
proboptFLOAT0.9990-1e+38–1e+38Parameter used for the RANSAC or LMedS methods only. It specifies a desirable level of confidence (probability) that the estimated matrix is correct. Preset to the OpenCV default (0.999).
thresholdoptFLOAT1.0000-1e+38–1e+38Parameter used for RANSAC. It is the maximum distance from a point to an epipolar line in pixels, beyond which the point is considered an outlier and is not used for computing the final fundamental matrix. It can be set to something like 1-3, depending on the accuracy of the point localization, image resolution, and the image noise. Preset to the OpenCV default (1.0).
maskoptNPARRAY,IMAGE,MASKOutput array of N elements, every element of which is set to 0 for outliers and to 1 for the other points. The array is computed only in the RANSAC and LMedS methods. 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 (2)

NameTypeDescription
ENPARRAY—
maskNPARRAY—