Nodes/ComfyUI CV/cv2.correctMatches
ComfyUI Node

cv2.correctMatches

Fixing correspondences that only *almost* line up

By bmad4ever·Created 4 months ago·Updated 14 days ago· 1
cv2.correctMatches
  • F
  • points1
  • points2
  • newPoints1
  • newPoints2

Matching features between two views gives you pairs that are nearly right - typically a pixel or two off, because the detector snapped to the same physical point in both images and got slightly different answers. cv2.correctMatches takes those pairs plus the epipolar geometry and nudges each pair to the positions that minimise the geometric error along the epipolar lines. It's the last cleanup before you triangulate.

In plain terms: you have a fundamental matrix F, and every correspondence should satisfy p2ᵀ F p1 = 0. Real matches don't, by a few pixels. This function enforces it optimally - Hartley's Optimal Triangulation Method - and returns two corrected point sets instead of one.

This is depth-and-stereo territory, not image-generation territory: 3D reconstruction is where matched points get turned into a depth field, and this is one of the plumbing steps on the way. The node is cv2.correctMatches in the ComfyUI CV pack, category image/CV/low-level/cv2 C - a raw wrapper, so it's all data in, all data out, with no images anywhere in sight.

How it works

For each pair, given F, cv2 parametrises the uncertainty of the correspondence and solves for the pair of points on the two epipolar lines that minimises the total geometric distance - the correction distributed across both images rather than dumped onto one side. The result is two matched sets where the epipolar constraint holds exactly.

It does not re-match anything. Wrong pairs stay wrong, they just become self-consistent wrong pairs, which is exactly why this belongs after a RANSAC step (which found F from the inlier subset) and not before it. Feeding it a garbage F produces confident nonsense.

The inputs and outputs that matter

Three required NPARRAY inputs, no widgets at all. F is the 3×3 fundamental matrix; points1 and points2 are the two corresponding point sets (the OpenCV docs the pack copies from describe them as 1xN arrays). Both flags and matrices are pure data - the pack's socket for these accepts only an NPARRAY link, so nothing here can be typed in by accident.

The two outputs are newPoints1 and newPoints2 - the corrected sets, in the same order as the inputs, so correspondence i in, correspondence i out.

Where the pieces come from, in this pack: F from cv2.findFundamentalMat (which returns the matrix plus an inlier mask) or the curated CV Find Fundamental Matrix node; the points from CV Match Features / cv2.goodFeaturesToTrack plus the matcher, carried as arrays. Downstream, the corrected pairs go to cv2.triangulatePoints (CV Triangulate Points), cv2.recoverPose, or a rectification step.

If you don't have an F yet

Don't start here. The order that works is: detect → match (with the ratio test on) → findFundamentalMat with RANSAC to get F and the inlier mask → apply the mask to keep only inliers → then correct the surviving pairs. Correcting before RANSAC means you're handing the estimator pre-bent points and it will happily fit the bend.

One shortcut for a degenerate case: if the pairs are already inliers of a robust estimate and the correction is sub-pixel, the honest answer is that you may not need this node. It pays off when your reconstruction is visibly jittery - triangulated depth flickering between frames, or a pose that oscillates - because that's the signature of uncorrected correspondences.

Installing it

ComfyUI Manager → search the pack title (ComfyUI CV) → install → restart. Manual:

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 ComfyUI on the V3 node API. This pack is a fork of geroldmeisinger's opencv-comfyui; it's a single-author project, largely LLM-written by the author's own admission in the README, with no updates planned. The camera-geometry nodes are old, well-defined cv2 calls, which makes them a good part of the pack to rely on - but read the code if you ship anything commercial.

Common issues and troubleshooting

The output points are wildly different from the input. Usually a bad F. Check the fundamental matrix arrived (and isn't a zero matrix from a failed fit), and that it came from the same point sets you're correcting - F estimated between other matches is a common copy-paste error in big graphs.

"(-215) ... assertion failed" on shapes. Point arrays need to be float32 and shaped the way cv2 wants (N×1×2 or N×2). CV Cast Array and Inspect CV Data are the tools; the pack's own CV Reshape Array note is explicit that a flat (3,) row needs reshaping before cv2 arithmetic behaves.

No F because RANSAC found nothing. Fewer than the minimum matches (7 or 8 depending on method), or all-correspondences-identical input. Check the count before blaming this node.

Coordinates look plausible but reconstruction is still noisy. This corrects geometry, not accuracy: if the matches themselves are on the wrong features, the corrected pairs are consistently wrong. Go back to the ratio test on the matcher.

Categoryimage/CV/low-level/cv2 C

Inputs (3)

NameTypeDefaultDescription
FNPARRAY3x3 fundamental matrix. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
points1NPARRAY1xN array containing the first set of points. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.
points2NPARRAY1xN array containing the second set of points. A data array (points / matrix), NOT an image - only an NPARRAY link is accepted here.

Outputs (2)

NameTypeDescription
newPoints1NPARRAY—
newPoints2NPARRAY—