API reference
This page documents the public StereoComplex API, auto-generated from the docstrings. For conceptual guides and worked examples see the rest of the documentation; for the tiered overview and the stability contract see Public API contract.
The most common entry points are also re-exported at the top level for
convenience — the calibration entry point is reachable both as
stereocomplex.api.calibrate and as sc.calibrate. The
stereocomplex.advanced namespace bundles additional composition and
diagnostic helpers, which are re-exports of the symbols documented below.
Note
StereoComplex v0.x is explicitly unstable: public names may still change. Backward-compatible stability commitments start at v1.0 — see Public API contract.
Physical optical models — stereocomplex.physics
Physical optical models (pinhole, Brown-Conrady, inclined parallel plate, compact-mirror-objective) and ray-space model selection.
- class stereocomplex.physics.BrownConrady(k1=0.0, k2=0.0, p1=0.0, p2=0.0, k3=0.0)[source]
Bases:
objectBrown-Conrady radial + tangential lens distortion in normalised coordinates.
Uses the same coefficient convention as OpenCV. Distortion acts on normalised (focal-length-relative) coordinates, not on pixels.
- k1, k2, k3
Radial distortion coefficients.
- Type:
- p1, p2
Tangential (decentering) distortion coefficients.
- Type:
- distort(x, y)[source]
Apply Brown-Conrady distortion to normalised image coordinates.
- Parameters:
x (ndarray) – Undistorted normalised coordinates (unitless).
y (ndarray) – Undistorted normalised coordinates (unitless).
- Returns:
xd, yd – Distorted normalised coordinates, same shape as the inputs.
- Return type:
ndarray
References
D. C. Brown, “Decentering distortion of lenses”, Photogrammetric Engineering 32(3), 444-462, 1966.
- undistort(xd, yd, iterations=10)[source]
Remove Brown-Conrady distortion by fixed-point iteration.
The Brown-Conrady model has no closed-form inverse; the undistorted coordinate is recovered by iterating from
(x, y) = (xd, yd)and subtracting the modelled distortion each step.- Parameters:
xd (ndarray) – Distorted normalised coordinates (unitless).
yd (ndarray) – Distorted normalised coordinates (unitless).
iterations (int) – Number of fixed-point iterations; 5-10 suffices for typical lenses.
- Returns:
x, y – Undistorted normalised coordinates, same shape as the inputs.
- Return type:
ndarray
- class stereocomplex.physics.CMOChannelRayField(channel, common_aberration=<factory>, name='cmo_channel')[source]
Bases:
objectPhysical CMO channel exposed as a rayfield for ray-space tools.
Wraps a fixed
CMOChannelSpecbehind the rayfield interface (ray,parameter_vector, …). This wrapper exposes no free parameters — it is a forward model, not a fittable one.- Parameters:
channel (CMOChannelSpec)
common_aberration (PolynomialRayAberration)
name (str)
- channel
The channel whose optics define the rayfield.
- Type:
- common_aberration
Shared aberration added to the channel’s differential aberration.
- Type:
- classmethod from_parameter_vector(x, **kwargs)[source]
Rebuild the rayfield from an (empty) parameter vector.
This model has no free parameters, so
xmust be empty; the channel itself is supplied through keyword arguments.- Parameters:
x (ndarray) – Must be empty (size 0).
**kwargs – Must include
channel(CMOChannelSpec); may includecommon_aberration(PolynomialRayAberration).
- Return type:
- Raises:
ValueError – If
xis non-empty.
- parameter_vector()[source]
Empty parameter vector (this channel has no free params).
- Return type:
ndarray
- ray(u, v)[source]
Compute the 3D ray (origin, direction) for each pixel of this channel.
Pipeline: invert the sensor warp to recover ideal pixels, convert to normalised coordinates, undistort (Brown-Conrady), apply the combined common + differential polynomial aberration, lift to a camera-frame direction
[x, y, 1]and normalise, then rotate into the world frame. Every ray shares the same sub-pupil origin (the channel is central).- Parameters:
u (ndarray) – Pixel coordinates (broadcast against each other).
v (ndarray) – Pixel coordinates (broadcast against each other).
- Returns:
origins (ndarray, shape (…, 3)) – Ray origin (the channel sub-pupil) in world millimetres — identical for every pixel.
directions (ndarray, shape (…, 3)) – Unit ray directions in the world frame, same leading shape as the inputs.
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.physics.CMOChannelSpec(name, intrinsics, origin_world_mm, R_cam_to_world=<factory>, distortion=<factory>, differential_aberration=<factory>, sensor_warp=<factory>, vignetting=<factory>)[source]
Bases:
objectOne effective CMO stereo channel: sub-pupil, intrinsics and per-channel optics.
“Effective” means the channel is described by a single sub-pupil (optical centre) plus image-formation terms — the per-camera view of a shared compact-mirror-objective (CMO) stereo head, not a literal lens model.
- Parameters:
name (Literal['left', 'right'])
intrinsics (CMOIntrinsics)
R_cam_to_world (ndarray)
distortion (BrownConrady)
differential_aberration (PolynomialRayAberration)
sensor_warp (SensorWarp)
vignetting (Vignetting)
- name
Channel identifier.
- Type:
{“left”, “right”}
- intrinsics
Pixel intrinsics of this channel.
- Type:
- origin_world_mm
Sub-pupil (optical centre) position in the world frame, in millimetres.
- Type:
tuple of 3 float
- R_cam_to_world
Rotation from the channel camera frame to the world frame.
- Type:
ndarray, shape (3, 3)
- distortion
Per-channel radial/tangential distortion.
- Type:
- differential_aberration
Per-channel polynomial ray perturbation, added on top of the shared one.
- Type:
- sensor_warp
Per-channel image-plane deformation.
- Type:
- vignetting
Per-channel radial shading.
- Type:
- property origin: ndarray
Sub-pupil (optical centre) position as a length-3 array, in millimetres.
- class stereocomplex.physics.CMOIntrinsics(width, height, fx, fy, cx, cy)[source]
Bases:
objectPinhole pixel intrinsics for a single CMO camera channel.
- width, height
Image size in pixels.
- Type:
- fx, fy
Focal length along the u and v axes, in pixels.
- Type:
- cx, cy
Principal point, in pixels.
- Type:
- as_K()[source]
Return the 3x3 pinhole camera matrix
K = [[fx, 0, cx], [0, fy, cy], [0, 0, 1]].- Return type:
ndarray
- classmethod from_focal_and_pitch(width, height, focal_mm, pitch_um)[source]
Build intrinsics from a physical focal length and sensor pixel pitch.
The pixel focal length is
f_px = focal_mm * 1000 / pitch_um(the factor 1000 converts millimetres to micrometres). The principal point is placed at the image centre((width - 1) / 2, (height - 1) / 2).- Parameters:
- Returns:
Intrinsics with square pixels (
fx == fy) and a centred principal point.- Return type:
- norm_to_pixel(x, y)[source]
Convert normalised image coordinates back to pixel coordinates.
Applies the intrinsics
u = fx * x + cxandv = fy * y + cy— the inverse ofpixel_to_norm().- Parameters:
x (ndarray) – Normalised (unitless) image coordinates.
y (ndarray) – Normalised (unitless) image coordinates.
- Returns:
Pixel coordinates stacked on the last axis.
- Return type:
ndarray, shape (…, 2)
- pixel_grid()[source]
Return the full-image meshgrid of integer pixel-centre coordinates.
- Returns:
u, v – Pixel column (u) and row (v) coordinates, built with
indexing="xy"; pixel centres sit at integer coordinates.- Return type:
ndarray, shape (height, width)
- pixel_to_norm(u, v)[source]
Convert pixel coordinates to normalised image coordinates.
Applies the inverse intrinsics
x = (u - cx) / fxandy = (v - cy) / fy. The result is dimensionless: for an ideal pinhole it equals the tangent of the ray angle.- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
x, y – Normalised image coordinates (unitless), same shape as the inputs.
- Return type:
ndarray
- class stereocomplex.physics.CMOPhysicalChannelModel(rig, channel, name='cmo_physical_channel', is_stereo_shared=True)[source]
Bases:
objectSingle-channel facade for a shared CMO physical rig.
- Parameters:
rig (CMOPhysicalStereoModel)
channel (Literal['left', 'right'])
name (str)
is_stereo_shared (bool)
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct a channel model from a flat parameter vector.
Builds the shared
CMOPhysicalStereoModelfrom x, then wraps it with the channel given bykwargs["channel"](default"left").- Parameters:
x (ndarray of float, shape (19,) or (21,)) – Flattened parameter vector (see
CMOPhysicalStereoModel.from_parameter_vector()).**kwargs – Must include
pixel_pitch_mm. May includeimage_size,share_principal_point, andchannel("left"or"right").
- Return type:
- parameter_vector()[source]
Serialize to a flat parameter vector, delegated to the shared rig.
See
CMOPhysicalStereoModel.parameter_vector().- Return type:
ndarray
- project_point(X, max_iter=20)[source]
Project a 3-D point with the non-tilted paraxial channel approximation.
Given a point X, find the pixel whose approximate ray passes through it. This helper is intentionally narrower than
CMOPhysicalStereoModel.ray(): it uses the sub-pupilz = working_distance_mm - f_obj_mmand does not inverttelecentric_offset_mm,theta_axis_tilt_radortheta_pitch_rad. Use it only for the legacy non-tilted projection path; useray()for the full fitted 19/21-parameter model.Returns
(uv, ok)where uv is (2,) and ok is True if the point projects inside the sensor.
- ray(u, v)[source]
Compute 3-D rays, delegating to the shared rig with this channel.
See
CMOPhysicalStereoModel.ray().- Parameters:
u (ndarray)
v (ndarray)
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.physics.CMOPhysicalStereoFitResult(model, success, message, n_parameters, n_samples, n_residual_scalars, rss, left_rms_mm, right_rms_mm, rms_mm, aic, bic, parameter_vector, parameter_dict)[source]
Bases:
objectResult of fitting a shared physical CMO model to two rayfields.
- class stereocomplex.physics.CMOPhysicalStereoModel(f_obj_mm, working_distance_mm, b_mm, f_tube_mm, cx_principal_px, cy_principal_px, pixel_pitch_mm, theta_axis_tilt_rad=0.0, theta_pitch_rad=0.0, telecentric_offset_mm=0.0, distortion_left=(0.0, 0.0, 0.0, 0.0, 0.0), distortion_right=(0.0, 0.0, 0.0, 0.0, 0.0), image_size=None, share_principal_point=True, delta_cx_diff_px=0.0, delta_cy_diff_px=0.0, name='cmo_physical_stereo', is_stereo_shared=True)[source]
Bases:
objectShared-rig paraxial CMO stereo model.
The model uses a common main objective with two decentered effective sub-pupils separated by
b_mm. For the central pixel, the left and right chief rays converge to the optical axis atworking_distance_mm. The chief-ray angle is controlled byb_mm / (2 f_obj_mm)because the entrance-pupil plane is placed one objective focal length before the working plane.Sensor coordinates are converted to object-plane coordinates through the tube-lens focal length and pixel pitch. The per-channel distortion is an effective direction distortion
D_c, parameterized by five Brown-Conrady-like coefficients applied to normalized angular coordinates. It absorbs residual aberrations of the tube lens and main objective; it is not a derivation from one specific physical aberration model.- Parameters:
f_obj_mm (float)
working_distance_mm (float)
b_mm (float)
f_tube_mm (float)
cx_principal_px (float)
cy_principal_px (float)
pixel_pitch_mm (float)
theta_axis_tilt_rad (float)
theta_pitch_rad (float)
telecentric_offset_mm (float)
share_principal_point (bool)
delta_cx_diff_px (float)
delta_cy_diff_px (float)
name (str)
is_stereo_shared (bool)
- channel(channel)[source]
Return a single-channel facade for the given channel name.
The returned
CMOPhysicalChannelModeldelegates all ray-tracing and parameter queries to this shared rig, transparently passing the channel identifier. This lets downstream code treat each channel as an independent ray model while the underlying parameters remain coupled through the shared CMO geometry.- Parameters:
channel ({"left", "right"}) – Which stereo channel to wrap.
- Return type:
- flat_parameter_dict()[source]
Return all free parameters as a flat dictionary keyed by name.
Distortion coefficients are named
{channel}_{k}where channel isleftorrightand k is one ofk1, k2, p1, p2, k3(Brown-Conrady convention). Principal-point deltas are included only whenshare_principal_point=False.- Returns:
Mapping from parameter name (str) to value (float, in its native unit: mm, px, or rad).
- Return type:
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct the model from a flat parameter vector.
Inverse of
parameter_vector(). The parameter layout depends onshare_principal_point:- Shared PP (19 params)
- 0:
f_obj_mm1:working_distance_mm2:b_mm3:f_tube_mm4:cx_principal_px5:cy_principal_px6:theta_axis_tilt_rad7:theta_pitch_rad8:telecentric_offset_mm9-13:distortion_left(k1, k2, p1, p2, k3)14-18:distortion_right - Per-channel PP (21 params)
- 0-5: as above6:
delta_cx_diff_px7:delta_cy_diff_px8:theta_axis_tilt_rad9:theta_pitch_rad10:telecentric_offset_mm11-15:distortion_left16-20:distortion_right
- Parameters:
x (ndarray of float, shape (19,) or (21,)) – Flattened parameter vector.
**kwargs – Must include
pixel_pitch_mm(float, mm). May includeimage_size,share_principal_point.
- Return type:
- property n_parameters: int
Number of free parameters in the flattened parameter vector.
Returns 19 when
share_principal_point=True(a single principal point serves both channels) or 21 when each channel carries its own principal-point offset viadelta_cx_diff_pxanddelta_cy_diff_px.The layout is: 6 shared optical parameters (
f_obj_mm,working_distance_mm,b_mm,f_tube_mm,cx,cy), optionally 2 principal-point deltas, 2 global tilt angles (theta_axis_tilt_rad,theta_pitch_rad), one axial telecentric offset/depth parameter (telecentric_offset_mm), and 5 Brown-Conrady distortion coefficients per channel (10 total).
- parameter_dict()[source]
Return the parameter set split into free and fixed groups.
Fixed parameters are quantities treated as known sensor constants:
pixel_pitch_mm,image_width,image_height, andshare_principal_point. Free parameters are the optical, geometric, and distortion coefficients (seeflat_parameter_dict()).- Returns:
{"free": {...}, "fixed": {...}}. All values carry their native units (mm, px, or rad for free; mm or px for fixed).- Return type:
- parameter_vector()[source]
Serialize the model to a flat parameter vector.
Inverse of
from_parameter_vector(). The order matches the layout documented there: shared optical params, optional PP deltas, tilt angles, then left and right distortion tuples.- Return type:
ndarray of float, shape (19,) or (21,)
- principal_point_for_channel(channel)[source]
Compute the principal point in pixels for a given channel.
When
share_principal_point=True, both channels share the same(cx_principal_px, cy_principal_px). WhenFalse, the left channel shifts by-0.5 * deltaand the right by+0.5 * delta, so thatdelta_cx_diff_px/delta_cy_diff_pxencode the total separation between the two principal points.
- ray(u, v, channel)[source]
Compute 3-D rays for pixel coordinates through the CMO paraxial model.
This is the core optical forward model. For each pixel
(u, v)the pipeline is:Convert pixel displacement from the principal point to angular coordinates via the tube lens:
alpha = (pixel - principal) * pixel_pitch / f_tube.Undo Brown-Conrady distortion to obtain undistorted angular coordinates
(alpha_x, alpha_y).Place the effective sub-pupil (ray origin) at
(±b/2, 0, z_pupil)wherez_pupil = working_distance - f_obj + telecentric_offset. The sign is negative for the left channel, positive for right.Determine the object-plane intersection at
(WD * alpha_x, WD * alpha_y, WD).The ray direction is the unit vector from pupil to object-plane point.
If
theta_axis_tilt_radortheta_pitch_radis non-zero, rotate both origin and direction by the corresponding yaw and pitch matrices.
Warning
f_obj_mmandtelecentric_offset_mmare exactly degenerate — only their difference entersz_pupil. Do not assert either value independently; useworking_distance_mm,b_mm,f_tube_mm, andf_obj_mm - telecentric_offset_mm.- Parameters:
u (ndarray) – Horizontal pixel coordinates (column index, 0-based).
v (ndarray) – Vertical pixel coordinates (row index, 0-based).
channel ({"left", "right"})
- Returns:
origin (ndarray, shape (…, 3)) – Ray origin in mm (the effective sub-pupil position).
direction (ndarray, shape (…, 3)) – Unit ray direction vector (dimensionless).
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.physics.CMOPlanePose(R, t)[source]
Bases:
objectRigid pose (rotation + translation) of a planar calibration target.
The target is a plane: its points live at
z = 0in the board-local frame and are mapped to the CMO/world frame byx_world = R @ x_local + t.- Parameters:
R (ndarray)
t (ndarray)
- R
Rotation from the board-local frame to the world frame.
- Type:
ndarray, shape (3, 3)
- t
Board-origin position in the world frame, in millimetres.
- Type:
ndarray, shape (3,)
- local_to_world(xy_plane_mm)[source]
Map 2D board-plane points to 3D world coordinates.
The board-local Z coordinate is taken as 0 (the target is planar), then the rigid pose
x_world = R @ [x, y, 0] + tis applied.- Parameters:
xy_plane_mm (ndarray, shape (N, 2) or (2,)) – Board-plane coordinates in millimetres.
- Returns:
World-frame coordinates in millimetres.
- Return type:
ndarray, shape (N, 3)
- property normal_world: ndarray
World-frame unit normal of the target plane (its local +Z axis rotated by
R).
- world_to_local(xyz_world)[source]
Map 3D world coordinates back into the board-local frame.
Inverse of the rigid map in
local_to_world():x_local = R.T @ (x_world - t). For points lying on the target the returned local Z is ~0.- Parameters:
xyz_world (ndarray, shape (..., 3)) – World-frame coordinates in millimetres.
- Returns:
Board-local coordinates in millimetres, same shape as the input.
- Return type:
ndarray
- class stereocomplex.physics.CMOPlaneTargetSpec(squares_x=11, squares_y=7, square_size_mm=1.0, pixels_per_square=80, pattern='charuco', marker_size_ratio=0.7)[source]
Bases:
objectTextured planar calibration target used by the CMO image generator.
- Parameters:
- squares_x, squares_y
Number of board squares along each axis.
- Type:
- pattern
Target pattern; “charuco” needs OpenCV aruco support.
- Type:
{“checker”, “charuco”}
- inner_corners_local_mm()[source]
Return the board’s inner-corner ids and their board-local coordinates.
Inner corners are the
(squares_x - 1) * (squares_y - 1)chessboard vertices, centred on the board origin.- Returns:
ids (ndarray of int32, shape (M,)) – Corner indices, row-major.
xy (ndarray of float64, shape (M, 2)) – Corner coordinates in board-local millimetres.
- Return type:
tuple[ndarray, ndarray]
- make_texture_u8()[source]
Render the target’s pattern as an 8-bit grayscale texture image.
For
pattern="charuco"an OpenCV ChArUco board is generated (needscv2.aruco); forpattern="checker"a plain checkerboard is drawn.- Returns:
Grayscale texture image.
- Return type:
ndarray of uint8, shape (squares_y * pixels_per_square, squares_x * pixels_per_square)
- Raises:
RuntimeError – If a ChArUco texture is requested but OpenCV aruco support is missing, or texture generation otherwise fails.
- class stereocomplex.physics.CMORayfieldBundleAdjustmentResult(left_model, right_model, poses, success, message, n_observations, incidence_rms_mm, incidence_p95_mm, left_rayfield_rms_mm, right_rayfield_rms_mm, parameter_vector, pose_vectors)[source]
Bases:
objectResult of jointly fitting effective CMO channels and board poses.
- Parameters:
left_model (NonCentralPolynomialChannelModel)
right_model (NonCentralPolynomialChannelModel)
poses (list[CMOPlanePose])
success (bool)
message (str)
n_observations (int)
incidence_rms_mm (float)
incidence_p95_mm (float)
left_rayfield_rms_mm (float)
right_rayfield_rms_mm (float)
parameter_vector (ndarray)
pose_vectors (ndarray)
- left_model, right_model
Fitted per-channel surrogate models.
- poses
Fitted board pose, one per frame.
- Type:
list of CMOPlanePose
- incidence_rms_mm, incidence_p95_mm
RMS and 95th-percentile point-to-ray incidence error, in millimetres.
- Type:
- left_rayfield_rms_mm, right_rayfield_rms_mm
RMS deviation from the measured Zernike rayfield, per channel, in mm.
- Type:
- parameter_vector
Concatenated fitted
[left, right]model parameters.- Type:
ndarray
- pose_vectors
Fitted pose parameters, 6 per frame (rotation vector + translation).
- Type:
ndarray
- class stereocomplex.physics.CMOStereoSpec(left, right, common_aberration=<factory>)[source]
Bases:
objectFull CMO stereo model: two channels plus a shared ray aberration.
- Parameters:
left (CMOChannelSpec)
right (CMOChannelSpec)
common_aberration (PolynomialRayAberration)
- left, right
The two effective channels.
- Type:
- common_aberration
Ray aberration shared by both channels, added to each channel’s own differential aberration.
- Type:
- classmethod symmetric_default(width=1280, height=960, focal_mm=25.0, pitch_um=3.45, baseline_mm=5.0, common_aberration=None, left_distortion=None, right_distortion=None)[source]
Build a symmetric default CMO stereo spec, both channels facing the screen.
The two channels share identical intrinsics and sit symmetrically on the world X axis at +/-
baseline_mm/ 2; mild opposite-sign vignetting is applied to each.- Parameters:
width (int) – Image size in pixels.
height (int) – Image size in pixels.
focal_mm (float) – Lens focal length, in millimetres.
pitch_um (float) – Sensor pixel pitch, in micrometres.
baseline_mm (float) – Distance between the two sub-pupils, in millimetres.
common_aberration (PolynomialRayAberration, optional) – Shared ray aberration; defaults to none.
left_distortion (BrownConrady, optional) – Per-channel distortion; default to none.
right_distortion (BrownConrady, optional) – Per-channel distortion; default to none.
- Returns:
Symmetric stereo specification.
- Return type:
- class stereocomplex.physics.CMOTelecentricChannelModel(rig, channel, name='cmo_telecentric_channel', is_stereo_shared=True)[source]
Bases:
objectSingle-channel facade for a shared telecentric CMO rig.
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct a channel model from a flat parameter vector.
Builds the shared
CMOTelecentricStereoModelfrom x, then wraps it with the channel given bykwargs["channel"](default"left").- Parameters:
x (ndarray of float) – Flattened parameter vector (see
CMOTelecentricStereoModel.from_parameter_vector()).**kwargs – Must include
pixel_pitch_mm. May includeimage_sizeandchannel.
- Return type:
- parameter_vector()[source]
Serialize to a flat parameter vector, delegated to the shared rig.
See
CMOTelecentricStereoModel.parameter_vector().- Return type:
ndarray
- ray(u, v)[source]
Compute 3-D rays, delegating to the shared rig with this channel.
See
CMOTelecentricStereoModel.ray().- Parameters:
u (ndarray)
v (ndarray)
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.physics.CMOTelecentricNModel(channels, name='cmo_telecentric_n', is_stereo_shared=False)[source]
Bases:
objectNamed collection of telecentric CMO channels for N-camera workflows.
- Parameters:
channels (tuple[CMOTelecentricChannelModel, ...])
name (str)
is_stereo_shared (bool)
- channel(name)[source]
Look up a channel by name.
- classmethod from_stereo(stereo)[source]
Wrap a stereo telecentric model as a 2-channel N-camera container.
This is a convenience constructor for the N-camera migration: it takes an existing
CMOTelecentricStereoModeland returns aCMOTelecentricNModelwith channels("left", "right"), allowing stereo models to be used wherever an N-channel container is expected.- Parameters:
stereo (CMOTelecentricStereoModel)
- Return type:
- ray(u, v, channel)[source]
Compute 3-D rays for the named channel.
Delegates to the appropriate
CMOTelecentricChannelModel.
- class stereocomplex.physics.CMOTelecentricStereoModel(f_obj_mm, working_distance_mm, b_mm, cx_principal_px, cy_principal_px, pixel_pitch_mm, f_angular_mm=0.0, theta_convergence_half_rad=0.0, d_y_common=0.0, s_x_L=0.0, s_y_L=0.0, s_x_R=0.0, s_y_R=0.0, s_xy_L=0.0, s_yx_L=0.0, s_xy_R=0.0, s_yx_R=0.0, shared_slopes=True, rho_x_L=0.0, rho_y_L=0.0, rho_x_R=0.0, rho_y_R=0.0, shared_shear=True, q_xx_L=0.0, q_yy_L=0.0, q_xx_R=0.0, q_yy_R=0.0, shared_quadratic=True, image_size=None, name='cmo_telecentric', is_stereo_shared=True, frame_convention='opencv_y_down')[source]
Bases:
objectQuasi-telecentric CMO model with rigid sub-pupil + affine direction field.
Each channel has a constant origin \(S_c\) (the effective sub-pupil) and a direction field that varies affinely across pixels. This captures the quasi-telecentric character of infinity-corrected CMO microscopes where the direction is nearly constant across the field of view.
The direction field is:
\[d_c(u,v) = \operatorname{normalize}\left( d_{c,0} + s_x \tilde{u}\, e_x + s_y \tilde{v}\, e_y \right)\]where \(\tilde{u} = (u - c_x) \cdot p_{\text{pix}} / f_{\text{obj}}\) and \(\tilde{v} = (v - c_y) \cdot p_{\text{pix}} / f_{\text{obj}}\).
- Parameters:
f_obj_mm (float)
working_distance_mm (float)
b_mm (float)
cx_principal_px (float)
cy_principal_px (float)
pixel_pitch_mm (float)
f_angular_mm (float)
theta_convergence_half_rad (float)
d_y_common (float)
s_x_L (float)
s_y_L (float)
s_x_R (float)
s_y_R (float)
s_xy_L (float)
s_yx_L (float)
s_xy_R (float)
s_yx_R (float)
shared_slopes (bool)
rho_x_L (float)
rho_y_L (float)
rho_x_R (float)
rho_y_R (float)
shared_shear (bool)
q_xx_L (float)
q_yy_L (float)
q_xx_R (float)
q_yy_R (float)
shared_quadratic (bool)
name (str)
is_stereo_shared (bool)
frame_convention (str)
- channel(channel)[source]
Return a single-channel facade for the given channel name.
See
CMOPhysicalStereoModel.channel()— the pattern is identical: the returnedCMOTelecentricChannelModeldelegates to this shared rig.- Parameters:
channel ({"left", "right"})
- Return type:
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct the telecentric model from a flat parameter vector.
Layout (12 params, shared slopes + shared shear):
0 f_obj_mm 1 working_distance_mm 2 b_mm 3 cx_principal_px 4 cy_principal_px 5 f_angular_mm 6 theta_convergence_half_rad 7 d_y_common 8 s_x_L (also s_x_R when shared_slopes) 9 s_y_L (also s_y_R when shared_slopes) 10 rho_x_L (also rho_x_R when shared_shear) 11 rho_y_L (also rho_y_R when shared_shear)
When
shared_slopes=False(14 params), indices 10-11 ares_x_R, s_y_Rand shear starts at 12.- Parameters:
x (ndarray of float, shape (12,), (14,), or (16,))
**kwargs – Must include
pixel_pitch_mm(float, mm). May includeimage_size.
- Return type:
- property n_parameters: int
Number of free parameters in the flattened vector.
Public parameter vectors have 12, 14, or 16 entries. The 12-parameter variant uses shared slopes and shared shear; disabling shared slopes yields 14 entries, and disabling shared shear yields 16. There is no supported 10-parameter public vector.
See
from_parameter_vector()for the exact layout.
- parameter_dict()[source]
Return free/fixed parameter groups.
Fixed keys:
pixel_pitch_mm,image_width,image_height(sensor constants). Free keys include all optical/geometric parameters withrhoconsolidated whenshared_shear=Trueands_x/s_yconsolidated whenshared_slopes=True.- Returns:
{"free": {...}, "fixed": {...}}.- Return type:
- parameter_vector()[source]
Serialize the telecentric model to a flat parameter vector.
Inverse of
from_parameter_vector(). The order is: base optical params (10), optionally per-channel slopes (2), then shear coefficients (2 shared or 4 per-channel).- Return type:
ndarray of float, shape (12,), (14,), or (16,)
- ray(u, v, channel)[source]
Compute 3-D rays through the quasi-telecentric CMO model.
For each pixel
(u, v):Convert pixel displacement to normalised angular coordinates \(\tilde{u}, \tilde{v}\) using
f_angular_mm(orf_obj_mmas fallback).Set the chief-ray direction \(d_0\) from the convergence half-angle
theta_convergence_half_radand common vertical offsetd_y_common. The left channel tilts rightward (\(+\sin\theta\)), the right channel leftward (\(-\sin\theta\)).Apply an affine + cross-term + centered-quadratic correction to the direction’s x and y components, then re-normalize.
Place the ray origin at the rigid sub-pupil \((\pm b/2, 0, z_{\text{pupil}})\) plus a small affine pupil shear \((\rho_x \tilde{u}, \rho_y \tilde{v}, 0)\).
This model captures the quasi-telecentric character of infinity-corrected stereo microscopes: the direction field varies only slowly across the field of view, and the origin is nearly constant.
- Parameters:
u (ndarray) – Horizontal pixel coordinates (0-based column index).
v (ndarray) – Vertical pixel coordinates (0-based row index).
channel ({"left", "right"})
- Returns:
origin (ndarray, shape (…, 3)) – Ray origin in mm at the sub-pupil plane.
direction (ndarray, shape (…, 3)) – Unit ray direction vector (dimensionless).
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.physics.CMOWarpedChannelModel(rig, channel, name='cmo_warped_channel', is_stereo_shared=True)[source]
Bases:
objectSingle-channel facade for a shared warped CMO rig.
- Parameters:
rig (CMOWarpedStereoModel)
channel (Literal['left', 'right'])
name (str)
is_stereo_shared (bool)
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct a channel model from a flat parameter vector.
Builds the shared
CMOWarpedStereoModelfrom x, then wraps it with the channel given bykwargs["channel"].- Parameters:
x (ndarray of float) – Flattened parameter vector (see
CMOWarpedStereoModel.from_parameter_vector()).**kwargs – Must include
pixel_pitch_mm,warp_level, andshared_warp. May includeimage_sizeandchannel.
- Return type:
- parameter_vector()[source]
Serialize to a flat parameter vector, delegated to the shared rig.
See
CMOWarpedStereoModel.parameter_vector().- Return type:
ndarray
- ray(u, v)[source]
Compute 3-D rays, delegating to the shared rig with this channel.
See
CMOWarpedStereoModel.ray().- Parameters:
u (ndarray)
v (ndarray)
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.physics.CMOWarpedStereoModel(f_obj_mm, working_distance_mm, b_mm, cx_principal_px, cy_principal_px, pixel_pitch_mm, f_angular_mm=0.0, theta_convergence_half_rad=0.0, d_y_common=0.0, s_x_L=0.0, s_y_L=0.0, s_x_R=0.0, s_y_R=0.0, s_xy_L=0.0, s_yx_L=0.0, s_xy_R=0.0, s_yx_R=0.0, shared_slopes=True, rho_x_L=0.0, rho_y_L=0.0, rho_x_R=0.0, rho_y_R=0.0, shared_shear=True, q_xx_L=0.0, q_yy_L=0.0, q_xx_R=0.0, q_yy_R=0.0, shared_quadratic=True, image_size=None, name='cmo_warped_stereo', is_stereo_shared=True, warp_xi_L=(), warp_eta_L=(), warp_xi_R=(), warp_eta_R=(), warp_level=0, shared_warp=True)[source]
Bases:
objectCMO model with configurable polynomial pixel pre-warp.
Pipeline per channel:
(xi, eta) = W_c(u, v) -- polynomial pre-warp (level 0..3) d = normalize(d_chief + affine correction on warped coords) O = S_c + pupil shear on warped coords
The warp maps pixel coordinates to optical field coordinates before the telecentric direction model acts. This captures non-radial, asymmetric field-angle distortions that a pure affine direction field cannot.
- Parameters:
f_obj_mm (float)
working_distance_mm (float)
b_mm (float)
cx_principal_px (float)
cy_principal_px (float)
pixel_pitch_mm (float)
f_angular_mm (float)
theta_convergence_half_rad (float)
d_y_common (float)
s_x_L (float)
s_y_L (float)
s_x_R (float)
s_y_R (float)
s_xy_L (float)
s_yx_L (float)
s_xy_R (float)
s_yx_R (float)
shared_slopes (bool)
rho_x_L (float)
rho_y_L (float)
rho_x_R (float)
rho_y_R (float)
shared_shear (bool)
q_xx_L (float)
q_yy_L (float)
q_xx_R (float)
q_yy_R (float)
shared_quadratic (bool)
name (str)
is_stereo_shared (bool)
warp_level (int)
shared_warp (bool)
- channel(channel)[source]
Return a single-channel facade for the given channel name.
See
CMOPhysicalStereoModel.channel()— identical pattern.- Parameters:
channel ({"left", "right"})
- Return type:
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct the warped model from a flat parameter vector.
The vector layout is: telecentric base (see
CMOTelecentricStereoModel.from_parameter_vector()), then warp polynomial coefficients in orderwarp_xi_L, warp_eta_L(andwarp_xi_R, warp_eta_Rifshared_warp=False).The number of coefficients per polynomial axis is determined by
warp_level(via_poly_terms_2d()). At level 0 (identity warp), no warp coefficients are present.- Parameters:
x (ndarray of float)
**kwargs – Must include
pixel_pitch_mm(float, mm). Must includewarp_level(int) andshared_warp(bool) for non-zero warp levels. May includeimage_size.
- Return type:
- property n_parameters: int
Number of free parameters including warp coefficients.
The base count is the telecentric parameter count (12, 14, or 16 depending on shared flags). Added to this is the total warp coefficient count from
_n_warp_coeff_total(), which depends onwarp_levelandshared_warp.
- parameter_dict()[source]
Return free/fixed parameter groups with warp coefficients.
Fixed keys are sensor constants. Free keys include telecentric base parameters plus per-channel, per-monomial warp coefficients keyed as
warp_xi_{L|R}_u{pu}v{pv}andwarp_eta_{L|R}_u{pu}v{pv}.- Returns:
{"free": {...}, "fixed": {...}}.- Return type:
- parameter_vector()[source]
Serialize the warped model to a flat parameter vector.
The vector begins with the telecentric base parameters (see
CMOTelecentricStereoModel.parameter_vector()), followed by the warp polynomial coefficients:warp_xi_L,warp_eta_L, and optionallywarp_xi_R,warp_eta_Rwhenshared_warp=False.- Return type:
ndarray of float
- ray(u, v, channel)[source]
Compute 3-D rays through the warped CMO model.
Extends
CMOTelecentricStereoModel.ray()with an initial pixel-domain polynomial warp:If
warp_level > 0, map pixel coordinates(u, v)through the polynomial warp \(W_c\):(xi, eta) = W_c(u, v). Otherwise(xi, eta) = (u, v).Convert the warped coordinates to normalised angular coordinates, then proceed with the telecentric direction model (chief-ray direction + affine/cross/quadratic correction + normalisation, sub-pupil origin + pupil shear).
The warp captures residual field-angle distortions that the affine direction-field model alone cannot represent, while the telecentric base handles the dominant quasi-telecentric behaviour.
- Parameters:
u (ndarray) – Horizontal pixel coordinates.
v (ndarray) – Vertical pixel coordinates.
channel ({"left", "right"})
- Returns:
origin (ndarray, shape (…, 3)) – Ray origin in mm.
direction (ndarray, shape (…, 3)) – Unit ray direction vector.
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.physics.CentralBrownConradyModel(K, k1=0.0, k2=0.0, p1=0.0, p2=0.0, k3=0.0, name='central_brown_conrady')[source]
Bases:
objectCentral Brown-Conrady optical candidate.
It can bend pixel directions, but all rays still share one camera center. Therefore it is intentionally unable to represent a pixel-dependent origin field generated by an inclined parallel plate.
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct model from a parameter vector. K must be passed via kwargs.
- Parameters:
x (ndarray)
- Return type:
- property n_parameters: int
Number of free parameters in this model (0 for pinhole, 5 for Brown-Conrady).
- parameter_vector()[source]
Pack model parameters into a flat vector for optimisation.
- Return type:
ndarray
- class stereocomplex.physics.CentralPinholeModel(K, name='central_pinhole')[source]
Bases:
objectCentral pinhole rayfield used as the zero-parameter baseline.
- Parameters:
K (ndarray)
name (str)
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct model from a parameter vector. K must be passed via kwargs.
- Parameters:
x (ndarray)
- Return type:
- property n_parameters: int
Number of free parameters in this model (0 for pinhole, 5 for Brown-Conrady).
- parameter_vector()[source]
Pack model parameters into a flat vector for optimisation.
- Return type:
ndarray
- class stereocomplex.physics.MultiChannelOpticalModelSelectionReport(channel_reports, best_by_bic, bic_by_model)[source]
Bases:
objectAggregated model-selection report across named camera channels.
- Parameters:
- class stereocomplex.physics.NonCentralPolynomialChannelModel(K, image_size, origin_x_mm=0.0, origin_y_mm=0.0, origin_z_mm=0.0, k1=0.0, k2=0.0, p1=0.0, p2=0.0, k3=0.0, aberration_coeff_x=(), aberration_coeff_y=(), aberration_terms=('x', 'y', 'x2', 'xy', 'y2'), name='polynomial_surrogate_channel')[source]
Bases:
objectFittable effective channel model for ray-space model selection.
This is a generic non-central surrogate: an effective sub-pupil origin (x, y, z free), a central Brown-Conrady distortion, and a low-order polynomial angular aberration field. It can represent a wide range of smooth rayfields — including CMO-like ones — without encoding any specific shared-objective constraint.
- Parameters:
- classmethod default_terms()[source]
Return the default polynomial aberration monomials, in packing order.
- classmethod from_parameter_vector(x, **kwargs)[source]
Rebuild the model from a flat parameter vector.
Inverse of
parameter_vector(); see it for the parameter layout.- Parameters:
x (ndarray, shape (8 + 2 * n_terms,)) – Flattened parameter vector.
**kwargs – Must include
K(3x3 intrinsics) and the image size ascmo_image_sizeorimage_size(a(width, height)pair). May includeaberration_terms.
- Return type:
- Raises:
ValueError – If the image size is missing or
xhas the wrong length.
- property n_parameters: int
8 (3 origin + 5 distortion) + 2 per aberration term.
- Type:
Free-parameter count
- parameter_dict()[source]
Return all free parameters as a flat
{name: value}dictionary.Origin entries are in millimetres; distortion entries are dimensionless; aberration entries are keyed
aberr_x_<term>andaberr_y_<term>.
- parameter_vector()[source]
Pack all free parameters into a flat optimisation vector.
Layout:
[origin_x, origin_y, origin_z (mm), k1, k2, p1, p2, k3, aberration_coeff_x..., aberration_coeff_y...]. Each aberration block followsaberration_termsorder and holdslen(aberration_terms)entries.- Return type:
ndarray, shape (8 + 2 * len(aberration_terms),)
- ray(u, v)[source]
Compute the 3D ray (origin, direction) for each pixel.
Assembles a transient
CMOChannelSpecfrom the model’s free parameters and delegates toCMOChannelRayField.ray().- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
origins, directions – Ray origin (mm, world frame) and unit direction for each pixel.
- Return type:
ndarray, shape (…, 3)
- class stereocomplex.physics.OpticalModelSelectionReport(target_name, candidates, best_by_aic, best_by_bic, best_by_rms, warnings)[source]
Bases:
objectAIC/BIC/RMS comparison across fitted optical model candidates.
- Parameters:
- class stereocomplex.physics.ParallelPlateFromRayfieldFitResult(params, success, message, rayfield_rms_support_mm, rayfield_median_support_mm, rayfield_p95_support_mm, rayfield_rms_full_mm, rayfield_median_full_mm, rayfield_p95_full_mm, n_support_samples, n_full_samples, parameter_error=None)[source]
Bases:
objectParallel-plate physical fit and rayfield residual diagnostics.
- Parameters:
params (PinholeParallelPlateFitParams)
success (bool)
message (str)
rayfield_rms_support_mm (float)
rayfield_median_support_mm (float)
rayfield_p95_support_mm (float)
rayfield_rms_full_mm (float)
rayfield_median_full_mm (float)
rayfield_p95_full_mm (float)
n_support_samples (int)
n_full_samples (int)
- class stereocomplex.physics.PhysicalModelFitResult(model_name, model, success, message, n_parameters, n_samples, n_residual_scalars, rss, rms_mm, median_mm, p95_mm, support_rms_mm, full_grid_rms_mm, aic, bic, parameter_vector, parameter_dict)[source]
Bases:
objectFit metrics and optimal parameters for one physical rayfield model.
- Parameters:
- class stereocomplex.physics.PhysicalModelSpec(name, model_class, initial_parameters, bounds=None, model_kwargs=None)[source]
Bases:
objectSpecification for one physical candidate to fit or score.
- class stereocomplex.physics.PinholeParallelPlateFitParams(alpha_deg, beta_deg, thickness_mm, eta=1.5, d1_mm=80.0)[source]
Bases:
objectPhysical pinhole + inclined parallel-plate parameters.
Units are millimetres and degrees. d1_mm is kept for ray generation, but is not fitted by default because changing it only moves the plate exit point along the emergent ray and therefore does not change the 3D line.
- class stereocomplex.physics.PinholeParallelPlateModel(K, params)[source]
Bases:
PinholeParallelPlateRayFieldPhysical pinhole + inclined parallel-plate model-selection candidate.
- Parameters:
K (np.ndarray)
params (PinholeParallelPlateFitParams)
- classmethod from_parameter_vector(x, **kwargs)[source]
Reconstruct model from a parameter vector. K must be passed via kwargs.
- Parameters:
x (ndarray)
- Return type:
- class stereocomplex.physics.PinholeParallelPlateRayField(K, params)[source]
Bases:
objectSmall adapter exposing a .ray(u, v) method for a fitted plate model.
- Parameters:
K (np.ndarray)
params (PinholeParallelPlateFitParams)
- class stereocomplex.physics.PolynomialRayAberration(coeff_x=<factory>, coeff_y=<factory>)[source]
Bases:
objectLow-order polynomial perturbation of a ray’s normalised direction.
Models residual aberrations the Brown-Conrady term does not capture, as a cubic polynomial in the normalised image coordinates
(x, y). Each of the two output components carries its own sparse coefficient dictionary.- coeff_x, coeff_y
Maps a monomial name to its coefficient, for the x and y direction perturbation respectively. Allowed monomials:
1, x, y, x2, xy, y2, x3, x2y, xy2, y3. Absent terms are treated as zero.
- add(other)[source]
Return the coefficient-wise sum of this aberration and
other.Coefficients present in only one operand are kept; coefficients present in both are added. Used to compose a per-channel aberration on top of a shared one.
- Parameters:
other (PolynomialRayAberration) – Aberration whose coefficients are added to this one.
- Returns:
New instance holding the merged coefficients.
- Return type:
- delta(x, y)[source]
Evaluate the polynomial direction perturbation at normalised coordinates.
- Parameters:
x (ndarray) – Normalised image coordinates (unitless).
y (ndarray) – Normalised image coordinates (unitless).
- Returns:
dx, dy – Additive perturbation of the normalised ray direction, same shape as the inputs.
- Return type:
ndarray
- Raises:
ValueError – If a coefficient dictionary contains an unknown monomial name.
- class stereocomplex.physics.SensorWarp(du_coeff_px=<factory>, dv_coeff_px=<factory>)[source]
Bases:
objectLow-order polynomial deformation of the image plane, expressed in pixels.
Models small sensor-mounting / readout geometry errors as a cubic polynomial in image coordinates normalised by the principal-point offset.
- du_coeff_px, dv_coeff_px
Maps a monomial name to its coefficient (in pixels) for the u and v pixel offset. Allowed monomials:
1, x, y, x2, xy, y2, x3, x2y, xy2, y3. Absent terms are treated as zero.
- delta_px(uv, intr)[source]
Evaluate the sensor-plane warp offset, in pixels, at given pixels.
The polynomial is evaluated in coordinates normalised by the principal point:
x = (u - cx) / max(|cx|, 1)and likewise fory.- Parameters:
uv (ndarray, shape (..., 2)) – Pixel coordinates.
intr (CMOIntrinsics) – Intrinsics supplying the principal point used for normalisation.
- Returns:
Pixel offset
(du, dv)to add touv.- Return type:
ndarray, shape (…, 2)
- Raises:
ValueError – If a coefficient dictionary contains an unknown monomial name.
- class stereocomplex.physics.Vignetting(strength=0.0, floor=0.25, x_shift=0.0, y_shift=0.0)[source]
Bases:
objectMultiplicative radial shading (vignetting) of the rendered image.
Brightness falls off quadratically from a (possibly shifted) centre and is clamped to a floor so it never reaches zero.
- x_shift, y_shift
Shift of the vignetting centre, in principal-point-normalised units.
- Type:
- gain(intr)[source]
Compute the per-pixel multiplicative vignetting gain map.
The gain is
1 - strength * (x^2 + y^2)in principal-point-normalised coordinates, clamped to[floor, 1].- Parameters:
intr (CMOIntrinsics) – Intrinsics defining the image size and principal point.
- Returns:
Multiplicative gain in
[floor, 1]to apply to the image.- Return type:
ndarray, shape (height, width)
- stereocomplex.physics.aggregate_model_selection_reports(channel_reports)[source]
Aggregate per-channel model-selection reports by summing BIC values.
- Parameters:
channel_reports (dict[str, OpticalModelSelectionReport])
- Return type:
- stereocomplex.physics.apply_blur_noise(img_u8, blur_sigma_px, noise_std_gray, rng)[source]
Simulate acquisition defects: Gaussian blur followed by Gaussian noise.
- Parameters:
img_u8 (ndarray of uint8) – Clean rendered image.
blur_sigma_px (float) – Gaussian blur standard deviation, in pixels; 0 disables blur (also a no-op when OpenCV is unavailable).
noise_std_gray (float) – Standard deviation of the additive Gaussian noise, in gray levels; 0 disables noise.
rng (numpy.random.Generator) – Random generator used to draw the noise.
- Returns:
Degraded image.
- Return type:
ndarray of uint8
- stereocomplex.physics.apply_sensor_warp(img_u8, warp, intr)[source]
Apply a sensor-plane deformation to an image by inverse mapping.
Each output pixel is sampled from
(u, v) - SensorWarp.delta_pxof the input. A no-op when the warp has no coefficients or OpenCV is unavailable.- Parameters:
img_u8 (ndarray of uint8) – Input grayscale image.
warp (SensorWarp) – Image-plane deformation to apply.
intr (CMOIntrinsics) – Intrinsics defining the image grid and principal point.
- Returns:
Warped image, same shape as the input.
- Return type:
ndarray of uint8
- stereocomplex.physics.brown_conrady_distort_normalized(x, y, k1, k2, p1, p2, k3)[source]
Apply Brown-Conrady distortion to normalised camera coordinates.
Uses the standard OpenCV convention: xd = x * (1 + k1*r2 + k2*r4 + k3*r6) + 2*p1*x*y + p2*(r2 + 2*x^2) yd = y * (1 + k1*r2 + k2*r4 + k3*r6) + p1*(r2 + 2*y^2) + 2*p2*x*y where r2 = x^2 + y^2.
- Parameters:
x (ndarray) – Undistorted normalised image coordinates (unitless).
y (ndarray) – Undistorted normalised image coordinates (unitless).
k1 (float) – Radial distortion coefficients (k3 is optional, often 0).
k2 (float) – Radial distortion coefficients (k3 is optional, often 0).
k3 (float) – Radial distortion coefficients (k3 is optional, often 0).
p1 (float) – Tangential distortion coefficients.
p2 (float) – Tangential distortion coefficients.
- Returns:
xd, yd – Distorted normalised coordinates (unitless).
- Return type:
ndarray
- stereocomplex.physics.compute_cmo_zernike_residuals(cmo_model, zernike_left, zernike_right, grid_shape=(17, 13), image_size=None, zernike_order=4)[source]
Compute direction/moment residuals between a CMO model and Zernike rayfield.
Returns delta_d (deg), delta_m (mm), and Zernike modal projection of the direction residual field.
- stereocomplex.physics.default_physical_model_specs(*, include_telecentric=False)[source]
Return the standard candidate set used in the parallel-plate notebook.
Set include_telecentric to True to add the quasi-telecentric CMO candidate.
- Parameters:
include_telecentric (bool)
- Return type:
- stereocomplex.physics.fit_cmo_physical_stereo_model_to_rayfields(left_field, right_field, image_size, initial_parameters, bounds=None, *, pixel_pitch_mm, z_planes=(50.0, 250.0), grid_shape=(17, 13), support_pixels_left=None, support_pixels_right=None, support_weight=1.0, full_grid_weight=0.25, robust_loss='huber', max_nfev=2000)[source]
Fit the shared physical CMO rig to left and right measured Zernike rayfields.
This entry point fits the shared 19/21-parameter paraxial CMO model: baseline, working distance, objective focal length, tube focal length, principal-point terms, two global tilt angles, one axial telecentric offset/depth parameter, and per-channel Brown-Conrady distortion. It does not fit the paper’s 26-parameter CMO + per-arm SE(3) bundle-adjustment model.
- Parameters:
left_field (ZernikeRayField) – Measured left-channel rayfield (origin + direction).
right_field (ZernikeRayField) – Measured right-channel rayfield.
image_size ((int, int)) – Sensor dimensions in pixels (width, height).
initial_parameters (ndarray, shape (19,) or (21,)) – Starting parameter vector. 19 = shared PP, 21 = aligned PP.
bounds (tuple of ndarray, optional) – Lower and upper bounds for the parameters.
pixel_pitch_mm (float) – Sensor pixel pitch in millimetres.
z_planes ((float, float)) – Two z-planes in mm (default 50, 250) where ray intersections are evaluated.
grid_shape ((int, int)) – Subsampling grid for the full-image residual.
support_pixels_left (ndarray, optional) – Observed-pixel coords (N, 2) whose ray gap is up-weighted.
support_pixels_right (ndarray, optional) – Observed-pixel coords (N, 2) whose ray gap is up-weighted.
support_weight (float) – Relative weight of support-pixel vs full-grid residuals.
full_grid_weight (float) – Relative weight of the full-grid residual term.
robust_loss (str) –
"huber"or"soft_l1"— robust loss for least_squares.max_nfev (int) – Maximum number of function evaluations for the optimiser.
- Returns:
Dataclass result object with
parameter_vector(optimal params),message,success,model(the fitted CMO stereo model), and diagnostics.- Return type:
Notes
The two-zone loss (sparse support + subsampled full grid) balances fidelity to observation pixels with smooth ray-space behaviour across the image. It is a rayfield-to-model fit, not the final per-arm SE(3) paper BA.
- stereocomplex.physics.fit_cmo_stereo_model_and_poses_from_zernike_rayfields(left_field, right_field, K, image_size, object_points, left_pixels, right_pixels, pose_initials, *, initial_left_parameters=None, initial_right_parameters=None, parameter_bounds=None, aberration_terms=None, z_planes=(80.0, 260.0), incidence_weight=1.0, rayfield_weight=0.25, pose_regularization=0.0, max_nfev=800, robust_loss='huber')[source]
Jointly fit effective CMO channel parameters and per-frame board poses.
The measured left/right Zernike rayfields supply the pixel-to-line observations. The fit minimises two coupled residual terms:
incidence: each ChArUco object point must lie on the back-projected ray of its observed pixel (point-to-line distance);
rayfield anchor: the CMO model rays must stay close to the measured Zernike rayfield, sampled on two depth planes.
A robust loss down-weights outliers.
- Parameters:
left_field (ZernikeRayField) – Measured rayfields providing the per-channel ray anchor.
right_field (ZernikeRayField) – Measured rayfields providing the per-channel ray anchor.
K (ndarray, shape (3, 3)) – Shared pinhole intrinsics used to seed the surrogate channels.
image_size (tuple of 2 int) – Image
(width, height)in pixels.object_points (ndarray or list of ndarray) – ChArUco corner coordinates in board millimetres — one
(M, 2)array per frame, or a single(M, 2)array shared by all frames.left_pixels (list of ndarray) – Observed corner pixels per frame, one
(M, 2)array each.right_pixels (list of ndarray) – Observed corner pixels per frame, one
(M, 2)array each.pose_initials (list of CMOPlanePose) – Initial board pose, one per frame.
initial_left_parameters (ndarray, optional) – Initial per-channel parameter vectors; default to zeros.
initial_right_parameters (ndarray, optional) – Initial per-channel parameter vectors; default to zeros.
parameter_bounds (tuple of (ndarray, ndarray), optional) – Lower/upper bounds for the per-channel parameters; sensible defaults are used when omitted.
aberration_terms (tuple of str, optional) – Polynomial aberration monomials to fit.
z_planes (tuple of 2 float) – The two depth planes (mm) on which the rayfield anchor is evaluated.
incidence_weight (float) – Weight of the point-to-ray incidence residual.
rayfield_weight (float) – Weight of the rayfield-anchor residual.
pose_regularization (float) – L2 penalty pulling poses toward their initial values.
max_nfev (int) – Maximum optimiser function evaluations.
robust_loss (str) – SciPy
least_squaresloss name (e.g."huber","linear").
- Returns:
Fitted models, poses, and incidence / rayfield diagnostics.
- Return type:
- stereocomplex.physics.fit_cmo_telecentric_model_to_rayfields(left_field, right_field, image_size, initial_parameters, *, pixel_pitch_mm, z_planes=(50.0, 250.0), grid_shape=(17, 13), full_grid_weight=0.0, max_nfev=500)[source]
Fit the telecentric CMO model to left and right measured Zernike rayfields.
This variant assumes telecentricity in object space, reducing the parameter count compared to the full physical model. It fits baseline, working distance, and per-channel sub-pupil positions while keeping the objective focal length fixed at infinity in object space.
- Parameters:
left_field (ZernikeRayField) – Measured left-channel rayfield (origin field + direction field).
right_field (ZernikeRayField) – Measured right-channel rayfield.
image_size ((int, int)) – Sensor dimensions in pixels (width, height).
initial_parameters (ndarray, shape (12,), (14,), or (16,)) – Starting parameter vector. The supported variants are shared slopes/shear (12), per-channel slopes with shared shear (14), and per-channel slopes plus per-channel shear (16).
pixel_pitch_mm (float) – Sensor pixel pitch in millimetres.
z_planes ((float, float)) – Two z-planes in mm (default 50, 250) for ray intersection evaluation.
grid_shape ((int, int)) – Subsampling grid (width, height) for the full-image residual.
full_grid_weight (float) – Relative weight of the full-grid residual term (0 = only support pixels).
max_nfev (int) – Maximum number of function evaluations for the optimiser.
- Returns:
Dataclass result object with
parameter_vector(optimal parameters),message,success, andmodel(the fitted CMOTelecentricStereoModel).- Return type:
- stereocomplex.physics.fit_cmo_warped_model_to_rayfields(left_field, right_field, image_size, initial_parameters, *, pixel_pitch_mm, z_planes=(50.0, 250.0), grid_shape=(17, 13), max_nfev=500, warp_level=0, shared_warp=True)[source]
Fit the warped CMO model with sensor-plane polynomial corrections.
The most flexible CMO variant. It adds a per-channel 2-D polynomial warp on the sensor plane before ray evaluation, capturing residual non-idealities beyond the physical model.
- Parameters:
left_field (ZernikeRayField) – Measured left-channel rayfield.
right_field (ZernikeRayField) – Measured right-channel rayfield.
image_size ((int, int)) – Sensor dimensions in pixels (width, height).
initial_parameters (ndarray) – Starting parameter vector including CMO rig + warp coefficients.
pixel_pitch_mm (float) – Sensor pixel pitch in millimetres.
z_planes ((float, float)) – Two z-planes in mm (default 50, 250) for ray intersection evaluation.
grid_shape ((int, int)) – Subsampling grid for the full-image residual.
max_nfev (int) – Maximum number of function evaluations.
warp_level (int) – Polynomial level for the sensor-plane warp.
shared_warp (bool) – If True, left and right channels share the same warp coefficients.
- Returns:
Dataclass result object with
parameter_vector(optimal params),message,success, andmodel(the fitted CMOWarpedStereoModel).- Return type:
- stereocomplex.physics.fit_parallel_plate_to_zernike_rayfield(zernike_field, K, image_size, initial_params=None, eta=1.5, z_planes=(100.0, 1000.0), grid_shape=(25, 19), support_pixels=None, support_weight=1.0, full_grid_weight=0.25, fit_eta=False, robust_loss='huber', oracle_params=None)[source]
Fit a compact pinhole + plate model to an already measured rayfield.
The target rayfield is treated as a geometric observable. The residual is evaluated in ray space by intersecting both rayfields with two z-planes; raw ray origins are never compared directly.
- Parameters:
K (ndarray)
initial_params (PinholeParallelPlateFitParams | None)
eta (float)
support_pixels (ndarray | None)
support_weight (float)
full_grid_weight (float)
fit_eta (bool)
robust_loss (str)
oracle_params (PinholeParallelPlateFitParams | ParallelPlateSyntheticParams | None)
- Return type:
- stereocomplex.physics.fit_physical_model_to_rayfield(model_class, target_field, K, image_size, initial_parameters=None, bounds=None, z_planes=(100.0, 1000.0), grid_shape=(25, 19), support_pixels=None, support_weight=1.0, full_grid_weight=0.25, robust_loss='huber', max_nfev=2000, name=None, **model_kwargs)[source]
Fit a physical model candidate to a measured rayfield in ray space.
This is the core model selection routine. Given a measured rayfield and a physical model class, it optimises the model parameters so that the model rays best reproduce the measured rays, then returns a fit result with RMS error and parameter estimates.
- Parameters:
model_class (type) – Physical model class with
ray(u,v) -> (origin, direction).target_field (ZernikeRayField) – Measured rayfield to match (origin + direction field).
K (ndarray, shape (3, 3)) – Camera matrix.
image_size ((int, int)) – Sensor dimensions in pixels (width, height).
initial_parameters (ndarray, optional) – Starting parameter vector (defaults to model_class default).
bounds ((lo, hi), optional) – Lower and upper bounds for the parameters.
z_planes ((float, float)) – Two z-planes in mm (default 100, 1000) for ray intersection evaluation.
grid_shape ((int, int)) – Subsampling grid for the full-image residual.
support_pixels (ndarray, optional) – Observed-pixel coords (N, 2) whose ray gap is up-weighted.
support_weight (float) – Relative weight of support-pixel residuals.
full_grid_weight (float) – Relative weight of the full-grid residual term.
robust_loss (str) –
"huber"or"soft_l1"— robust loss for least_squares.max_nfev (int) – Maximum number of function evaluations.
name (str, optional) – Human-readable model name for reporting.
**model_kwargs – Additional keyword arguments forwarded to the model constructor.
- Returns:
Dataclass result object with
parameter_vector(optimal parameters),rms_mm,success, andmodel(the fitted instance).- Return type:
- stereocomplex.physics.generate_cmo_plane_dataset(out_dir, cmo, target, poses, image_format='png', blur_sigma_px=0.0, noise_std_gray=2.0, seed=0)[source]
Render and write a full CMO stereo planar-target dataset to disk.
For each pose, both channels are rendered with the CMO physics model and the target inner corners are projected to ground-truth pixels. The output directory receives
left/andright/PNG folders,meta.json,frames.jsonlandgt_charuco_corners.npz.- Parameters:
out_dir (Path) – Output directory; created if missing.
cmo (CMOStereoSpec) – Stereo CMO model used for rendering and ground-truth projection.
target (CMOPlaneTargetSpec) – Planar target geometry.
poses (list of CMOPlanePose) – One target pose per frame.
image_format ({"png"}) – Output image format (only PNG is supported).
blur_sigma_px (float) – Gaussian blur sigma in pixels applied to the rendered images.
noise_std_gray (float) – Gaussian noise standard deviation, in gray levels.
seed (int) – Seed for the noise random generator.
- Raises:
ValueError – If
image_formatis not “png”.- Return type:
None
- stereocomplex.physics.intersect_ray_with_z_plane(origin_points, d, z)[source]
Intersect one or more rays with a horizontal z-plane at a given depth.
- Parameters:
origin_points (ndarray, shape (N, 3)) – Ray origins in world coordinates, in millimetres.
d (ndarray, shape (N, 3)) – Ray directions (unit vectors).
z (float) – Z-coordinate of the target plane in millimetres.
- Returns:
Intersection points in millimetres.
- Return type:
ndarray, shape (N, 3)
- Raises:
ValueError – If any ray direction has a z-component smaller than 1e-12 in absolute value (ray is parallel to the plane).
- stereocomplex.physics.intersect_rays_with_plane(origins, directions, pose)[source]
Intersect a dense rayfield with a planar target.
Solves, per ray, for
tausuch thatorigin + tau * directionlies on the plane throughpose.twith normalpose.normal_world.- Parameters:
origins (ndarray, shape (..., 3)) – Ray origins (mm) and directions in the world frame.
directions (ndarray, shape (..., 3)) – Ray origins (mm) and directions in the world frame.
pose (CMOPlanePose) – Pose of the target plane.
- Returns:
X (ndarray, shape (…, 3)) – Intersection points in world millimetres (NaN where the ray is parallel to the plane).
valid (ndarray of bool, shape (…)) – True where the intersection is finite and in front of the ray origin (
tau > 0).
- Return type:
tuple[ndarray, ndarray]
- stereocomplex.physics.make_reference_cmo_scenario()[source]
Build a canonical CMO test scenario: stereo model, target and poses.
Returns a fixed, reproducible setup — a symmetric CMO stereo head carrying a shared aberration plus per-channel distortion / aberration asymmetries, a ChArUco planar target, and a list of target poses — used as a known-truth case for tests and demonstrations.
- Returns:
cmo (CMOStereoSpec) – The stereo CMO model.
target (CMOPlaneTargetSpec) – The planar ChArUco target.
poses (list of CMOPlanePose) – Target poses spanning the working volume.
- Return type:
tuple[CMOStereoSpec, CMOPlaneTargetSpec, list[CMOPlanePose]]
- stereocomplex.physics.normalize_vectors(v, eps=1e-15)[source]
Normalize an array of vectors to unit length along the last axis.
- Parameters:
v (ndarray, shape (..., D)) – Stack of vectors; the last axis holds the vector components.
eps (float) – Lower bound on the divisor norm, so a (near-)zero vector stays finite instead of producing a division by zero.
- Returns:
Each vector divided by its Euclidean norm (or by
epswhen that norm is smaller thaneps).- Return type:
ndarray, shape (…, D)
- stereocomplex.physics.pinhole_parallel_plate_ray_from_pixel(u, v, K, params)[source]
Compute the 3-D ray (origin, direction) for a pixel through a pinhole camera with an inclined parallel plate in front of the sensor.
The plate shifts the apparent ray origin while preserving the direction.
- Parameters:
u (ndarray) – Pixel x-coordinates.
v (ndarray) – Pixel y-coordinates.
K (ndarray, shape (3, 3)) – Camera matrix.
params (PinholeParallelPlateFitParams) – Plate geometry (normal, thickness, refractive index, distance).
- Returns:
(origin, direction) – Ray origins in mm and unit directions, each shape (N, 3).
- Return type:
tuple of ndarray
- stereocomplex.physics.polynomial_channel_parameters_from_spec(channel, common_aberration=None, aberration_terms=None)[source]
Convert a CMOChannelSpec into a NonCentralPolynomialChannelModel vector.
The fittable CMO surrogate is per-channel: its polynomial aberration is the sum of the shared (common) CMO aberration and the channel’s differential aberration. This packs that effective channel into the flat vector the surrogate model optimises.
- Parameters:
channel (CMOChannelSpec) – Channel to convert.
common_aberration (PolynomialRayAberration, optional) – Shared aberration; defaults to none.
aberration_terms (tuple of str, optional) – Monomials to keep; defaults to
NonCentralPolynomialChannelModel.default_terms().
- Returns:
Parameter vector in
NonCentralPolynomialChannelModel.parameter_vector()layout.- Return type:
ndarray, shape (8 + 2 * len(aberration_terms),)
- stereocomplex.physics.pose_from_euler_xyz(rx, ry, rz, t_xyz)[source]
Build a planar-target pose from intrinsic XYZ Euler angles and a translation.
The rotation is composed as
R = Rz(rz) @ Ry(ry) @ Rx(rx): the board is rotated first about X, then Y, then Z, all in the CMO/world frame.- Parameters:
- Returns:
Rigid pose mapping board-plane coordinates to the world frame.
- Return type:
- stereocomplex.physics.project_cmo_points(channel, common_aberration, xyz_world_mm, *, max_nfev=40)[source]
Project world points by inverting the channel’s pixel-to-ray model.
The exact sparse counterpart of the renderer’s pixel -> ray -> plane model: for each point, the pixel whose CMO ray passes closest to the point (minimum point-to-ray / Plücker distance) is found by least squares.
project_cmo_points_approx()provides the optimiser initialisation.- Parameters:
channel (CMOChannelSpec) – Target channel.
common_aberration (PolynomialRayAberration) – Shared aberration added to the channel’s differential aberration.
xyz_world_mm (ndarray, shape (N, 3)) – World points to project, in millimetres.
max_nfev (int) – Maximum optimiser function evaluations per point.
- Returns:
Sub-pixel pixel coordinates minimising point-to-ray distance.
- Return type:
ndarray, shape (N, 2)
- stereocomplex.physics.project_cmo_points_approx(channel, common_aberration, xyz_world_mm)[source]
First-order (pinhole-like) forward projection of world points into a channel.
Transforms points into the channel camera frame, applies the perspective divide, the polynomial aberration, Brown-Conrady distortion and the sensor warp. This is an approximation — it ignores the non-central sub-pupil geometry — used mainly to seed the exact
project_cmo_points().- Parameters:
channel (CMOChannelSpec) – Target channel.
common_aberration (PolynomialRayAberration) – Shared aberration added to the channel’s differential aberration.
xyz_world_mm (ndarray, shape (N, 3)) – World points to project, in millimetres.
- Returns:
Pixel coordinates; rows behind the camera (
z <= 0) are NaN.- Return type:
ndarray, shape (N, 2)
- stereocomplex.physics.project_cmo_target_corners(cmo, target, pose)[source]
Project the target’s inner corners into both CMO channels.
Inner corners are placed in the world frame via
poseand projected withproject_cmo_points(); only corners visible (in bounds) in both channels are kept.- Parameters:
cmo (CMOStereoSpec) – Stereo model.
target (CMOPlaneTargetSpec) – Planar target geometry.
pose (CMOPlanePose) – Pose of the target in the world frame.
- Returns:
Keys:
corner_id(ndarray int),XYZ_world_mm(N, 3 float32),uv_left_pxanduv_right_px(N, 2 float32) — restricted to corners visible in both channels.- Return type:
- stereocomplex.physics.rayfield_two_plane_residuals(field_a, field_b, pixels, z_planes=(100.0, 1000.0))[source]
Compare two rayfields by intersections with two reference z-planes.
Both field_a and field_b must declare
frame_convention = "opencv_y_down"(the internal StereoComplex convention). AValueErroris raised if either declares a different convention.
- stereocomplex.physics.rays_from_cmo_pixels(channel, common_aberration)[source]
Compute the dense per-pixel CMO rayfield of a channel, in world coordinates.
- Parameters:
channel (CMOChannelSpec) – Channel whose optics define the rays.
common_aberration (PolynomialRayAberration) – Shared aberration added to the channel’s differential aberration.
- Returns:
origins, directions – Per-pixel ray origin (mm) and unit direction in the world frame.
- Return type:
ndarray, shape (H, W, 3)
- stereocomplex.physics.render_cmo_channel_image(cmo, channel, target, pose, texture_u8, interpolation='linear', background_gray=20, blur_sigma_px=0.0, noise_std_gray=0.0, rng=None)[source]
Render one CMO channel image: pixel -> physical ray -> target-plane sampling.
For every pixel the channel’s physical ray is traced, intersected with the posed target plane, and the target texture is sampled at the hit point. Pixels that miss the target get
background_gray; vignetting, then optional blur and noise, are applied last.- Parameters:
cmo (CMOStereoSpec) – Stereo model (supplies the shared common aberration).
channel (CMOChannelSpec) – Channel to render.
target (CMOPlaneTargetSpec) – Planar target geometry.
pose (CMOPlanePose) – Pose of the target in the world frame.
texture_u8 (ndarray of uint8) – Target texture, e.g. from
CMOPlaneTargetSpec.make_texture_u8().interpolation ({"nearest", "linear", "cubic", "lanczos4"}) – Texture resampling kernel.
background_gray (int) – Gray level (0-255) for pixels that miss the target.
blur_sigma_px (float) – Gaussian blur sigma in pixels (0 disables).
noise_std_gray (float) – Gaussian noise standard deviation in gray levels (0 disables).
rng (numpy.random.Generator, optional) – Random generator for the noise; a default-seeded one is used if omitted.
- Returns:
The rendered channel image.
- Return type:
ndarray of uint8, shape (height, width)
- stereocomplex.physics.reprojection_guard_penalty(px_rms, *, threshold_px=1.5, n_pixel_observations, hard_penalty=1000000.0, alpha=1.0)[source]
Penalty term for models exceeding a pixel reprojection threshold.
Returns 0 if
px_rms <= threshold_px. Otherwise returns a hard barrier plus a log-ratio term that ranks non-usable models among themselves:penalty = hard_penalty + alpha * n_obs * log((px_rms / threshold)^2)
This is designed to be added to a ray-space BIC to produce an operational
bic_usablethat enforces a usability constraint.Notes
This penalty is not a statistical likelihood term. It is an operational guard: a model whose direct pixel reprojection RMS is above
threshold_pxis considered non-usable for calibration, even if it explains the rayfield compactly.
- stereocomplex.physics.rotx(a)[source]
Active 3x3 rotation matrix about the world X axis (right-hand rule);
ain radians.- Parameters:
a (float)
- Return type:
ndarray
- stereocomplex.physics.roty(a)[source]
Active 3x3 rotation matrix about the world Y axis (right-hand rule);
ain radians.- Parameters:
a (float)
- Return type:
ndarray
- stereocomplex.physics.rotz(a)[source]
Active 3x3 rotation matrix about the world Z axis (right-hand rule);
ain radians.- Parameters:
a (float)
- Return type:
ndarray
- stereocomplex.physics.sample_cmo_target_texture(target, texture_u8, local_xy_mm, inside, interpolation='linear')[source]
Sample a target texture at board-local metric coordinates.
Board-local millimetre coordinates are mapped to texture pixel coordinates, then resampled (via
cv2.remapwhen OpenCV is available, else nearest-neighbour). Samples outsideinsideare set to 0.- Parameters:
target (CMOPlaneTargetSpec) – Target geometry (supplies the board width/height in mm).
texture_u8 (ndarray of uint8, shape (Ht, Wt)) – Texture image to sample.
local_xy_mm (ndarray, shape (..., 2)) – Board-local coordinates, in millimetres.
inside (ndarray of bool, shape (...)) – Mask of samples that fall on the physical target.
interpolation ({"nearest", "linear", "cubic", "lanczos4"}) – Resampling kernel.
- Returns:
Sampled grayscale values, 0 outside
inside.- Return type:
ndarray of uint8
- stereocomplex.physics.save_gray(path, img_u8)[source]
Write a grayscale image to disk as a PNG.
Uses Pillow when available, otherwise OpenCV.
- Parameters:
path (Path) – Destination file path; parent directories are created as needed.
img_u8 (ndarray of uint8) – Grayscale image to save.
- Raises:
RuntimeError – If neither Pillow nor OpenCV is available, or the write fails.
- Return type:
None
- stereocomplex.physics.select_physical_model_from_rayfield(target_field, candidate_specs, K, image_size, z_planes=(100.0, 1000.0), grid_shape=(25, 19), support_pixels=None, support_weight=1.0, full_grid_weight=0.25, max_nfev=2000, target_right=None, K_right=None, support_pixels_right=None)[source]
Fit candidate physical models and select the best in ray space.
With only
target_fieldthis keeps the historical single-channel behavior. Whentarget_rightis provided, non-shared candidates are fitted independently to both channels and aggregated, while stereo-shared candidates such asCMOPhysicalStereoModelare fitted once with their shared parameter vector.- Parameters:
candidate_specs (list[PhysicalModelSpec] | None)
K (ndarray)
support_pixels (ndarray | None)
support_weight (float)
full_grid_weight (float)
max_nfev (int)
K_right (ndarray | None)
support_pixels_right (ndarray | None)
- Return type:
- stereocomplex.physics.undistort_brown_normalized(xd, yd, k1, k2, p1, p2, k3, n_iter=10)[source]
Invert Brown-Conrady distortion by fixed-point iteration.
The model-selection use case only needs a stable central candidate, not a high-performance undistorter. The iteration is vectorized and initialized at the distorted normalized coordinates.
- stereocomplex.physics.usable_bic(bic_ray, px_rms, *, threshold_px=1.5, n_pixel_observations, hard_penalty=1000000.0, alpha=1.0)[source]
Return ray-space BIC plus an operational pixel-RMS usability guard.
bic_rayremains the Gaussian BIC computed from ray-space residuals.usable_bicadds a hard penalty when the same model is not usable in direct reprojection, according tothreshold_px.This deliberately separates two questions:
ray-space BIC: which optical family explains the measured rayfield?
usable BIC: which model is accurate enough for calibration use?
Zernike rayfields — stereocomplex.rayfields
Zernike origin / ray-field models and the N-camera rayfield container.
Zernike-based ray-field models for non-central stereo calibration.
- class stereocomplex.rayfields.MultiCameraZernikeRayField(channels)[source]
Bases:
objectOrdered collection of named Zernike rayfields, one per camera.
Container for an N-camera calibration result: each camera contributes one
ZernikeRayField, addressed by name. Channel names must be unique and non-empty.- Parameters:
channels (tuple[ZernikeRayFieldChannel, ...])
- channels
The per-camera rayfields, in a fixed order.
- Type:
- channel(name)[source]
Return the rayfield of the named channel.
- classmethod from_camera_configs(intrinsics_by_channel, configs_by_channel)[source]
Build zero-initialised rayfields for a set of cameras.
Creates one
ZernikeRayFieldper channel from its intrinsics and Zernike configuration, with all coefficients at zero (i.e. the plain pinhole model). The two mappings must cover exactly the same set of channel names.- Parameters:
intrinsics_by_channel (dict[str, ndarray]) – 3x3 pinhole intrinsic matrix per channel.
configs_by_channel (dict[str, ZernikeOriginFieldConfig]) – Zernike field configuration per channel.
- Return type:
- Raises:
ValueError – If the two mappings do not cover the same set of channel names.
- classmethod from_fields(fields)[source]
Build a multi-camera rayfield from a mapping of named rayfields.
- Parameters:
fields (dict[str, ZernikeRayField]) – Rayfield per channel name; iteration order fixes the channel order.
- Return type:
- ray(name, u, v)[source]
Compute the 3D ray for a pixel in a named channel.
- Parameters:
name (str) – Channel name.
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
origin, direction – Ray origin (mm) and unit direction per pixel, in the channel frame.
- Return type:
ndarray, shape (N, 3)
- class stereocomplex.rayfields.ZernikeCandidate(K, config, coefficients, name='zernike_compact', is_stereo_shared=False, fit_directions=True)[source]
Bases:
objectCompact Zernike origin-field candidate for ray-space model selection.
This wraps a
ZernikeOriginFieldinto thePhysicalRayFieldModelprotocol so it can compete alongside the physical candidates (pinhole, Brown-Conrady, CMO, polynomial surrogate) inselect_physical_model_from_rayfield().The candidate usually uses a lower max-order than the measured Zernike rayfield. The raw coefficient count is
n_modes * 6when directions are fitted andn_modes * 3for origin-only fitting. The number therefore depends on the exact Zernike mode list and on whether direction coefficients are part of the candidate.By default both origin and direction Zernike fields are fitted (
fit_directions=True, usingZernikeRayField). Setfit_directions=Falsefor origin-only fitting withZernikeOriginField(3 scalar coefficients per mode instead of 6).Note
The transverse gauge \(O(u,v)\cdot d(u,v)=0\) is enforced at ray-evaluation time. Depending on the gauge and on whether pose parameters are included in a surrounding fit, the effective comparison count may differ from the raw coefficient count. The
n_parametersproperty intentionally reports the raw coefficient count (6 or 3 per mode) for BIC consistency across candidates.- Parameters:
K (ndarray)
config (ZernikeOriginFieldConfig)
coefficients (ZernikeRayFieldCoefficients)
name (str)
is_stereo_shared (bool)
fit_directions (bool)
- classmethod from_parameter_vector(x, **kwargs)[source]
Rebuild a candidate from a flat parameter vector.
Inverse of
parameter_vector(); see it for the layout.- Parameters:
x (ndarray) – Flat coefficient vector.
**kwargs – Must include
config(ZernikeOriginFieldConfig) andK(3x3 intrinsics); may includefit_directions(default True).
- Return type:
- Raises:
ValueError – If the length of
xdoes not match the mode count and thefit_directionssetting.
- property n_parameters: int
n_modes * 6with directions,* 3without.This is the raw coefficient count. The transverse gauge removes one redundant degree of freedom per mode, so the effective count is slightly lower — see the class docstring.
- Type:
Raw free-parameter count
- parameter_dict()[source]
Return all coefficients as a flat
{name: value}dictionary.Keys encode the mode index and its
(n, m, kind)descriptor, suffixed by the component:_Ox/_Oy/_Ozfor the origin field (mm) and, when directions are fitted,_dx/_dy/_dzfor the direction perturbation (dimensionless).
- parameter_vector()[source]
Pack the Zernike coefficients into a flat optimisation vector.
Layout: the
(n_modes, 3)origin coefficients flattened, followed — whenfit_directionsis set — by the(n_modes, 3)direction coefficients.- Return type:
ndarray, shape (n_modes * 6,) or (n_modes * 3,)
- ray(u, v)[source]
Compute the 3D ray
(origin, direction)for the given pixels.Builds the underlying
ZernikeRayField(orZernikeOriginFieldwhenfit_directionsis False) from the candidate coefficients and evaluates it.- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
origin, direction – Ray origin (mm) and unit direction per pixel.
- Return type:
ndarray, shape (N, 3)
- class stereocomplex.rayfields.ZernikeOriginField(K, config, coefficients=None)[source]
Bases:
objectGeneric non-central ray model with pinhole directions and a Zernike origin field.
The physical oracle may choose any point on a ray. This model uses the canonical transverse gauge O(u,v) dot d(u,v) = 0 by default.
- Parameters:
K (np.ndarray)
config (ZernikeOriginFieldConfig)
coefficients (ZernikeOriginFieldCoefficients | None)
- basis(u, v)[source]
Evaluate the Zernike design matrix at the given pixels.
Pixel coordinates are mapped to the unit disk (via the image diagonal), then every Zernike mode is evaluated to form one column of the matrix.
- Parameters:
u (ndarray) – Pixel coordinates (broadcast against each other).
v (ndarray) – Pixel coordinates (broadcast against each other).
- Returns:
Design matrix
A;A @ coeffsgives the field sampled at theNflattened pixels.- Return type:
ndarray, shape (N, n_modes)
- Raises:
ValueError – If the configured image is not larger than one pixel per axis.
- property coeffs: ndarray
Origin-field Zernike coefficients, shape
(n_modes, 3), in millimetres.
- direction(u, v)[source]
Return the unit pinhole ray directions at the given pixels.
In this model the origin field carries the non-central behaviour; directions are the plain pinhole rays from the intrinsic matrix
K.- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
Unit ray directions.
- Return type:
ndarray, shape (N, 3)
- origin(u, v)[source]
Return the origin field
O(u, v), with the transverse gauge applied.When
config.enforce_transverse_gaugeis set, the raw Zernike origin is projected perpendicular to the ray direction (O . d = 0), removing the redundant longitudinal displacement along each ray.- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
Ray origin per pixel, in millimetres.
- Return type:
ndarray, shape (N, 3)
- raw_origin(u, v)[source]
Return the Zernike origin field before the transverse gauge is applied.
- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
Origin field
basis(u, v) @ coeffs, in millimetres.- Return type:
ndarray, shape (N, 3)
- ray(u, v)[source]
Return the rays
(O(u, v), d(u, v))for the given pixels.- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
origin (ndarray, shape (N, 3)) – Ray origin per pixel (mm), gauge-projected when configured.
direction (ndarray, shape (N, 3)) – Unit pinhole ray direction per pixel.
- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.rayfields.ZernikeOriginFieldCoefficients(coeffs)[source]
Bases:
objectZernike coefficients of an origin field
O(u, v).- Parameters:
coeffs (ndarray)
- coeffs
One 3-vector per Zernike mode, in millimetres; the origin field is
basis(u, v) @ coeffs.- Type:
ndarray, shape (n_modes, 3)
- class stereocomplex.rayfields.ZernikeOriginFieldConfig(image_size, max_order=4, normalization='diagonal_disk', enforce_transverse_gauge=True)[source]
Bases:
objectConfiguration of a Zernike origin / ray field: domain, order and gauge.
- Parameters:
- image_size
Image
(width, height)in pixels; defines the disk over which the Zernike polynomials are evaluated.- Type:
tuple of 2 int
- normalization
Zernike normalisation scheme. Only
"diagonal_disk"is supported: pixel coordinates are mapped to the unit disk via the image diagonal.- Type:
- enforce_transverse_gauge
If True, the origin field is projected transverse to the ray direction (
O . d = 0) at evaluation time, removing the redundant longitudinal degree of freedom along each ray.- Type:
- modes()[source]
Return the Zernike mode descriptors selected by
max_order.- Returns:
One descriptor (radial order n, azimuthal order m, parity) per polynomial, in canonical order — this is the column order of the design matrix returned by
ZernikeOriginField.basis().- Return type:
tuple of ZernikeMode
- class stereocomplex.rayfields.ZernikeRayField(K, config, coefficients=None)[source]
Bases:
ZernikeOriginFieldGeneric ray model with both origin and direction Zernike fields.
Directions are initialized from the pinhole model and corrected by a smooth Zernike perturbation:
d(u,v) = normalize(d0(u,v) + delta_d_perp(u,v)).
The perturbation is projected transverse to the pinhole direction. This keeps the parameterization well conditioned around the central initialization and avoids wasting coefficients on direction-scale changes.
- Parameters:
K (np.ndarray)
config (ZernikeOriginFieldConfig)
coefficients (ZernikeRayFieldCoefficients | None)
- direction(u, v)[source]
Return the unit fitted ray directions.
The pinhole direction
d0plus the transverse Zernike perturbation, then renormalised:d = normalize(d0 + direction_delta(u, v)).- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
Unit ray directions.
- Return type:
ndarray, shape (N, 3)
- property direction_coeffs: ndarray
Direction-perturbation Zernike coefficients, shape
(n_modes, 3), dimensionless.
- direction_delta(u, v)[source]
Return the transverse direction perturbation, before renormalisation.
The raw Zernike direction field is projected perpendicular to the pinhole direction
d0, so the perturbation cannot change the ray scale — only its tilt.- Parameters:
u (ndarray) – Pixel coordinates.
v (ndarray) – Pixel coordinates.
- Returns:
Additive direction perturbation, transverse to
d0.- Return type:
ndarray, shape (N, 3)
- property origin_coeffs: ndarray
Origin-field Zernike coefficients
O(u, v), shape(n_modes, 3), in mm.
- class stereocomplex.rayfields.ZernikeRayFieldChannel(name, field)[source]
Bases:
objectOne named camera channel of a multi-camera Zernike rayfield.
- Parameters:
name (str)
field (ZernikeRayField)
- field
The channel’s fitted rayfield.
- Type:
- class stereocomplex.rayfields.ZernikeRayFieldCoefficients(origin_coeffs, direction_coeffs)[source]
Bases:
objectZernike coefficients for a generic central-reference rayfield.
origin_coeffs are in millimetres. direction_coeffs are dimensionless perturbations added to the pinhole direction before renormalization.
- Parameters:
origin_coeffs (ndarray)
direction_coeffs (ndarray)
Synthetic datasets — stereocomplex.synthetic
Synthetic dataset generation: the parallel-plate non-central oracle and rendered ChArUco scenes.
Synthetic dataset generators and image renderers.
- class stereocomplex.synthetic.ParallelPlateImageRenderParams(pixels_per_square=90, texture_interp='linear', blur_fwhm_px=0.6, blur_edge_factor=1.4, blur_edge_start=0.55, blur_edge_power=2.0, noise_std=0.002, vignette_strength=0.24, illumination_gradient_x=0.08, illumination_gradient_y=0.05, background_level=0.18, image_format='png', seed=1234)[source]
Bases:
objectPhotometric parameters for rendered non-central ChArUco images.
- Parameters:
pixels_per_square (int)
texture_interp (str)
blur_fwhm_px (float)
blur_edge_factor (float)
blur_edge_start (float)
blur_edge_power (float)
noise_std (float)
vignette_strength (float)
illumination_gradient_x (float)
illumination_gradient_y (float)
background_level (float)
image_format (str)
seed (int)
- class stereocomplex.synthetic.ParallelPlateSyntheticParams(eta=1.5, thickness=8.0, alpha_deg=12.0, beta_deg=5.0, d1=80.0)[source]
Bases:
objectPhysical parameters used only by the inclined parallel-plate oracle.
- class stereocomplex.synthetic.RenderedParallelPlateImageDataset(dataset, board, left_images, right_images, render_params)[source]
Bases:
objectRendered image counterpart of a synthetic parallel-plate observation set.
- Parameters:
dataset (SyntheticStereoDataset)
board (CharucoBoardSpec)
render_params (ParallelPlateImageRenderParams)
- class stereocomplex.synthetic.SyntheticStereoDataset(object_points, board_poses, left_pixels, right_pixels, K_left, K_right, T_left_world, T_right_world, image_size, oracle_left_params=None, oracle_right_params=None, per_frame_object_points=None)[source]
Bases:
objectSynthetic stereo observations generated by an oracle.
Conventions: - units are millimetres except pixels and K entries; - board_poses are 4x4 transforms from board coordinates to world coordinates; - T_left_world and T_right_world are 4x4 transforms from world to camera coordinates.
- Parameters:
object_points (ndarray)
board_poses (list[ndarray])
left_pixels (list[ndarray])
right_pixels (list[ndarray])
K_left (ndarray)
K_right (ndarray)
T_left_world (ndarray)
T_right_world (ndarray)
oracle_left_params (ParallelPlateSyntheticParams | None)
oracle_right_params (ParallelPlateSyntheticParams | None)
per_frame_object_points (list[ndarray] | None)
- property T_right_left: ndarray
4x4 transform mapping left-camera coordinates to right-camera coordinates.
- property oracle_left_ray_function
Exact ray function for the left channel (no noise).
- property oracle_right_ray_function
Exact ray function for the right channel (no noise).
- stereocomplex.synthetic.charuco_inner_corners_object_points(board)[source]
Return ChArUco inner-corner ids and board-frame 3D points.
The convention matches the CPU dataset generator: the board is centered at (0,0) and lies in the z=0 plane.
- Parameters:
board (CharucoBoardSpec)
- Return type:
tuple[ndarray, ndarray]
- stereocomplex.synthetic.detected_observations_from_rendered_parallel_plate(rendered, min_common_corners=12, method2d='raw')[source]
Detect ChArUco corners in rendered images and return BA-ready observations.
Each frame contributes its own detected corner subset. Frames with different board poses (including poses where part of the board is outside the image) naturally see different corners.
per_frame_object_pointscarries the per-frame 3D point arrays so the BA handles variable-size observation sets.- Parameters:
rendered (RenderedParallelPlateImageDataset)
min_common_corners (int)
method2d (Literal['raw', 'rayfield_tps_robust'])
- Return type:
- stereocomplex.synthetic.generate_parallel_plate_stereo_dataset(object_points, board_poses, K_left, K_right, T_left_world, T_right_world, plate_left, plate_right, image_size, noise_std_px=0.0, keep_oracle_rayfields=True)[source]
Generate synthetic stereo pixel observations from inclined-plate oracle cameras.
For each board pose, projects the known object points through the left and right parallel-plate camera models and optionally adds Gaussian pixel noise.
- Parameters:
object_points (ndarray, shape (N, 3)) – Board-plane object points in mm (Z=0).
board_poses (sequence of ndarray) – Board-to-world transforms, each shape (4, 4).
K_left (ndarray, shape (3, 3)) – Camera matrices for the two channels.
K_right (ndarray, shape (3, 3)) – Camera matrices for the two channels.
T_left_world (ndarray, shape (4, 4)) – World-to-camera transforms.
T_right_world (ndarray, shape (4, 4)) – World-to-camera transforms.
plate_left (ParallelPlateSyntheticParams) – Plate geometry for each channel.
plate_right (ParallelPlateSyntheticParams) – Plate geometry for each channel.
image_size ((int, int)) – Sensor dimensions in pixels (width, height).
noise_std_px (float) – Standard deviation of additive Gaussian pixel noise (default 0).
keep_oracle_rayfields (bool) – If True, attach exact ray functions to the returned dataset for ground-truth evaluation.
- Returns:
Dataclass dataset object with
left_pixels,right_pixels,object_points,board_poses, and optional oracle rayfields.- Return type:
- stereocomplex.synthetic.normal_from_tilts(alpha_deg, beta_deg)[source]
Return the unit normal q of the tilted parallel plate.
- stereocomplex.synthetic.parallel_plate_ray_from_pixel(u, v, K, params)[source]
Return the physical oracle ray (O_true, d_true) for a pixel.
The origin is the plate exit point I2. It is not gauge-projected here: the generator keeps the physical ray, and evaluation code compares rays geometrically rather than by raw origin equality.
- Parameters:
u (float | ndarray)
v (float | ndarray)
K (ndarray)
params (ParallelPlateSyntheticParams)
- Return type:
tuple[ndarray, ndarray]
- stereocomplex.synthetic.pinhole_ray_from_pixel(u, v, K)[source]
Compute normalised pinhole ray directions from pixel coordinates.
Uses the camera matrix K to back-project pixels to unit vectors in camera space. The origin is implicitly at (0, 0, 0) — this function returns directions only.
- stereocomplex.synthetic.project_point_with_parallel_plate(P_cam, K, params, image_size=None)[source]
Find the pixel whose generated plate-distorted ray passes closest to a 3-D point.
Uses iterative least-squares optimisation. The point must be in front of the camera (Z > 0).
- Parameters:
P_cam (ndarray, shape (3,)) – 3-D point in camera coordinates, in millimetres.
K (ndarray, shape (3, 3)) – Camera matrix.
params (ParallelPlateSyntheticParams) – Plate geometry parameters.
image_size ((int, int), optional) – Sensor dimensions, used to validate the returned pixel.
- Returns:
(u, v) – Pixel coordinates of the closest ray.
- Return type:
- stereocomplex.synthetic.render_parallel_plate_charuco_images(dataset, board, out_dir, params=None)[source]
Render stereo ChArUco images from the non-central parallel-plate oracle.
Rendering is done by ray tracing each camera pixel through the oracle rayfield, intersecting the calibration board plane, then sampling the ChArUco texture. Vignetting, spatially varying blur and sensor noise are applied after geometric rendering.
- Parameters:
dataset (SyntheticStereoDataset)
board (CharucoBoardSpec)
params (ParallelPlateImageRenderParams | None)
- Return type:
Calibration, refinement and I/O — stereocomplex.api
Calibration entry points, ChArUco detection / refinement, reconstruction and model I/O. Symbols re-exported from the namespaces above are documented in their own sections and omitted here to avoid duplication.
- class stereocomplex.api.BenchmarkReport(fit_result, reconstruction_comparison, oracle_floor, left_rayfield_comparison, right_rayfield_comparison)[source]
Bases:
objectSynthetic parallel-plate origin-field benchmark outputs.
- Parameters:
fit_result (StereoZernikeOriginFieldFitResult)
reconstruction_comparison (ReconstructionComparisonReport)
oracle_floor (OracleReconstructionFloorReport)
left_rayfield_comparison (RayfieldComparisonReport)
right_rayfield_comparison (RayfieldComparisonReport)
- class stereocomplex.api.CalibrationAssessment(status, messages=<factory>, recommendations=<factory>)[source]
Bases:
objectStructured quality assessment for a stereo calibration result.
- class stereocomplex.api.CharucoBoardSpec(squares_x: 'int', squares_y: 'int', square_size_mm: 'float', marker_size_mm: 'float', aruco_dictionary: 'str' = 'DICT_4X4_1000', adaptive_thresh_win_size_max: 'int | None' = None, corner_refinement_win_size: 'int' = 5, corner_refinement_max_iterations: 'int' = 50, corner_refinement_min_accuracy: 'float' = 0.001, check_markers: 'bool | None' = None, min_markers: 'int | None' = None, try_refine_markers: 'bool | None' = None, legacy_pattern: 'bool' = False)[source]
Bases:
object- Parameters:
squares_x (int)
squares_y (int)
square_size_mm (float)
marker_size_mm (float)
aruco_dictionary (str)
adaptive_thresh_win_size_max (int | None)
corner_refinement_win_size (int)
corner_refinement_max_iterations (int)
corner_refinement_min_accuracy (float)
check_markers (bool | None)
min_markers (int | None)
try_refine_markers (bool | None)
legacy_pattern (bool)
- classmethod from_dict(payload)[source]
Build a CharucoBoardSpec from a configuration dictionary.
- Parameters:
payload (dict) – Dictionary with board geometry fields.
- Return type:
- class stereocomplex.api.NCameraCalibrationResult(channel_names, stereo_result=None)[source]
Bases:
objectPublic calibration result for named camera sets.
- Parameters:
stereo_result (StereoCentralRayFieldFitResult | None)
- class stereocomplex.api.OracleReconstructionFloorReport(oracle_clean_pixels, oracle_observed_pixels)[source]
Bases:
objectNoise-free and observed-pixel oracle reconstruction floors.
- Parameters:
oracle_clean_pixels (ReconstructionErrorReport)
oracle_observed_pixels (ReconstructionErrorReport)
- class stereocomplex.api.RayfieldComparisonReport(plane_intersection_rms, plane_intersection_median, plane_intersection_p95, direction_angle_rms_deg, n_samples)[source]
Bases:
objectSummary of rayfield comparison between two models.
- Parameters:
- class stereocomplex.api.ReconstructionComparisonReport(central, with_origin_field, improvement_rms_factor, improvement_median_factor, improvement_p95_factor)[source]
Bases:
objectCentral-vs-origin-field reconstruction comparison summary.
- Parameters:
central (ReconstructionErrorReport)
with_origin_field (ReconstructionErrorReport)
improvement_rms_factor (float)
improvement_median_factor (float)
improvement_p95_factor (float)
- class stereocomplex.api.ReconstructionErrorReport(rms_3d, median_3d, p95_3d, max_3d, rms_x, rms_y, rms_z, ray_gap_rms, ray_gap_median, ray_gap_p95, n_points)[source]
Bases:
objectAggregate 3-D reconstruction errors in millimetres.
- class stereocomplex.api.ReconstructionResult(points_3d, ray_gap, valid_mask)[source]
Bases:
objectTriangulated 3-D points and ray-gap validity diagnostics.
- Parameters:
points_3d (ndarray)
ray_gap (ndarray)
valid_mask (ndarray)
- class stereocomplex.api.RenderedImageBenchmarkReport(fit_result, reconstruction_comparison, oracle_detected, rendered, detected_dataset, method2d, n_common_corners, n_frames, n_points_total)[source]
Bases:
objectRendered-image parallel-plate benchmark outputs and metadata.
- Parameters:
fit_result (StereoZernikeOriginFieldFitResult)
reconstruction_comparison (ReconstructionComparisonReport)
oracle_detected (ReconstructionErrorReport)
rendered (RenderedParallelPlateImageDataset)
detected_dataset (SyntheticStereoDataset)
method2d (Literal['raw', 'rayfield_tps_robust'])
n_common_corners (int)
n_frames (int)
n_points_total (int)
- class stereocomplex.api.StereoCentralRayFieldFitReport(image_width_px, image_height_px, n_input_pairs, n_detected_pairs, n_observation_frames, n_initialized_frames, used_frame_ids, method2d, min_common_corners, nmax, train_skew_rms_mm, train_skew_p95_mm, train_point_to_ray_rms_mm, train_point_to_ray_p95_mm, n_points_total, mean_common_corners_per_frame, diagnostics, exported_model_json=None)[source]
Bases:
objectQuality metrics for a fitted stereo central rayfield calibration.
- Parameters:
image_width_px (int)
image_height_px (int)
n_input_pairs (int)
n_detected_pairs (int)
n_observation_frames (int)
n_initialized_frames (int)
method2d (Literal['raw', 'rayfield_tps_robust'])
min_common_corners (int)
nmax (int)
train_skew_rms_mm (float)
train_skew_p95_mm (float)
train_point_to_ray_rms_mm (float)
train_point_to_ray_p95_mm (float)
n_points_total (int)
mean_common_corners_per_frame (float)
exported_model_json (str | None)
- class stereocomplex.api.StereoCentralRayFieldFitResult(model, report)[source]
Bases:
objectFitted stereo central rayfield model plus calibration report.
- Parameters:
model (StereoCentralRayFieldModel)
report (StereoCentralRayFieldFitReport)
- class stereocomplex.api.StereoCentralRayFieldModel(image_width_px, image_height_px, left, right, R_RL, t_RL)[source]
Bases:
objectStereo reconstruction model with a central ray-field per camera.
The left camera frame is the reference frame. The right camera pose is expressed as
X_R = R_RL @ X_L + t_RL, so the right camera centre in the left frame isC_R = -R_RL.T @ t_RL.- Parameters:
- image_width_px, image_height_px
Image size in pixels.
- Type:
- left, right
Per-camera central ray-field models.
- Type:
CentralRayFieldZernike
- R_RL
Rotation of the right camera relative to the left.
- Type:
ndarray, shape (3, 3)
- t_RL
Translation of the right camera relative to the left, in millimetres.
- Type:
ndarray, shape (3,)
- property C_L_mm: ndarray
Left camera centre in world coordinates (origin, in mm).
- property C_R_in_L_mm: ndarray
Right camera centre expressed in the left camera frame (in mm).
- classmethod from_coeffs(*, image_width_px, image_height_px, nmax, u0_px, v0_px, radius_px, coeffs_left_x, coeffs_left_y, coeffs_right_x, coeffs_right_y, R_RL, t_RL, C_L_mm=None)[source]
Build a StereoCentralRayFieldModel from raw coefficient arrays.
- Parameters:
image_width_px (int) – Sensor dimensions in pixels.
image_height_px (int) – Sensor dimensions in pixels.
nmax (int) – Maximum Zernike radial order.
u0_px (float) – Unit-disk centre in pixels.
v0_px (float) – Unit-disk centre in pixels.
radius_px (float) – Unit-disk radius in pixels.
coeffs_left_x (ndarray) – Zernike coefficients for the left camera.
coeffs_left_y (ndarray) – Zernike coefficients for the left camera.
coeffs_right_x (ndarray) – Zernike coefficients for the right camera.
coeffs_right_y (ndarray) – Zernike coefficients for the right camera.
R_RL (ndarray, shape (3, 3)) – Rotation from left to right camera frame.
t_RL (ndarray, shape (3,)) – Translation from left to right camera frame.
C_L_mm (ndarray, optional) – Left camera centre in millimetres (defaults to origin).
- Returns:
The reconstructed central rayfield model.
- Return type:
- ray_direction_maps()[source]
Precompute per-pixel ray direction maps for left and right cameras.
Returns
(dL_map, dR_map)with shape(H, W, 3).dL_mapcontains directions expressed in the left camera frame;dR_mapcontains directions expressed in the right camera frame. Transform right-channel directions withR_RL.Tbefore triangulating in the left frame.- Return type:
tuple[ndarray, ndarray]
- class stereocomplex.api.StereoImagePair(left_path: 'Path', right_path: 'Path', frame_id: 'int | None' = None)[source]
Bases:
object
- class stereocomplex.api.StereoOpenCVCalibrationReport(image_width_px, image_height_px, n_input_pairs, n_detected_pairs, n_mono_frames_left, n_mono_frames_right, n_stereo_frames, used_frame_ids, method2d, min_common_corners, mono_left_rms_px, mono_right_rms_px, stereo_rms_px, baseline_mm)[source]
Bases:
objectFrame counts and RMS metrics for OpenCV stereo calibration.
- Parameters:
image_width_px (int)
image_height_px (int)
n_input_pairs (int)
n_detected_pairs (int)
n_mono_frames_left (int)
n_mono_frames_right (int)
n_stereo_frames (int)
method2d (Literal['raw', 'rayfield_tps_robust'])
min_common_corners (int)
mono_left_rms_px (float)
mono_right_rms_px (float)
stereo_rms_px (float)
baseline_mm (float)
- class stereocomplex.api.StereoOpenCVCalibrationResult(K_left, dist_left, K_right, dist_right, R_right_from_left, t_right_from_left_mm, essential_matrix, fundamental_matrix, report)[source]
Bases:
objectOpenCV stereo intrinsics, distortion, rig transform and report.
- Parameters:
K_left (ndarray)
dist_left (ndarray)
K_right (ndarray)
dist_right (ndarray)
R_right_from_left (ndarray)
t_right_from_left_mm (ndarray)
essential_matrix (ndarray)
fundamental_matrix (ndarray)
report (StereoOpenCVCalibrationReport)
- class stereocomplex.api.StereoZernikeOriginFieldFitResult(left_field, right_field, stereo_transform, board_poses, residual_rms, residual_median, residual_p95, n_observations, success, message)[source]
Bases:
objectFitted stereo Zernike origin fields and residual diagnostics.
- Parameters:
left_field (ZernikeOriginField)
right_field (ZernikeOriginField)
stereo_transform (ndarray)
board_poses (list[ndarray])
residual_rms (float)
residual_median (float)
residual_p95 (float)
n_observations (int)
success (bool)
message (str)
- stereocomplex.api.assess_calibration(result)[source]
Assess whether a stereo calibration result is usable.
Works with
StereoOpenCVCalibrationResult,StereoCentralRayFieldFitResult, andStereoZernikeOriginFieldFitResult.- Parameters:
result (Any) – A calibration result object with a
.reportattribute.- Return type:
- stereocomplex.api.build_charuco_board(board)[source]
Build an OpenCV
aruco.CharucoBoardfrom a stable Python dataclass.- Parameters:
board (CharucoBoardSpec)
- Return type:
- stereocomplex.api.calibrate(*, cameras, board, max_pairs=0, method2d='rayfield_tps_robust', min_common_corners=10, nmax=10, lam_coeff=0.001, tps_lam=10.0, huber_c=3.0, iters=3, max_nfev=800, export_model_dir=None)[source]
Calibrate a named camera set.
Phase 1 exposes an N-camera API surface while preserving the existing stereo implementation for the supported left/right case.
- Parameters:
- Return type:
- stereocomplex.api.compare_3d_reconstruction_with_without_origin_field(dataset, central_model_result, origin_field_result)[source]
Compare central stereo against non-central reconstruction with origin fields.
Triangulates the same point correspondences using a central model (all rays from a single camera centre) and a non-central model (per-pixel origins). Reports RMS, median, and P95 reconstruction error in 3-D.
- Parameters:
dataset (SyntheticStereoDataset) – Stereo observations with ground-truth 3-D points.
central_model_result (StereoCentralRayFieldFitResult) – Result from central rayfield calibration.
origin_field_result (StereoZernikeOriginFieldFitResult) – Result from non-central Zernike origin field calibration.
- Returns:
Dataclass result object with
centralandwith_origin_fielderror statistics.- Return type:
- stereocomplex.api.compare_opencv_stereo_calibration(left_dir, right_dir, board, *, max_pairs=None, method2d='rayfield_tps_robust', **kwargs)[source]
Run OpenCV stereo calibration with raw AND refined corners.
This is the recommended first step for an OpenCV user: it runs
fit_opencv_stereo_from_image_dirstwice (once withmethod2d="raw", once with method2d) and returns a comparison dictionary.- Parameters:
left_dir (str or Path) – Directory containing left-camera calibration images.
right_dir (str or Path) – Directory containing right-camera calibration images.
board (CharucoBoardSpec) – ChArUco board geometry used for detection and calibration.
max_pairs (int or None) – Maximum number of stereo pairs to process.
Nonemeans the default offit_opencv_stereo_from_image_dirs.method2d (str) – Refined 2-D corner method used for the second calibration pass.
**kwargs – Additional keyword arguments forwarded to
fit_opencv_stereo_from_image_dirs.
- Returns:
Dictionary containing raw/refined dataclass result objects, their serialised dictionaries, and the RMS improvement in pixels.
- Return type:
- stereocomplex.api.compare_rayfields_on_planes(fitted_field, oracle_ray_function, image_size, z_planes, grid_shape=(25, 19))[source]
Compare two ray fields by intersecting each ray with two reference z planes.
This avoids comparing raw origins that may be expressed in different gauges.
- stereocomplex.api.detect_charuco_corners(*, image, board)[source]
Detect ArUco markers and ChArUco corners in one image.
- Parameters:
board (CharucoBoardSpec)
- Return type:
CharucoDetections | None
- stereocomplex.api.fit_opencv_stereo_from_dataset(*, dataset_root, split='train', scene='scene_0000', max_frames=0, method2d='raw', min_common_corners=10, tps_lam=10.0, huber_c=3.0, iters=3)[source]
Fit an OpenCV stereo model to a pre-organized dataset.
- Parameters:
dataset_root (str or Path) – Root directory of the dataset.
split (str) – Dataset split name (‘train’, ‘val’, ‘test’).
scene (str) – Scene identifier.
max_frames (int) – Maximum number of frames to process (0 = all).
method2d (str) – 2-D corner detection/refinement method.
min_common_corners (int) – Minimum number of corners common to both views.
tps_lam (float) – TPS smoothing parameter.
huber_c (float) – Huber loss threshold in pixels.
iters (int) – Number of IRLS refinement iterations.
- Returns:
Dataclass result object with OpenCV calibration parameters per channel.
- Return type:
- stereocomplex.api.fit_opencv_stereo_from_image_dirs(*, left_dir, right_dir, board, max_pairs=0, method2d='raw', min_common_corners=10, tps_lam=10.0, huber_c=3.0, iters=3)[source]
Fit an OpenCV stereo model to images in left/right directories.
- Parameters:
left_dir (str or Path) – Directory containing left-camera images.
right_dir (str or Path) – Directory containing right-camera images.
board (CharucoBoardSpec) – ChArUco board geometry.
max_pairs (int) – Maximum number of stereo pairs to process (0 = all).
method2d (str) – 2-D corner detection/refinement method.
min_common_corners (int) – Minimum number of corners common to both views.
tps_lam (float) – TPS smoothing parameter.
huber_c (float) – Huber loss threshold in pixels.
iters (int) – Number of IRLS refinement iterations.
- Returns:
Dataclass result object with OpenCV calibration parameters per channel.
- Return type:
- stereocomplex.api.fit_opencv_stereo_from_image_pairs(*, image_pairs, board, method2d='raw', min_common_corners=10, tps_lam=10.0, huber_c=3.0, iters=3)[source]
Calibrate a standard OpenCV stereo pinhole model from image pairs.
This is the onboarding-friendly companion to the 3D ray-field API: it uses the same public ChArUco detection/refinement path, then runs plain OpenCV mono and stereo calibration. Use method2d=”raw” for baseline OpenCV and method2d=”rayfield_tps_robust” for OpenCV fed with refined corners.
- Parameters:
- Return type:
- stereocomplex.api.fit_stereo_central_rayfield_from_dataset(*, dataset_root, split='train', scene='scene_0000', max_frames=0, method2d='rayfield_tps_robust', min_common_corners=10, nmax=10, lam_coeff=0.001, tps_lam=10.0, huber_c=3.0, iters=3, max_nfev=800, export_model_dir=None)[source]
Fit a central rayfield stereo model to a pre-organized dataset.
- Parameters:
dataset_root (str or Path) – Root directory of the dataset.
split (str) – Dataset split name.
scene (str) – Scene identifier.
max_frames (int) – Maximum number of frames (0 = all).
method2d (str) – 2-D corner refinement method.
min_common_corners (int) – Minimum common corners per pair.
nmax (int) – Maximum Zernike radial order.
lam_coeff (float) – Regularisation weight for Zernike coefficients.
tps_lam (float) – TPS smoothing parameter.
huber_c (float) – Huber loss threshold in pixels.
iters (int) – Number of IRLS iterations.
max_nfev (int) – Maximum LS function evaluations.
export_model_dir (str or Path or None) – If set, export the fitted model to this directory.
- Returns:
Dataclass result object with the fitted central rayfield model and diagnostics.
- Return type:
- stereocomplex.api.fit_stereo_central_rayfield_from_image_dirs(*, left_dir, right_dir, board, max_pairs=0, method2d='rayfield_tps_robust', min_common_corners=10, nmax=10, lam_coeff=0.001, tps_lam=10.0, huber_c=3.0, iters=3, max_nfev=800, export_model_dir=None)[source]
Fit a central rayfield stereo model to images in left/right directories.
- Parameters:
left_dir (str or Path) – Directory containing left-camera images.
right_dir (str or Path) – Directory containing right-camera images.
board (CharucoBoardSpec) – ChArUco board geometry.
max_pairs (int) – Maximum number of stereo pairs (0 = all).
method2d (str) – 2-D corner refinement method.
min_common_corners (int) – Minimum common corners per pair.
nmax (int) – Maximum Zernike radial order.
lam_coeff (float) – Regularisation weight for Zernike coefficients.
tps_lam (float) – TPS smoothing parameter.
huber_c (float) – Huber loss threshold in pixels.
iters (int) – Number of IRLS iterations.
max_nfev (int) – Maximum LS function evaluations.
export_model_dir (str or Path or None) – If set, export the fitted model to this directory.
- Returns:
Dataclass result object with the fitted central rayfield model and diagnostics.
- Return type:
- stereocomplex.api.fit_stereo_central_rayfield_from_image_pairs(*, image_pairs, board, method2d='rayfield_tps_robust', min_common_corners=10, nmax=10, lam_coeff=0.001, tps_lam=10.0, huber_c=3.0, iters=3, max_nfev=800, export_model_dir=None)[source]
Calibrate a public stereo central ray-field model directly from image pairs.
This is the stable high-level entry point for users who already have left/right image pairs and a known ChArUco board.
- Parameters:
- Return type:
- stereocomplex.api.fit_stereo_zernike_origin_field(observations, K_left, K_right, T_right_left_initial, board_poses_initial, config_left, config_right, optimize_board_poses=False, optimize_stereo_extrinsics=False, optimize_directions=False, robust_loss='huber', regularization=1e-06, direction_regularization=None, pose_regularization=0.0, rig_regularization=0.0, max_nfev=200)[source]
Fit stereo non-central Zernike origin fields from point-to-ray residuals.
The default mode identifies per-pixel ray origins
O_left(u,v)andO_right(u,v)on top of fixed pinhole directions, fixed board poses and a fixed stereo rig. Optional flags can extend the optimisation to direction perturbations, per-frame board poses and the stereo extrinsics. The fit is purely geometric: it uses only observed pixels, camera intrinsics, initial poses and the board object points, never the physical oracle parameters used to generate synthetic data.- Parameters:
observations (SyntheticStereoDataset) – Stereo calibration observations.
left_pixelsandright_pixelsare per-frame pixel arrays;object_pointsorper_frame_object_pointsprovide matching board coordinates in mm.K_left (ndarray, shape (3, 3)) – Left and right pinhole intrinsics used for the fixed base directions.
K_right (ndarray, shape (3, 3)) – Left and right pinhole intrinsics used for the fixed base directions.
T_right_left_initial (ndarray, shape (4, 4)) – Initial transform from left-camera coordinates to right-camera coordinates.
board_poses_initial (sequence of ndarray, each shape (4, 4)) – Initial board-to-world transforms, one per observed frame.
config_left (ZernikeOriginFieldConfig) – Zernike basis, image size and gauge settings for each channel.
config_right (ZernikeOriginFieldConfig) – Zernike basis, image size and gauge settings for each channel.
optimize_board_poses (bool) – If True, include one SE(3) board pose block per frame in the least- squares vector.
optimize_stereo_extrinsics (bool) – If True, refine the stereo rig transform around
T_right_left_initial.optimize_directions (bool) – If True, fit Zernike direction perturbation coefficients as well as origin coefficients.
robust_loss ({"linear", "huber", "soft_l1", "cauchy", "arctan"}) – Robust loss passed to
scipy.optimize.least_squares.regularization (float) – L2 weight for origin-field coefficients.
direction_regularization (float or None) – L2 weight for direction coefficients.
Nonereusesregularization.pose_regularization (float) – L2 weight anchoring optimised board poses to their initial values.
rig_regularization (float) – L2 weight anchoring optimised stereo extrinsics to the initial rig.
max_nfev (int) – Maximum number of least-squares function evaluations.
- Returns:
Dataclass result object containing the fitted left/right rayfields, optional direction coefficients, refined poses/rig and residual diagnostics.
- Return type:
- stereocomplex.api.fit_stereo_zernike_origin_field_from_image_dirs(*, left_dir, right_dir, board, max_order=4, max_pairs=0, method2d='raw', min_common_corners=10, tps_lam=10.0, huber_c=3.0, iters=3, regularization=1e-06, max_nfev=200)[source]
Calibrate a non-central stereo Zernike origin-field model from image directories.
Detects ChArUco corners, runs OpenCV mono+stereo calibration to obtain K and the stereo rig transform, solves per-frame board poses, then fits a Zernike origin field O(u,v) on top of the pinhole directions.
- Parameters:
left_dir (str | Path) – Directories containing sorted left/right calibration images (same count).
right_dir (str | Path) – Directories containing sorted left/right calibration images (same count).
board (CharucoBoardSpec) – ChArUco board specification.
max_order (int) – Maximum Zernike radial order for the origin field.
max_pairs (int) – Cap on the number of image pairs used (0 = use all).
method2d (Literal['raw', 'rayfield_tps_robust']) – Corner refinement method passed to refine_charuco_corners.
min_common_corners (int) – Minimum corners common to left and right per frame.
tps_lam (float) – Thin-plate-spline smoothing parameter forwarded to
refine_charuco_cornerswhenmethod2d="rayfield_tps_robust".huber_c (float) – Huber threshold in pixels for robust 2-D corner refinement.
iters (int) – Number of IRLS iterations for robust 2-D corner refinement.
regularization (float) – L2 regularization weight on the Zernike origin coefficients.
max_nfev (int) – Maximum function evaluations for the Zernike BA.
- Return type:
Notes
All frames are restricted to the intersection of corners visible in EVERY frame, because SyntheticStereoDataset requires a single shared object_points array. Corners not detected in all frames are dropped. If this intersection is too small, add more frames with full board coverage or reduce min_common_corners.
- stereocomplex.api.intersect_rays_with_z_plane(origin, direction, z_plane)[source]
Intersect rays with a horizontal z-plane.
- Parameters:
origin (np.ndarray) – Ray origins, shape (N, 3).
direction (np.ndarray) – Ray directions (unit vectors), shape (N, 3).
z_plane (float) – Z-coordinate of the target plane.
- Returns:
Intersection points, shape (N, 3).
- Return type:
np.ndarray
- Raises:
ValueError – If any ray is parallel to the z-plane (z-component < 1e-12).
- stereocomplex.api.load_stereo_central_rayfield(model_dir)[source]
Load a fitted StereoCentralRayFieldModel from a directory.
- Parameters:
model_dir (Path) – Directory containing model.json and coefficient .npy files.
- Returns:
The loaded central rayfield model.
- Return type:
- stereocomplex.api.make_default_parallel_plate_charuco_board()[source]
Return the ChArUco board used by the rendered non-central image demo.
- Return type:
- stereocomplex.api.make_default_parallel_plate_charuco_dataset(noise_std_px=0.0)[source]
Default parallel-plate dataset whose object points are ChArUco inner corners.
This is the geometric counterpart of the rendered-image benchmark. The same board poses and optical oracle are used, but observations are exact projected ChArUco inner corners rather than OpenCV detections.
- Parameters:
noise_std_px (float)
- Return type:
- stereocomplex.api.make_default_parallel_plate_dataset(noise_std_px=0.0)[source]
Generate the default synthetic parallel-plate dataset.
- Parameters:
noise_std_px (float)
- Return type:
- stereocomplex.api.make_parallel_plate_wide_coverage_dataset(noise_std_px=0.0)[source]
Dataset with a larger board and wider pose coverage for rayfield support plots.
The default dataset is intentionally small and fast because it is used by multiple regression tests. This variant is used for physical rayfield interpretation figures where the observed pixel support should cover much more of the image.
Six central poses keep the full 11x9 board within both cameras. Four axis-aligned paired edge poses cover the top/bottom/right image borders. One additional left-only monocular frame (empty right_pixels sentinel) fills the left-edge gap that paired stereo geometry cannot reach: u_min_paired = baseline * fx / z = 90 * 620 / 650 ≈ 86 px. The total is 11 frames; only the monocular frame contributes no right-camera residuals.
- Parameters:
noise_std_px (float)
- Return type:
- stereocomplex.api.oracle_reconstruction_floor_report(dataset_observed, dataset_clean=None)[source]
Compute the oracle floor for clean and observed/noisy pixels.
dataset_clean should share the same geometry and oracle parameters as dataset_observed, but with noise-free pixels. If omitted, the clean case is evaluated with dataset_observed pixels.
- Parameters:
dataset_observed (SyntheticStereoDataset)
dataset_clean (SyntheticStereoDataset | None)
- Return type:
- stereocomplex.api.reconstruct_points_central_stereo(left_pixels, right_pixels, K_left, K_right, T_right_left)[source]
Reconstruct 3-D points from stereo pixel correspondences using central pinhole rays.
Back-projects each pixel pair through the camera matrices, transforms the right ray into the left camera frame via T_right_left, then triangulates by midpoint of closest approach.
- Parameters:
left_pixels (ndarray, shape (N, 2)) – Left pixel coordinates (u, v) in pixels.
right_pixels (ndarray, shape (N, 2)) – Right pixel coordinates (u, v) in pixels.
K_left (ndarray, shape (3, 3)) – Camera matrices for each channel.
K_right (ndarray, shape (3, 3)) – Camera matrices for each channel.
T_right_left (ndarray, shape (4, 4)) – Rigid transform from left to right camera frame.
- Returns:
Dataclass result object with
points_3d(N, 3),ray_gap(N,), andvalid_mask(N, bool).- Return type:
- stereocomplex.api.reconstruct_points_with_origin_fields(left_pixels, right_pixels, left_field, right_field, T_right_left)[source]
Reconstruct 3-D points using per-pixel origin fields (non-central rays).
Unlike the central model where all rays share one camera centre, each pixel gets its own ray origin O(u,v) and direction d(u,v) from the Zernike origin field. Triangulation uses midpoint of closest approach between the two skew rays.
- Parameters:
left_pixels (ndarray, shape (N, 2)) – Left pixel coordinates (u, v) in pixels.
right_pixels (ndarray, shape (N, 2)) – Right pixel coordinates (u, v) in pixels.
left_field (ZernikeOriginField) – Fitted left-channel non-central rayfield.
right_field (ZernikeOriginField) – Fitted right-channel non-central rayfield.
T_right_left (ndarray, shape (4, 4)) – Rigid transform from left to right camera frame.
- Returns:
Dataclass result object with
points_3d(N, 3),ray_gap(N,), andvalid_mask(N, bool).- Return type:
- stereocomplex.api.reconstruct_points_with_parallel_plate_oracle(left_pixels, right_pixels, dataset)[source]
Reconstruct correspondences with the physical oracle rayfields.
The oracle keeps the physical exit point I2. This function is for evaluation only and must not be used by the generic Zernike fit.
- Parameters:
left_pixels (ndarray)
right_pixels (ndarray)
dataset (SyntheticStereoDataset)
- Return type:
- stereocomplex.api.reconstruction_error_report(result, true_points)[source]
Compute 3D reconstruction error statistics against ground truth.
- Parameters:
result (ReconstructionResult) – Reconstructed points, ray gaps, and validity mask.
true_points (np.ndarray) – Ground truth 3D points, shape
(N, 3).
- Returns:
RMS, median, P95, and max 3D errors plus per-axis RMS and ray-gap stats.
- Return type:
- stereocomplex.api.refine_charuco_corners(*, method, board, detections=None, marker_ids=None, marker_corners=None, charuco_ids=None, charuco_xy=None, tps_lam=10.0, huber_c=3.0, iters=3)[source]
Refine ChArUco corners using geometric priors on the board plane.
The function accepts either a bundled
CharucoDetectionsobject or the four raw detection arrays.method="raw"returns the ChArUco detector coordinates unchanged;method="rayfield_tps_robust"fits a robust 2-D board-plane warp from marker corners to image pixels and evaluates it at the requested ChArUco corner IDs.- Parameters:
method ({"raw", "rayfield_tps_robust"}) – Refinement strategy.
board (CharucoBoardSpec or OpenCV CharucoBoard) – Board geometry.
CharucoBoardSpecis converted withbuild_charuco_board; an OpenCV board must providegetIds,getObjPointsandgetChessboardCorners.detections (CharucoDetections, optional) – Bundled marker and ChArUco detections for one image. If provided, the four raw detection arguments below are ignored.
marker_ids (ndarray, shape (M,), optional) – ArUco marker IDs detected in the image.
marker_corners (list of ndarray, optional) – Marker corner coordinates in pixels, one
(4, 2)array per marker.charuco_ids (ndarray, shape (K,), optional) – ChArUco corner IDs to refine.
charuco_xy (ndarray, shape (K, 2), optional) – Initial ChArUco corner coordinates in pixels.
tps_lam (float) – Thin-plate-spline smoothing parameter for
rayfield_tps_robust.huber_c (float) – Huber threshold in pixels for robust TPS fitting.
iters (int) – Number of robust reweighting iterations.
- Returns:
Refined corner positions in pixels, in the same order as
charuco_ids.- Return type:
ndarray, shape (K, 2)
- stereocomplex.api.run_parallel_plate_origin_field_benchmark(max_order=4, noise_std_px=0.05, optimize_directions=False, optimize_board_poses=False, optimize_stereo_extrinsics=False, pose_regularization=0.0, rig_regularization=0.0)[source]
Run the full origin-field benchmark end-to-end on the default parallel-plate dataset.
Generates data, fits a Zernike origin field, and compares central vs non-central reconstruction accuracy.
- Parameters:
max_order (int) – Maximum Zernike radial order for the origin field fit.
noise_std_px (float) – Pixel noise standard deviation added to the synthetic observations.
optimize_directions (bool) – If True, jointly optimise ray directions in the BA.
optimize_board_poses (bool) – If True, refine board poses during BA.
optimize_stereo_extrinsics (bool) – If True, refine the stereo rig transform during BA.
pose_regularization (float) – Regularisation weight for pose parameters.
rig_regularization (float) – Regularisation weight for the stereo rig transform.
- Returns:
Dataclass result object with reconstruction comparison and diagnostics.
- Return type:
- stereocomplex.api.run_parallel_plate_rendered_image_benchmark(out_dir, max_order=3, render_params=None, method2d='raw')[source]
Render non-central ChArUco images, detect them with OpenCV, then run full BA.
This is the first end-to-end image front-end check for the parallel-plate oracle. The fit does not receive oracle plate parameters; it only receives detected 2D ChArUco corners, the board model, and a central initialization.
- Parameters:
max_order (int)
render_params (ParallelPlateImageRenderParams | None)
method2d (Literal['raw', 'rayfield_tps_robust'])
- Return type:
- stereocomplex.api.save_stereo_central_rayfield(model_dir, model)[source]
Save a stereo central ray-field model into a directory:
model.json + weights.npz
The JSON is small and ML-friendly (pure metadata + paths). The NPZ stores arrays.
- Parameters:
model_dir (Path)
model (StereoCentralRayFieldModel)
- Return type:
- stereocomplex.api.triangulate_two_rays(O_left, d_left, O_right, d_right)[source]
Midpoint triangulation of two 3-D rays, returning the 3-D point of closest approach and the ray gap (minimum distance between the two skew lines).
The triangulated point is the midpoint of the shortest segment connecting the two rays. No gauge constraint is applied to the ray origins — they are used as given. If the rays are parallel or nearly parallel (denominator < 1e-12), the midpoint of the origins is returned and the ray gap is computed as the orthogonal distance from one origin to the other ray.
- Parameters:
O_left (ndarray, shape (3,)) – Left ray origin in world coordinates, in millimetres.
d_left (ndarray, shape (3,)) – Left ray direction (unit vector, or will be normalised).
O_right (ndarray, shape (3,)) – Right ray origin in world coordinates, in millimetres.
d_right (ndarray, shape (3,)) – Right ray direction (unit vector, or will be normalised).
- Returns:
P (ndarray, shape (3,)) – Midpoint of the closest-approach segment, in millimetres.
gap (float) – Minimum distance between the two rays, in millimetres. Zero when the rays intersect exactly.
- Return type: