Configuration & Types

Type definitions and schema for AquaCal calibration system.

This module defines all dataclasses, type aliases, and custom exceptions used throughout the library. No validation is performed at runtime; shapes are documented in docstrings and type hints.

Coordinate conventions: - World frame: Z-down (into water), origin at reference camera - Camera frame: Z-forward, X-right, Y-down (OpenCV convention) - Interface normal: [0, 0, -1] points up (water toward air)

class aquacal.config.schema.BoardConfig(squares_x, squares_y, square_size, marker_size, dictionary, legacy_pattern=False)[source]

Bases: object

ChArUco board specification.

Parameters:
squares_x

Number of chessboard squares in X direction

Type:

int

squares_y

Number of chessboard squares in Y direction

Type:

int

square_size

Size of each square in meters

Type:

float

marker_size

Size of ArUco markers in meters

Type:

float

dictionary

ArUco dictionary name (e.g., “DICT_4X4_50”)

Type:

str

legacy_pattern

If True, board uses legacy ChArUco pattern with marker in top-left cell. Default False (new pattern with solid square in top-left cell)

Type:

bool

class aquacal.config.schema.CameraIntrinsics(K, dist_coeffs, image_size, is_fisheye=False)[source]

Bases: object

Intrinsic parameters for a single camera.

Parameters:
K

3x3 intrinsic matrix

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

dist_coeffs

Distortion coefficients. For pinhole: length 5 or 8 [k1, k2, p1, p2, k3, …]. For fisheye: length 4 [k1, k2, k3, k4].

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

image_size

Image dimensions as (width, height) in pixels

Type:

tuple[int, int]

is_fisheye

If True, uses equidistant fisheye projection model

Type:

bool

class aquacal.config.schema.CameraExtrinsics(R, t)[source]

Bases: object

Extrinsic parameters for a single camera.

Defines the transformation from world coordinates to camera coordinates.

Parameters:
R

3x3 rotation matrix, world -> camera

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

t

3x1 translation vector, world -> camera

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

property C: ndarray[tuple[int, ...], dtype[float64]]

Camera center in world coordinates.

Returns:

3-element array representing camera center position in world frame

class aquacal.config.schema.CameraCalibration(name, intrinsics, extrinsics, water_z, is_auxiliary=False)[source]

Bases: object

Complete calibration for a single camera.

Parameters:
name

Camera identifier (e.g., “cam0”, “cam1”)

Type:

str

intrinsics

Intrinsic camera parameters

Type:

aquacal.config.schema.CameraIntrinsics

extrinsics

Extrinsic camera parameters (pose in world frame)

Type:

aquacal.config.schema.CameraExtrinsics

water_z

Z-coordinate of the water surface in world frame (meters). Same for all cameras after optimization.

Type:

float

is_auxiliary

If True, this camera was registered post-hoc against fixed board poses (excluded from joint Stage 3/4 optimization).

Type:

bool

class aquacal.config.schema.InterfaceParams(normal, n_air=1.0, n_water=1.333)[source]

Bases: object

Refractive interface (water surface) parameters.

Note: Per-camera interface distances are stored in each CameraCalibration object, not here. This dataclass holds only the shared interface properties.

Parameters:
normal

Unit vector pointing from water toward air (typically [0, 0, -1])

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

n_air

Refractive index of air (default 1.0)

Type:

float

n_water

Refractive index of water (default 1.333 for fresh water at 20°C)

Type:

float

class aquacal.config.schema.CalibrationResult(cameras, interface, board, diagnostics, metadata)[source]

Bases: object

Complete calibration output.

Parameters:
cameras

Dictionary mapping camera names to their calibrations

Type:

dict[str, aquacal.config.schema.CameraCalibration]

interface

Refractive interface parameters

Type:

aquacal.config.schema.InterfaceParams

board

ChArUco board configuration used

Type:

aquacal.config.schema.BoardConfig

diagnostics

Calibration quality metrics

Type:

aquacal.config.schema.DiagnosticsData

metadata

Metadata for reproducibility

Type:

aquacal.config.schema.CalibrationMetadata

Example

>>> from aquacal import run_calibration, save_calibration
>>> result = run_calibration("config.yaml")
>>> print(f"Water surface at Z = {result.cameras['cam0'].water_z:.3f} m")
>>> save_calibration(result, "output/calibration.yaml")

Note

For coordinate system conventions, see the Coordinate Conventions guide.

class aquacal.config.schema.DiagnosticsData(reprojection_error_rms, reprojection_error_per_camera, validation_3d_error_mean, validation_3d_error_std, per_corner_residuals=None, per_corner_camera_labels=None, per_frame_errors=None)[source]

Bases: object

Calibration quality metrics.

Parameters:
reprojection_error_rms

Overall RMS reprojection error in pixels (primary cameras only)

Type:

float

reprojection_error_per_camera

Per-camera RMS reprojection errors (primary cameras only)

Type:

dict[str, float]

validation_3d_error_mean

Mean 3D reconstruction error in meters (holdout set, primary cameras only)

Type:

float

validation_3d_error_std

Standard deviation of 3D errors in meters (primary cameras only)

Type:

float

per_corner_residuals

Optional (N, 2) array of pixel errors for each corner

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]] | None

per_corner_camera_labels

Optional list of camera names parallel to per_corner_residuals

Type:

list[str] | None

per_frame_errors

Optional dict mapping frame index to error value

Type:

dict[int, float] | None

class aquacal.config.schema.CalibrationMetadata(calibration_date, software_version, config_hash, num_frames_used, num_frames_holdout)[source]

Bases: object

Metadata for reproducibility.

Parameters:
  • calibration_date (str)

  • software_version (str)

  • config_hash (str)

  • num_frames_used (int)

  • num_frames_holdout (int)

calibration_date

ISO format date string

Type:

str

software_version

Version of aquacal library used

Type:

str

config_hash

Hash of configuration for reproducibility

Type:

str

num_frames_used

Number of frames used in calibration

Type:

int

num_frames_holdout

Number of frames held out for validation

Type:

int

class aquacal.config.schema.CalibrationConfig(board, camera_names, intrinsic_video_paths, extrinsic_video_paths, output_dir, intrinsic_board=None, n_air=1.0, n_water=1.333, interface_normal_fixed=False, robust_loss='huber', loss_scale=1.0, min_corners_per_frame=8, min_cameras_per_frame=2, frame_step=1, holdout_fraction=0.2, max_calibration_frames=None, refine_intrinsics=False, refine_auxiliary_intrinsics=False, save_detailed_residuals=True, initial_water_z=None, rational_model_cameras=<factory>, auxiliary_cameras=<factory>, fisheye_cameras=<factory>)[source]

Bases: object

Input configuration for calibration pipeline.

Parameters:
board

ChArUco board specification (extrinsic/underwater board)

Type:

aquacal.config.schema.BoardConfig

camera_names

List of camera identifiers

Type:

list[str]

intrinsic_video_paths

Dict mapping camera names to intrinsic calibration videos

Type:

dict[str, pathlib.Path]

extrinsic_video_paths

Dict mapping camera names to extrinsic calibration videos

Type:

dict[str, pathlib.Path]

output_dir

Directory for output files

Type:

pathlib.Path

intrinsic_board

Optional separate board for in-air intrinsic calibration (defaults to None, uses board)

Type:

aquacal.config.schema.BoardConfig | None

n_air

Refractive index of air (default 1.0)

Type:

float

n_water

Refractive index of water (default 1.333)

Type:

float

interface_normal_fixed

Whether to fix interface normal to [0, 0, -1]

Type:

bool

robust_loss

Loss function for optimization (“huber”, “soft_l1”, “linear”)

Type:

str

loss_scale

Scale parameter for robust loss in pixels

Type:

float

min_corners_per_frame

Minimum corners required to use a detection

Type:

int

min_cameras_per_frame

Minimum cameras required to use a frame

Type:

int

frame_step

Process every Nth frame (1 = all frames, default 1)

Type:

int

holdout_fraction

Fraction of frames to hold out for validation

Type:

float

max_calibration_frames

Maximum number of frames for Stages 3-4 optimization. None (default) = use all calibration frames. When set, calibration frames are uniformly subsampled to this limit before optimization.

Type:

int | None

refine_intrinsics

If True, Stage 4 jointly refines per-camera focal lengths (fx, fy) and principal points (cx, cy) alongside extrinsics and interface distances. Distortion coefficients are NOT refined. Only enable after Stage 3 converges reliably. Default False (Stage 4 skipped).

Type:

bool

save_detailed_residuals

Whether to save per-corner residuals

Type:

bool

initial_water_z

Optional dict mapping camera names to approximate camera-to-water-surface distances in meters. When None, all cameras default to 0.15m. Doesn’t need to be exact — within 2-3x of the true value is sufficient for good initialization in Stage 3.

Type:

dict[str, float] | None

rational_model_cameras

List of camera names that should use the 8-coefficient rational distortion model instead of the standard 5-coefficient model. Use for wide-angle lenses where 5 coefficients are insufficient.

Type:

list[str]

auxiliary_cameras

List of auxiliary camera names registered post-hoc against fixed board poses. These cameras are calibrated for intrinsics and detected, but excluded from joint Stage 3/4 optimization. Must not overlap with camera_names.

Type:

list[str]

fisheye_cameras

List of camera names that should use the equidistant fisheye projection model. Must be a subset of auxiliary_cameras and must not overlap with rational_model_cameras.

Type:

list[str]

refine_auxiliary_intrinsics

If True, Stage 4b refines auxiliary camera intrinsics (fx, fy, cx, cy) alongside extrinsics. Requires auxiliary_cameras to be set. Independent of refine_intrinsics (which controls primary camera refinement in Stage 4). Distortion coefficients are NOT refined.

Type:

bool

class aquacal.config.schema.BoardPose(frame_idx, rvec, tvec)[source]

Bases: object

Pose of ChArUco board in a single frame.

Parameters:
frame_idx

Frame index in the video sequence

Type:

int

rvec

Rodrigues rotation vector (3,)

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

tvec

Translation vector (3,)

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

class aquacal.config.schema.Detection(corner_ids, corners_2d)[source]

Bases: object

ChArUco detection in a single image.

Parameters:
corner_ids

Array of corner IDs detected, shape (N,)

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.int32]]

corners_2d

Array of 2D corner positions in pixels, shape (N, 2)

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

property num_corners: int

Number of detected corners.

Returns:

Count of detected corners

class aquacal.config.schema.PointCorrespondence(point_3d, observations, weight=1.0)[source]

Bases: object

A 3D point with its observed 2D projections across cameras.

Used by refine_calibration() to refine an existing calibration using 3D-to-2D point correspondences from downstream analysis.

Parameters:
point_3d

3D point in world coordinates, shape (3,)

Type:

numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]

observations

Dict mapping camera name to observed pixel coordinate (u, v). Must contain at least 2 cameras.

Type:

dict[str, numpy.ndarray[tuple[int, …], numpy.dtype[numpy.float64]]]

weight

Optional non-negative weight for this correspondence. Default 1.0. Set to 0.0 to soft-disable without removing.

Type:

float

class aquacal.config.schema.CameraDrift(translation_mm, rotation_deg, exceeded)[source]

Bases: object

Per-camera extrinsics drift metrics from refinement.

Parameters:
translation_mm

Translation shift magnitude in millimeters.

Type:

float

rotation_deg

Rotation shift magnitude in degrees.

Type:

float

exceeded

True if either translation or rotation exceeds its threshold.

Type:

bool

class aquacal.config.schema.ValidationReport(holdout_reproj_error, triangulation_consistency_before, triangulation_consistency_after, camera_drifts, accepted, summary)[source]

Bases: object

Structured validation report for a calibration refinement.

Parameters:
holdout_reproj_error

RMS reprojection error on held-out correspondences (pixels).

Type:

float

triangulation_consistency_before

Mean ray intersection residual before refinement (meters).

Type:

float

triangulation_consistency_after

Mean ray intersection residual after refinement (meters).

Type:

float

camera_drifts

Per-camera extrinsics drift, mapping camera name to CameraDrift.

Type:

dict[str, aquacal.config.schema.CameraDrift]

accepted

True if all thresholds pass, False if any exceeded.

Type:

bool

summary

Human-readable explanation of the accept/reject decision.

Type:

str

class aquacal.config.schema.RefinementResult(result, validation_report, accepted)[source]

Bases: object

Result of refine_calibration() with optional validation.

Parameters:
result

The refined CalibrationResult.

Type:

aquacal.config.schema.CalibrationResult

validation_report

Structured validation metrics, or None if validate=False was passed.

Type:

aquacal.config.schema.ValidationReport | None

accepted

True/False recommendation, or None if validate=False.

Type:

bool | None

class aquacal.config.schema.FrameDetections(frame_idx, detections)[source]

Bases: object

Detections across all cameras for a single frame.

Parameters:
frame_idx

Frame index in the video sequence

Type:

int

detections

Dict mapping camera names to Detection objects

Type:

dict[str, aquacal.config.schema.Detection]

property cameras_with_detections: list[str]

List of camera names that detected the board in this frame.

Returns:

List of camera names

property num_cameras: int

Number of cameras that detected the board in this frame.

Returns:

Count of cameras with detections

class aquacal.config.schema.DetectionResult(frames, camera_names, total_frames)[source]

Bases: object

All detections from a video set.

Parameters:
frames

Dict mapping frame indices to FrameDetections

Type:

dict[int, aquacal.config.schema.FrameDetections]

camera_names

List of all camera names in the dataset

Type:

list[str]

total_frames

Total number of frames processed

Type:

int

get_frames_with_min_cameras(min_cameras)[source]

Return frame indices where at least min_cameras see the board.

Parameters:

min_cameras (int) – Minimum number of cameras required

Returns:

List of frame indices meeting the criterion

Return type:

list[int]

exception aquacal.config.schema.CalibrationError[source]

Bases: Exception

Base class for calibration-related errors.

exception aquacal.config.schema.InsufficientDataError[source]

Bases: CalibrationError

Raised when there isn’t enough data for calibration.

exception aquacal.config.schema.ConvergenceError[source]

Bases: CalibrationError

Raised when optimization fails to converge.

exception aquacal.config.schema.ConnectivityError[source]

Bases: CalibrationError

Raised when pose graph is not connected (cameras cannot be linked).