triangulate_column — 3D structured_light op

• Data kinds: image2d → depth

• Call: import fullseye as fs; fs.ledger.triangulate_column(column, k_cam, k_proj, rot, trans) -> 'np.ndarray' (to call the implementation directly, import fringe; fringe.triangulate_column(column, k_cam, k_proj, rot, trans) -> 'np.ndarray'; from the registry, ops3d.get("triangulate_column"))

Usage

Triangulate the depth Z from the "projector column number" of each camera pixel (the final stage of structured light).

The geometry of a structured-light scanner itself: a camera pixel (u,v) spans 1 line of sight, and a projector column number u_p spans 1 plane (the plane containing the projector centre and that column). The intersection of the line of sight and the plane is the 3D surface point, and its camera-frame Z is the depth. It is a closed form, so neither iteration nor optimisation is needed.

column: (H, W) projector column numbers (sub-pixel real values). Values derived from the phase can be

passed as is. NaN = undetermined pixel (output also NaN).

k_cam: camera intrinsic matrix 3x3 (fx, fy, cx, cy[, skew]). Pixel centres are at integer coordinates

(the same convention as render3d.render_mesh / camera.depth_to_points).

k_proj: projector intrinsic matrix 3x3. Only row 0 (column direction) and row 2 are used.

rot: 3x3 rotation. Camera frame → projector frame (X_proj = rot·X_cam + trans).

trans: translation of length 3 (as above, same unit as the scene). The zero vector is forbidden

(baseline 0 = camera and projector at the same point. The plane and the line of sight do not intersect and the depth is undefined).

Returns: (H, W) float64 depth map (Z in front of the camera, the same quantity as the depth of render_mesh).

Pixels whose intersection is behind (Z<=0) or whose line of sight is parallel to the plane are NaN.

Derivation: X_cam = Z·d (d = K_cam⁻¹[u,v,1]). The column condition on the projector side is (K_proj[0] − u_p·K_proj[2])·X_proj = 0. Substituting X_proj = rot·X_cam + trans and solving for Z gives Z = −(a·trans) / (a·(rot·d)), a = K_proj[0] − u_p·K_proj[2].

Raises: ValueError on bad shapes or matrices, zero baseline, or a singular camera matrix.

Provenance (public literature): structured-light triangulation by ray-plane intersection — Hartley & Zisserman, *Multiple View Geometry* 2nd ed. §12 (intersections in projective geometry) / Salvi et al., *Pattern Recognition* 43 2010 (classification and decoding of structured-light patterns).

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)

• structured_light_scan — py -3.11 examples_3d/structured_light_scan.py

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

depth_to_points · tsdf_from_depth · to_points · fuse_to_voxel · depth_to_organized_points · normals_from_depth · occlusion_edges · bearing_angle_image

Same category (structured_light)

wrapped_phase · unwrap_phase_2d · graycode_decode · decode_fringe · synthesize_fringes · absolute_phase


*Provenance: fringe.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.