CV Draw Epipolar Lines
Seeing whether your fundamental matrix is actually right
- source
- lines
- points
- inlier_mask
- image
Why you'd reach for this
Two views of the same scene, and a point in one of them. Epipolar geometry says that point's match must lie on a specific line in the other view - a line you can compute from the fundamental matrix, without knowing the match. That line is the single most informative sanity check in two-view geometry, because if the computed line doesn't pass through the actual correspondence, something upstream is wrong: the matches, the matrix, or the calibration.
You can't check that with numbers. You check it by drawing the lines over the second image and looking at whether they converge on the right spot - a correct fundamental matrix gives you a family of lines meeting near a common epipole.
How it works
Input is Nx1x3 line coefficients from cv2.computeCorrespondEpilines, in ax + by + c = 0 form. For each line the node intersects it with the frame - clipped at left/right when the line is mostly horizontal, top/bottom when mostly vertical, whichever edge pair is numerically safer - and draws that segment anti-aliased. Degenerate all-zero lines, which is what a not-found fundamental matrix produces, are skipped rather than dividing by zero.
max_draw defaults to 40, not 0, and that's a sensible default: with a few hundred matches an unfiltered epiline render is a grey smear. Then inlier_mask (the Nx1 uint8 from CV Find Fundamental Matrix or a homography) slices both the lines and the optional points by the same mask, so what you see is the RANSAC-consistent subset. The tooltip's suggestion is worth stealing: set it to 0 (all) exactly once so you know what the clutter looks like, then leave it filtered.
The colouring is the clever part. Each line is coloured by its index through the pack's colour-vision-deficiency-safe categorical palette, and if you wire this image's matched points into points they're marked with a dot in the same colour, radius scaled by thickness. Run two of these nodes - one per view - with the same inlier mask, and a point in the left image shares its colour with its epipolar line in the right one. That's the correspondence made visible as a colour match, not a coordinate table.
Inputs and outputs that matter
- lines - from
CV Compute Correspond Epilines-style call, i.e. theNx1x3output. Feed it the other view's points, as the maths requires. - max_draw - default 40. Your main clutter control.
- inlier_mask (optional) - must match the line count exactly, or the node raises with both numbers.
- points (optional) - this image's matched points, dotted in their line's colour.
- image - the only output, same format as the input (IMAGE or MASK). No count output on this one; if you need "how many inliers", that's what the mask arithmetic upstream gives you.
Install
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, ComfyUI on the V3 node API, or install the pack as ComfyUI CV from ComfyUI Manager.
Common issues
- Lines everywhere and none near the points. Ambiguous matches. Everything is geometrically consistent with some wrong matrix when you feed it outliers - filter with a ratio test and re-fit before blaming this node.
- Zero lines drawn. The fundamental matrix wasn't found. The pack's
CV Find Fundamental Matrixreports afoundflag for this; degenerate all-zero rows are skipped here by design, so a total absence of lines is the message. - Length mismatch error.
inlier_maskorpointshas a different row count thanlines. They all have to come from the same matched point set, in the same order. - Points and lines in different colours. You ran two nodes with different masks, or wired the wrong view's points in. Use one mask for both nodes.
- Contrib trap. Needs the contrib OpenCV wheel; installing plain
opencv-pythonover it silently empties the contrib submodules.tools/repair_opencv_contrib.py --check.
Inputs (6)
| Name | Type | Default | Description |
|---|---|---|---|
| source | COMFY_MATCHTYPE_V3 | Image or mask to draw the epilines on (a copy is made). 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. | |
| lines | NPARRAY | Nx1x3 line coefficients from cv2.computeCorrespondEpilines. | |
| max_draw | INT | 400–10000 | Draw at most this many lines (after inlier filtering). 0 = all - usually too cluttered. |
| thickness | INT | 11–16 | Line width in pixels (point dots scale with it). |
| pointsopt | NPARRAY | This image's matched points (Nx1x2): each is marked with a dot in its line color. | |
| inlier_maskopt | NPARRAY | Nx1 uint8 mask from the fundamental-matrix node: only entries flagged 1 are drawn. |
Outputs (1)
| Name | Type | Description |
|---|---|---|
| image | COMFY_MATCHTYPE_V3 | Same format as the image input. |