triangulate — 3D two_view op

• Data kinds: image2d × image2d → points

• Call: import fullseye as fs; fs.ledger.triangulate(pts1, pts2, P1, P2) (to call the implementation directly, import twoview; twoview.triangulate(pts1, pts2, P1, P2); from the registry, ops3d.get("triangulate"))

Usage

DLT triangulation: correspondences from two views plus the projection matrices → 3-D points. → (N,3).

Points at infinity are returned as NaN (not as ±inf). The 4th component of the homogeneous coordinate being 0 = the 2 lines of sight are parallel, and that correspondence determines no finite 3-D point. Previously it divided as is and produced ±inf, but then the downstream cheirality test depth > 0 counts inf as "in front of the camera" (inf > 0 is True). recover_pose picks, out of the 4 (R, t) candidates, the one with the most points in front, so if points at infinity get votes the candidate selection is silently skewed. With NaN the comparison is False, so they are not counted (2026-09-02, found when chain_fuzz reached it).

A correspondence that is nearly but not exactly parallel is returned as a large finite value. This cannot be caught by NaN, so the caller must check whether the distance is plausible.

Raises ValueError: points are not (N,2) / non-finite / correspondence counts mismatch.

Notes:

• P1, P2 are (3,4) projection matrices (K[R|t]). Correspondences are (N,2) in the same pixel coordinate system as that P. If cam1 is the reference, P1 = K1[I|0].

• A Python loop that runs SVD on a 4×4 coefficient matrix for each point (proportional to the point count). The return value is float64 (N,3).

• The sign of the depth (cheirality) is not checked. If a front/back test is needed, look at the z of the result and the z of R X + t (recover_pose does this internally).

• The unit of the solution is the same as the translation t of P. For P derived from recover_pose, the scale is |t|=1.

• Deterministic. Not (N,2), non-finite, or mismatched point counts give ValueError.

Background guides (the physics and conventions behind this op)

• depth_sensors — Depth sensors — ranging principles, real-device figures, how dropouts appear

References (sample data, literature)

• Sample-data catalog (download URLs / licences) — 2-D uses skimage.data (BSD/public domain) plus synthetic images; 3-D lists download URLs for real data sources (Stanford, PDS, …).

• Operator provenance and references — the sources of the research/methods this op family came from.

Runnable examples (verified samples that actually call this op)

• sfm_recon — py -3.11 examples_3d/sfm_recon.py

Ops the type connects to (they accept points as input)

points_to_voxel · gaussians_to_voxel · estimate_point_normals · to_points · match_points_ncc · match_pca · moment_axes · icp_point2point_3d

Same category (two_view)

fundamental_8point · essential_8point · recover_pose · sampson_distance


*Provenance: twoview.py — 3D operator registry. This per-op note is generated by tools/opdocs.py md (do not hand-edit).*

© 2026 Kazufumi Furuse — Fullseye operator documentation. Licensed under Apache-2.0.