fovi.sensing.calibration

Construction-time foveal density fitting against a calibrated source camera.

fovi.sensing.calibration.minimize_scalar(fun, bracket=None, bounds=None, args=(), method=None, tol=None, options=None)[source]

Local minimization of scalar function of one variable.

Parameters:
  • fun (callable) –

    Objective function. Scalar function, must return a scalar.

    Suppose the callable has signature f0(x, *my_args, **my_kwargs), where my_args and my_kwargs are required positional and keyword arguments. Rather than passing f0 as the callable, wrap it to accept only x; e.g., pass fun=lambda x: f0(x, *my_args, **my_kwargs) as the callable, where my_args (tuple) and my_kwargs (dict) have been gathered before invoking this function.

  • bracket (sequence, optional) – For methods ‘brent’ and ‘golden’, bracket defines the bracketing interval and is required. Either a triple (xa, xb, xc) satisfying xa < xb < xc and func(xb) < func(xa) and  func(xb) < func(xc), or a pair (xa, xb) to be used as initial points for a downhill bracket search (see scipy.optimize.bracket). The minimizer res.x will not necessarily satisfy xa <= res.x <= xb.

  • bounds (sequence, optional) – For method ‘bounded’, bounds is mandatory and must have two finite items corresponding to the optimization bounds.

  • args (tuple, optional) – Extra arguments passed to the objective function.

  • method (str or callable, optional) –

    Type of solver. Should be one of:

    • Brent

    • Bounded

    • Golden

    • custom - a callable object (added in version 0.14.0), see below

    Default is “Bounded” if bounds are provided and “Brent” otherwise. See the ‘Notes’ section for details of each solver.

  • tol (float, optional) – Tolerance for termination. For detailed control, use solver-specific options.

  • options (dict, optional) –

    A dictionary of solver options.

    maxiterint

    Maximum number of iterations to perform.

    dispbool

    Set to True to print convergence messages.

    See show_options() for solver-specific options.

Returns:

res – The optimization result represented as a OptimizeResult object. Important attributes are: x the solution array, success a Boolean flag indicating if the optimizer exited successfully and message which describes the cause of the termination. See OptimizeResult for a description of other attributes.

Return type:

OptimizeResult

See also

minimize

Interface to minimization algorithms for scalar multivariate functions

show_options

Additional options accepted by the solvers

Notes

This section describes the available solvers that can be selected by the ‘method’ parameter. The default method is the "Bounded" Brent method if bounds are passed and unbounded "Brent" otherwise.

Method Brent uses Brent’s algorithm [1] to find a local minimum. The algorithm uses inverse parabolic interpolation when possible to speed up convergence of the golden section method.

Method Golden uses the golden section search technique [1]. It uses analog of the bisection method to decrease the bracketed interval. It is usually preferable to use the Brent method.

Method Bounded can perform bounded minimization [2] [3]. It uses the Brent method to find a local minimum in the interval x1 < xopt < x2.

Note that the Brent and Golden methods do not guarantee success unless a valid bracket triple is provided. If a three-point bracket cannot be found, consider scipy.optimize.minimize. Also, all methods are intended only for local minimization. When the function of interest has more than one local minimum, consider global_optimization.

Custom minimizers

It may be useful to pass a custom minimization method, for example when using some library frontend to minimize_scalar. You can simply pass a callable as the method parameter.

The callable is called as method(fun, args, **kwargs, **options) where kwargs corresponds to any other parameters passed to minimize (such as bracket, tol, etc.), except the options dict, which has its contents also passed as method parameters pair by pair. The method shall return an OptimizeResult object.

The provided method callable must be able to accept (and possibly ignore) arbitrary parameters; the set of parameters accepted by minimize may expand in future versions and then these parameters will be passed to the method. You can find an example in the scipy.optimize tutorial.

Added in version 0.11.0.

References

Examples

Consider the problem of minimizing the following function.

>>> def f(x):
...     return (x - 2) * x * (x + 2)**2

Using the Brent method, we find the local minimum as:

>>> from scipy.optimize import minimize_scalar
>>> res = minimize_scalar(f)
>>> res.fun
-9.9149495908

The minimizer is:

>>> res.x
1.28077640403

Using the Bounded method, we find a local minimum with specified bounds as:

>>> res = minimize_scalar(f, bounds=(-3, -1), method='bounded')
>>> res.fun  # minimum
3.28365179850e-13
>>> res.x  # minimizer
-2.0000002026
fovi.sensing.calibration.find_desired_res(fov, cmf_a, n_points_desired, style, device='cpu', bounds=(1, 1000), force_less_than=False, quiet=False, fov_type='circular', field_geometry='planar', radius_norm=2.0)[source]

Find the resolution that gives the desired number of sampling points using binary search.

Parameters:
  • fov (float) – Field of view diameter in degrees.

  • cmf_a (float) – A parameter from the CMF: M(r)=1/(r+a). Smaller a = stronger foveation.

  • n_points_desired (int) – Desired number of sampling points.

  • style (str) – Which sampling style, e.g. ‘isotropic’.

  • device (str, optional) – Device to run computation on. Defaults to ‘cpu’.

  • bounds (tuple, optional) – Bounds for resolution search. Defaults to (1,1000).

  • force_less_than (bool, optional) – Whether to force less than target resolution. Defaults to False.

  • quiet (bool, optional) – Whether to suppress output. Defaults to False.

Returns:

A tuple containing:
  • int: Resolution that gives the desired number of points.

  • int: Actual number of points achieved.

Return type:

tuple

fovi.sensing.calibration.isotropic_foveal_ring(fov: float, cmf_a: float, res: int, fov_type: str = 'circular', field_geometry: str = 'planar') → Tensor[source]

Return the first noncentral ring as normalized (N, 2) visual coordinates.

class fovi.sensing.calibration.CameraModel(model: str, image_size: tuple[int, int], intrinsics: tuple[float, float, float, float], distortion: tuple[float, ...] = (), image_circle: tuple[float, float, float] | None = None, max_angle_deg: float = 90.0)[source]

Bases: object

A calibrated pinhole or equidistant-polynomial fisheye camera.

Parameters:
  • model – pinhole or fisheye (OpenCV fisheye convention).

  • image_size – Source image (height, width).

  • intrinsics – (fx, fy, cx, cy), in integer-center pixel coordinates.

  • distortion – Pinhole (k1, k2, p1, p2[, k3[, k4, k5, k6]]) or fisheye (k1, k2, k3, k4). Empty means the ideal model.

  • image_circle – Optional usable disc (cx, cy, radius), in source pixels.

  • max_angle_deg – Calibrated angular domain about the optical axis.

model: str
image_size: tuple[int, int]
intrinsics: tuple[float, float, float, float]
distortion: tuple[float, ...] = ()
image_circle: tuple[float, float, float] | None = None
max_angle_deg: float = 90.0
classmethod from_config(camera: CameraModel | CameraCalibration) → CameraModel[source]

Normalize serialized calibration once at an API boundary.

resized(image_size: tuple[int, int]) → CameraModel[source]

Calibrate a full-frame resize; cropping and image rotation need new intrinsics.

_pinhole_undistort(target: Tensor) → Tensor[source]

Invert radial/tangential distortion with a batched analytic Newton step.

pixel_validity(pixels: Tensor) → Tensor[source]

Return (…,) validity for (…, 2) source pixels.

project(directions: Tensor) → tuple[Tensor, Tensor][source]

Project (…, 3) directions to (…, 2) pixels and (…,) validity.

unproject(pixels: Tensor) → tuple[Tensor, Tensor][source]

Invert calibrated pixels into unit directions; flag failed inversions.

field_of_view(reference_side: str, fraction: float = 1.0) → float[source]

Return the angular span of a centered short/long-side retinal window.

Window endpoints are image boundaries in integer-center coordinates. The selected axis follows pixel dimensions, not an assumed aspect ratio.

__init__(model: str, image_size: tuple[int, int], intrinsics: tuple[float, float, float, float], distortion: tuple[float, ...] = (), image_circle: tuple[float, float, float] | None = None, max_angle_deg: float = 90.0) → None
fovi.sensing.calibration.angular_directions(cartesian: Tensor, fov_deg: float) → Tensor[source]

Map normalized retinal (N, 2), X right/Y up, to camera unit rays.

fovi.sensing.calibration.gaze_rotation(directions: Tensor, convention: str = 'camera_xyz') → Tensor[source]

Aim +Z at (B, 3) directions using the declared zero-torsion convention.

camera_xyz matches Rx(roll) Ry(pitch) in a Y-down/Z-forward camera. pan_tilt matches pan-then-tilt, Ry(pan) Rx(tilt).

fovi.sensing.calibration.calibrated_cmf_a(camera: CameraModel, fov: float, resolution: int, *, auto_match_cart_resources: bool, style: str, fov_type: str, gaze_convention: str) → float[source]

Fit minimum center-to-first-ring spacing to one source pixel at central gaze.

The minimum is over the actual first-ring directions, so anisotropic focal lengths and lens distortion participate in the criterion. Resource matching selects the effective ring count for each candidate. Integer ring counts can make the optimum discontinuous; require spacing within 5% of one pixel. The returned degree-valued CMF parameter stays fixed across all later gazes.

Parameters:
  • camera – Calibration of the images that will be sampled.

  • fov – Full angular diameter in degrees.

  • resolution – Ring count, or Cartesian side length when resource matching.

  • auto_match_cart_resources – Match the squared resolution as a node budget.

  • style – Sampling layout; automatic calibration supports isotropic.

  • fov_type – circular or square retinal boundary.

  • gaze_convention – Rotation convention at nominal central gaze.

Returns:

Positive CMF parameter in degrees.

Raises:

ValueError – The layout or calibration cannot meet the density criterion.