Nodes/ComfyUI CV/CV Find Homography (RANSAC)
ComfyUI Node

CV Find Homography (RANSAC)

Teach two photos that they're the same wall

By bmad4ever·Created 3 months ago·Updated 14 days ago· 1
CV Find Homography (RANSAC)
  • points_a
  • points_b
  • homography
  • inlier_mask
  • inlier_count
  • found
◄methodRANSAC►
◄reproj_threshold3.0►
◄min_inliers10►

A homography is the maths behind "that poster is still the same poster, just photographed from a different spot." You give this node two sets of matched points - the same features found in image A and image B - and it hands back the 3×3 matrix that maps one onto the other. With that matrix you can warp A into B's frame, drop a virtual cube on the poster, or stitch a panorama. It's cv2.findHomography with the plumbing and the failure handling done for you.

This is classic computer vision, not a diffusion pass. ComfyUI CV is bmad4ever's pack - a fork of Gerold Meisinger's opencv-comfyui, ~470 auto-generated cv2.* wrappers plus a few hundred hand-written nodes, all deterministic. When the pack's ancestor was announced on r/comfyui, the framing was honest about where it belongs: small, quick transformations inside a graph, not full OpenCV apps living in Comfy. Homography is squarely in the first camp, and it does a job a diffusion model can't do at all: pixel-exact geometric agreement.

How it works

points_a and points_b come from CV Match Features - the same node's two outputs, in the same order, one point per match. Both are Nx1x2. The node fits H by minimizing reprojection error, but real feature matches always contain outliers, so a robust estimator runs on top: RANSAC picks a minimal sample, counts how many points land within reproj_threshold pixels (default 3) of where H says they should, and keeps the consensus.

The four outputs are the useful part:

  • homography - 3×3 float64, mapping points_a into points_b.
  • inlier_mask - Nx1 uint8, 1 = inlier. Wire it into CV Draw Matches and you can see which matches were lies.
  • inlier_count - the consensus size.
  • found - a boolean you should actually use.

method defaults to RANSAC and that's the right answer for feature matches. The alternatives (LMEDS, RHO, the USAC family, plain least-squares) are refinements for specific cases; least-squares will happily average outliers into a wrong matrix. min_inliers (default 10, minimum 4) is your false-positive gate - RANSAC can converge on noise, and four inliers is the mathematical minimum, not evidence.

Wire homography into cv2_warpPerspective (dsize = the destination image's size, from CV Array Size) or into CV Homography Map if you want it folded into a larger remap chain - that node inverts the matrix by default so you feed it the src→dst H you just got.

The failure contract is the good bit

Raw cv2.findHomography returns None on a degenerate configuration, and graphs die on None. Here, too few points, a non-finite matrix, or an estimate with fewer than min_inliers inliers all return the same safe thing: an identity matrix, a zero mask, inlier_count = 0, found = false. Identity is a no-op warp, so the workflow keeps running and you get the original image instead of a crash.

That means found is your branch. Into a control-flow node - Basic Data Handling's IfElse, or a switch - and bypass the compositing or the drawing when nothing was found. Same principle as the plumbing docs' fallback switches: let the graph decide, don't make the reader remember.

Install

ComfyUI Manager, search ComfyUI CV (repo bmad4ever/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"

Requires Python ≥ 3.12 and a recent ComfyUI built on the V3 node API - on an old frontend/backend the nodes won't register at all. The pack pins OpenCV 5 (5.0.0.93) because behaviour is curated against it.

Common issues

Mismatched point sets. points_a and points_b must come from the same matcher run. The node raises a clear error when the counts differ, so this one at least tells you.

Plane-only, both ways. A homography is only strictly valid for a planar scene or a pure camera rotation. Two views of a room with depth will fit something with plenty of inliers and warp it wrong - for that you want the fundamental matrix instead.

"found is true but the warp looks wrong." Raise min_inliers (say 15–25) so a weak consensus can't pass, and tighten reproj_threshold toward 2–3 px. Feature matching quality is upstream of everything here; filter weak keypoints first.

Contrib gone missing. If the whole pack imports but contrib-only nodes vanish, another install dropped a non-contrib OpenCV wheel over yours - all the wheels share one site-packages/cv2. tools/repair_opencv_contrib.py --check diagnoses it, --apply fixes it.

Open workflows/exercise_homography_ransac.json first: two images, the match/filter/find chain, an overlay preview and both the matrix and inlier count printed. Then exercise_homography_ar.json for the thing you actually wanted to build.

Categoryimage/CV/features

Inputs (5)

NameTypeDefaultDescription
points_aNPARRAYSource points, Nx1x2 (from 'CV Match Features').
points_bNPARRAYDestination points, Nx1x2.
methodCOMBORANSACRobust estimator. RANSAC is the standard choice for feature matches (which always contain outliers).
reproj_thresholdFLOAT3.00.1–100Maximum reprojection error in pixels for a match to count as an inlier.
min_inliersINT104–10000Minimum RANSAC inliers for 'found' to be true. Raise it to reject false positives.

Outputs (4)

NameTypeDescription
homographyNPARRAY3x3 float64 matrix mapping points_a to points_b (identity if not found).
inlier_maskNPARRAYNx1 uint8: 1 = inlier. Feed into 'CV Draw Matches'.
inlier_countINT—
foundBOOLEAN—