ForeshorteningCalibration#

class pypillometry.ForeshorteningCalibration(eye, theta, phi, experimental_setup, spline_coeffs, spline_knots, spline_degree=3, fit_intervals=None, fit_metrics=None)[source]#

Bases: object

Container for foreshortening correction calibration parameters.

This class stores the fitted camera geometry and temporal pupil model needed to correct pupil size measurements for viewing angle effects. It is usually created by fit_foreshortening().

Parameters:
  • eye (str) – Which eye (‘left’ or ‘right’)

  • theta (float) – Fitted camera polar angle from the z-axis in radians (the fit constrains it to [0, pi/2])

  • phi (float) – Fitted camera azimuthal angle in the x-y plane in radians (the fit constrains it to [-pi, pi])

  • experimental_setup (ExperimentalSetup) – Experimental setup containing known geometry; its camera distance r and eye-to-screen distance d are used for the correction

  • spline_coeffs (ndarray) – B-spline coefficients for true pupil size A0(t)

  • spline_knots (ndarray) – Knot vector for B-spline (time in ms)

  • spline_degree (int) – Degree of B-spline (3 for cubic)

  • fit_intervals (Optional[Intervals]) – Intervals used for fitting, if any

  • fit_metrics (Optional[Dict]) – Fit quality metrics; fit_foreshortening() stores ‘r2’, ‘rmse’, ‘n_samples’, ‘loss’, ‘n_iterations’ and ‘converged’. Default is an empty dict.

Attributes:
eyestr

Which eye (‘left’ or ‘right’)

thetafloat

Fitted camera polar angle in radians

phifloat

Fitted camera azimuthal angle in radians

experimental_setupExperimentalSetup

Experimental setup containing known geometry (r, d, screen info)

spline_coeffsnp.ndarray

B-spline coefficients for true pupil size A0(t)

spline_knotsnp.ndarray

Knot vector for B-spline

spline_degreeint

Degree of B-spline (typically 3 for cubic)

fit_intervalsIntervals or None

Intervals used for fitting, if any

fit_metricsdict

Fit quality metrics (R², RMSE, etc.)

Examples

>>> import numpy as np
>>> from pypillometry.eyedata import ExperimentalSetup
>>> from pypillometry.eyedata.foreshortening_calibration import ForeshorteningCalibration
>>> 
>>> # Create experimental setup
>>> setup = ExperimentalSetup(
...     screen_resolution=(1920, 1080),
...     physical_screen_size=("52 cm", "29 cm"),
...     eye_to_screen_center="70 cm",
...     camera_spherical=("85 deg", "-90 deg", "60 cm"),
... )
>>> 
>>> # Create a calibration object with fitted parameters
>>> theta = np.radians(85)  # fitted angle
>>> phi = np.radians(-90)   # fitted angle
>>> knots = np.array([0]*4 + [50] + [100]*4)
>>> coeffs = np.array([3.5, 3.7, 3.6, 3.8, 3.5])
>>> 
>>> cal = ForeshorteningCalibration(
...     eye='left',
...     theta=theta,
...     phi=phi,
...     experimental_setup=setup,
...     spline_coeffs=coeffs,
...     spline_knots=knots,
...     spline_degree=3,
...     fit_metrics={'r2': 0.95, 'rmse': 0.12}
... )
>>> 
>>> # Get correction factor at screen center (using pixel coordinates)
>>> correction = cal.get_correction_factor(960, 540)  # screen center in pixels
>>> print(f"Correction factor: {correction:.3f}")

Methods

evaluate_spline

Evaluate true pupil size A0(t) at given time point(s).

get_correction_factor

Compute correction factor 1/cos(alpha) with quality control thresholding.

Details

evaluate_spline(t)[source]#

Evaluate true pupil size A0(t) at given time point(s).

Parameters:

t (Union[float, ndarray]) – Time point(s) in ms

Return type:

Union[float, ndarray]

Returns:

A0 (float or array) – True pupil size(s)

Examples

>>> A0_at_t50 = cal.evaluate_spline(50.0)
>>> A0_trace = cal.evaluate_spline(np.linspace(0, 100, 100))
get_correction_factor(x, y, threshold=0.15, from_pixels=True)[source]#

Compute correction factor 1/cos(alpha) with quality control thresholding.

When cos(alpha) is very small (extreme viewing angles), the correction factor becomes very large and amplifies measurement noise. This method returns a masked array where values below threshold are masked.

Parameters:
  • x (Union[float, ndarray]) – Gaze x-coordinate(s) in screen pixels (default) or in mm relative to screen center (if from_pixels is False)

  • y (Union[float, ndarray]) – Gaze y-coordinate(s) in screen pixels (default) or in mm relative to screen center (if from_pixels is False)

  • threshold (float) – Minimum cos(alpha) for reliable correction (0.15 corresponds to ~81° viewing angle)

  • from_pixels (bool) – If True (default), x and y are in pixels and are converted to mm with pixels_to_mm() (centered, positive y = up; as in fit_foreshortening()). If False, x and y are already in mm relative to screen center. Requires experimental_setup to have screen info when True.

Return type:

MaskedArray

Returns:

correction_factor (numpy.ma.MaskedArray) – Correction factor(s), with values masked where cos(alpha) < threshold.

Raises:

ValueError – If from_pixels is True and the setup has no screen info, or if the setup has no camera position or eye-to-screen distance (r and d are taken from experimental_setup).

Notes

To apply correction: A0_corrected = A_measured * correction_factor

Only the monocular model is used (no eye offset), and screen offset and tilt in experimental_setup are not taken into account.

Masked arrays multiply cleanly with other masked arrays, combining masks automatically (union of masks).

Examples

>>> # Using pixel coordinates (typical use case - default)
>>> correction = cal.get_correction_factor(960, 540)
>>> corrected_pupil = measured_pupil * correction
>>> 
>>> # Using mm coordinates (relative to screen center)
>>> correction = cal.get_correction_factor(0, 0, from_pixels=False)
>>> corrected_pupil = measured_pupil * correction