Inference, Camera, Recording, And Gaze

class meyelens.meye.Camera(camera_index=0, calibration_file='camera_calibration.toml', undistort=False, exposure=0, framerate=30, resolution=(640, 480), auto_exposure=True, crop=None)[source]

Bases: object

Open a camera and configure acquisition settings.

Parameters:
  • camera_index (int, default=0) – Camera index passed to cv2.VideoCapture. The default value 0 usually opens the first available camera.

  • calibration_file (str or pathlib.Path, default="camera_calibration.toml") –

    Path to a TOML camera-calibration file.

    The file should contain the following top-level keys:

    camera_matrix

    A 3 x 3 OpenCV camera intrinsic matrix.

    distortion_coefficients

    OpenCV distortion coefficients, usually [k1, k2, p1, p2, k3].

    If the file is missing or invalid, the camera still opens and the class proceeds without calibration.

  • undistort (bool, default=False) – If True, apply OpenCV undistortion to frames returned by get_frame(), provided that valid calibration parameters were loaded from calibration_file.

  • exposure (int or float, default=0) –

    Manual exposure value requested from the camera when auto_exposure=False.

    The meaning and valid range of this value depend on the camera, operating system, and OpenCV backend.

  • framerate (int or float, default=30) –

    Requested camera frame rate in frames per second.

    This value is passed to cv2.CAP_PROP_FPS. The actual frame rate may differ from the requested value.

  • resolution (tuple of int, default=(640, 480)) –

    Requested camera resolution as (width, height).

    This value is passed to cv2.CAP_PROP_FRAME_WIDTH and cv2.CAP_PROP_FRAME_HEIGHT. The actual resolution may differ if the camera does not support the requested size.

  • auto_exposure (bool, default=True) –

    If True, attempt to enable camera auto-exposure.

    If False, attempt to disable auto-exposure and apply the manual value provided in exposure.

    Exposure control is hardware- and backend-dependent. Some cameras may ignore these requests.

  • crop (tuple of int or None, default=None) –

    Optional rectangular crop applied to frames returned by get_frame().

    The crop must be provided as (top, left, height, width) in pixels.

    top and left define the upper-left corner of the crop. height and width define the crop size.

    If None, no crop is applied.

Raises:
  • RuntimeError – If the camera cannot be opened with the requested camera_index.

  • ValueError – If crop is not None and is not a valid (top, left, height, width) tuple.

Notes

OpenCV camera properties are requests rather than guarantees. The actual resolution, frame rate, exposure mode, or exposure value may differ from the requested settings depending on the camera and driver.

The constructor calls, in order:

  1. cv2.VideoCapture(camera_index)

  2. load_calibration()

  3. set_resolution()

  4. set_auto_exposure()

  5. set_framerate(), only when auto_exposure=False

load_calibration(calibration_file)[source]

Load camera calibration parameters from a TOML file.

The calibration file is used only when undistort=True. If valid calibration parameters are loaded, frames returned by get_frame() can be undistorted using OpenCV.

The file must contain the following top-level TOML keys:

camera_matrix

A 3 x 3 OpenCV intrinsic camera matrix.

distortion_coefficients

OpenCV distortion coefficients. The most common format is [k1, k2, p1, p2, k3].

Parameters:
  • calibration_file (str or pathlib.Path) – Path to the TOML calibration file.

  • Modified (Attributes)

  • -------------------

  • camera_matrix (numpy.ndarray or None) – Set to the loaded 3 x 3 camera matrix if loading succeeds. Set to None if loading fails.

  • dist_coeffs (numpy.ndarray or None) – Set to the loaded distortion coefficients if loading succeeds. Set to None if loading fails.

  • _new_camera_matrix (numpy.ndarray or None) – Updated by the internal undistortion setup when calibration succeeds.

  • _roi (tuple or None) – Updated by the internal undistortion setup when calibration succeeds.

Returns:

This method modifies the camera object in place.

Return type:

None

Notes

Camera calibration is optional but useful when geometrically accurate images are needed. It corrects lens distortion, which can otherwise affect pupil position, ellipse shape, area, and gaze-related measurements. For simple pupil-area recordings with a centered eye ROI, calibration is usually not required.

If the file does not exist, the method prints a warning and continues without calibration.

If the file exists but does not contain the required keys, or if the calibration parameters are invalid, the method prints a warning and continues without calibration.

Camera calibration follows the standard OpenCV chessboard calibration procedure. See the official OpenCV tutorial:

https://docs.opencv.org/4.x/dc/dbb/tutorial_py_calibration.html

The resulting camera_matrix and distortion_coefficients should be saved in a TOML file.

get_frame(flip_vertical=True, apply_crop=True)[source]

Acquire one frame from the camera.

The returned frame can optionally be flipped vertically, undistorted using the loaded camera calibration, and cropped to the selected region of interest.

Parameters:
  • flip_vertical (bool, default=True) – If True, flip the frame vertically using cv2.flip(frame, 0).

  • apply_crop (bool, default=True) – If True and self.crop is not None, return only the selected crop region.

Returns:

The acquired frame as an OpenCV image array, or None if frame acquisition failed.

Return type:

numpy.ndarray or None

Notes

If self.undistort=True and valid calibration parameters are available, the frame is undistorted before cropping.

preview(window_name='Camera Preview')[source]

Show a live preview of the camera image.

The preview window displays the current camera frame together with the estimated acquisition frame rate and the current camera resolution.

During preview, the user can adjust manual exposure with the keyboard (if supported by OS and drivers):

  • o increases the exposure value by 1;

  • p decreases the exposure value by 1;

  • ESC closes the preview window.

Parameters:

window_name (str, default="Camera Preview") – Name of the OpenCV window used to display the live camera preview.

Returns:

This method runs an interactive preview loop until the user presses ESC.

Return type:

None

Notes

Frames are acquired using get_frame(), so the preview uses the current camera settings, including vertical flipping, undistortion, and cropping.

Exposure changes are applied by calling set_exposure(). Whether the camera responds to exposure changes depends on the camera hardware, driver, operating system, and OpenCV backend.

The displayed FPS is estimated from the number of frames acquired over approximately two-second intervals.

select_roi(window_name='Select ROI')[source]

Interactively select a rectangular region of interest.

This method opens a live camera window and lets the user draw a rectangular ROI with the mouse. When the ROI is saved, it is stored in self.crop as:

(top, left, height, width)

The selected crop is then automatically applied by get_frame() when apply_crop=True.

Parameters:

window_name (str, default="Select ROI") – Name of the OpenCV window used for interactive ROI selection.

Returns:

  • None – This method modifies self.crop in place.

  • Keyboard Controls

  • —————–

  • s – Save the currently selected ROI.

  • r – Reset the current selection and draw a new ROI.

  • ESC – Cancel ROI selection and keep the previous value of self.crop.

Notes

The ROI is selected on uncropped frames by calling get_frame(apply_crop=False). This allows the user to redefine the ROI even if a previous crop is already active.

The selected rectangle is clipped to the image boundaries before it is stored. If the user drags from bottom-right to top-left, negative width or height values are automatically converted to a valid rectangle.

If no valid frame can be acquired, the method prints a warning and returns without modifying self.crop.

class meyelens.meye.MeyeResult(probabilities: dict, masks: dict, features: dict, inference_time_ms: float, inference_fps: float)[source]

Bases: object

Container for the output of a MEYELens prediction.

A MeyeResult object is returned by Meye.predict(). It stores the binary segmentation masks, optional probability maps, optional extracted mask features, and inference timing information for one input frame.

probabilities

Dictionary containing probability maps for each predicted class.

Keys are class names, usually:

  • "pupil"

  • "eye"

Values are 2D NumPy arrays with the same height and width as the input frame. Probability maps are included only when Meye.return_probabilities=True. Otherwise, this dictionary is empty.

Type:

dict

masks

Dictionary containing binary segmentation masks for each predicted class.

Keys are class names, usually:

  • "pupil"

  • "eye"

Values are 2D uint8 NumPy arrays with the same height and width as the input frame. Mask pixels are encoded as:

  • 0 for background;

  • 255 for the segmented object.

Type:

dict

features

Dictionary containing geometric features extracted from the binary masks.

Keys are class names, usually "pupil" and "eye". Values are feature dictionaries returned by MeyeMaskFeatures.compute_mask.

Each feature dictionary may include:

  • valid

  • area

  • centroid

  • ellipse

If feature computation is disabled with Meye.compute_features=False, this dictionary is empty.

Type:

dict

inference_time_ms

Time required to run neural-network inference for the frame, in milliseconds.

This timing measures the model prediction step. It does not include camera acquisition, drawing, file writing, or downstream analysis.

Type:

float

inference_fps

Inference speed expressed as frames per second, computed from inference_time_ms.

Type:

float

class meyelens.meye.MeyeMaskFeatures[source]

Bases: object

Extract geometric features from MEYELens binary masks.

MeyeMaskFeatures is a stateless helper class used to compute simple geometric measurements from segmentation masks, usually the "pupil" and "eye" masks returned by Meye.predict().

The class is intentionally separate from Meye: the Meye class handles neural-network inference, thresholding, morphology, and preview logic, while MeyeMaskFeatures handles measurement of the resulting binary masks.

All methods are static. The class does not need to be instantiated.

Computed Features

For each input mask, the output is a dictionary with the following fields:

validbool

True if the mask contains at least one positive pixel. False if the mask is empty.

areaint

Number of positive pixels in the mask.

centroidtuple of float

Mean position of all positive pixels, returned as (row, col).

This follows NumPy image coordinates, where row corresponds to the vertical image coordinate and col corresponds to the horizontal image coordinate.

ellipsedict

Dictionary containing the ellipse fitted to the largest external contour in the mask.

If no valid ellipse can be fitted, the ellipse dictionary has valid=False and all numeric values are NaN.

Ellipse Features

The ellipse dictionary contains:

validbool

True if an ellipse was successfully fitted. False otherwise.

centertuple of float

Ellipse center as (row, col).

major_diameterfloat

Diameter of the major axis of the fitted ellipse, in pixels.

minor_diameterfloat

Diameter of the minor axis of the fitted ellipse, in pixels.

orientation_degfloat

Orientation of the major axis in degrees.

ovalityfloat

Shape elongation index computed as:

1 - minor_diameter / major_diameter

Values close to 0 indicate a nearly circular shape. Larger values indicate a more elongated shape.

eccentricityfloat

Ellipse eccentricity computed as:

sqrt(1 - (minor_diameter / major_diameter) ** 2)

Values close to 0 indicate a nearly circular ellipse. Values closer to 1 indicate a more elongated ellipse.

major_axisdict

Endpoints of the major axis. Contains:

p1

First endpoint as (row, col).

p2

Second endpoint as (row, col).

minor_axisdict

Endpoints of the minor axis. Contains:

p1

First endpoint as (row, col).

p2

Second endpoint as (row, col).

Notes

Input masks are interpreted as binary masks. Any pixel value greater than zero is treated as part of the object.

Ellipse fitting is performed on the largest external contour. This is useful when small isolated components are present, because the largest component is usually the pupil or eye region after morphology.

A valid mask does not always produce a valid ellipse. OpenCV requires at least five contour points to fit an ellipse. Therefore, a mask can have valid=True while ellipse["valid"] is False.

static compute_mask(mask)[source]

Compute geometric features for one binary mask.

Parameters:

mask (numpy.ndarray) – Two-dimensional binary mask. Pixels greater than zero are treated as object pixels.

Returns:

Feature dictionary with valid, area, centroid, and ellipse fields.

Return type:

dict

Notes

If the mask is empty, valid is False, area is 0, centroid is (np.nan, np.nan), and ellipse is an invalid ellipse dictionary.

static fit_ellipse(mask)[source]

Fit an ellipse to the largest external contour of a binary mask.

Parameters:

mask (numpy.ndarray) – Two-dimensional binary mask. Pixels greater than zero are treated as object pixels.

Returns:

Ellipse feature dictionary containing center, major/minor diameters, orientation, ovality, eccentricity, and axis endpoints.

If no ellipse can be fitted, returns empty_ellipse().

Return type:

dict

Notes

OpenCV requires at least five contour points to fit an ellipse. If the largest contour has fewer than five points, the returned ellipse is marked as invalid.

Coordinates are returned as (row, col) for consistency with NumPy image indexing.

static draw(image, features, draw_area=True, draw_centroid=True, draw_ellipse=True, draw_axis_points=True)[source]

Draw mask features on an image.

Parameters:
  • image (numpy.ndarray) – Image on which features are drawn. The image is modified in place and also returned.

  • features (dict) – Dictionary of feature dictionaries, usually produced by compute_all().

  • draw_area (bool, default=True) – If True, draw text showing mask name, area, ovality, and ellipse orientation when available.

  • draw_centroid (bool, default=True) – If True, draw the mask centroid.

  • draw_ellipse (bool, default=True) – If True, draw the fitted ellipse when available.

  • draw_axis_points (bool, default=True) – If True, draw the major and minor ellipse axes and their endpoints.

Returns:

The input image with the requested feature overlays.

Return type:

numpy.ndarray

Notes

The input image is modified in place.

Feature coordinates are stored as (row, col), but OpenCV drawing uses (x, y). This method performs the conversion internally.

static feature_color(name, idx)[source]

Return the drawing color for a feature name.

Parameters:
  • name (str) – Feature or mask name. Special colors are used for "pupil" and "eye".

  • idx (int) – Index of the feature in the drawing order. Used to select a fallback color for unknown names.

Returns:

OpenCV BGR color tuple.

Return type:

tuple of int

Notes

Returned colors are in BGR order, not RGB order, because they are used with OpenCV drawing functions.

class meyelens.meye.Meye(model_path=None, config_path=None, gpu_device='auto', use_half_precision=None, reset_config=False, verbose=True)[source]

Bases: object

Initialize the MEYELens segmentation model.

The constructor loads the TOML configuration file, resolves the model path, selects the inference device, loads the trained PyTorch checkpoint, and prepares the runtime settings used by predict(), overlay(), and the interactive preview methods.

If no configuration file exists, a default one is created automatically. The default configuration file is located at:

~/.meyelens/meye_config.toml

Parameters:
  • model_path (str) –

    Path to a trained MEYELens model checkpoint.

    If provided, this path overrides the model path stored in the TOML configuration file. The new path is also saved to the configuration file so that future Meye instances use the same checkpoint.

    If None, the model path is read from the configuration file.

  • config_path (pathlib.Path) –

    Path to the TOML configuration file.

    If None, the default path is used:

    ~/.meyelens/meye_config.toml

    If the file does not exist, it is created automatically using DEFAULT_CONFIG.

  • gpu_device ({"auto", "cpu", int, str}, default="auto") –

    Device used for model inference.

    Supported values are:

    "auto"

    Use CUDA if available, otherwise Apple MPS if available, otherwise CPU.

    "cpu"

    Force CPU inference.

    int

    Use a specific CUDA device index, for example 0 for "cuda:0".

    str

    Any valid PyTorch device string, for example "cuda:0".

    If CUDA or MPS is requested but unavailable, Meye prints a message and falls back to CPU inference.

  • use_half_precision (bool or None, default=None) –

    Whether to request half-precision inference.

    If None, the value is read from the configuration file.

    If True, half precision is used only when inference runs on CUDA. On CPU, inference remains in full precision even if half precision is requested.

    If a value is provided, it overrides the value stored in the TOML configuration file and is saved to that file.

  • reset_config (bool, default=False) –

    If True, overwrite the TOML configuration file with default settings before loading the model.

    This is useful when the saved configuration should be reset to a clean state.

  • verbose (bool, default=True) – If True, print information about the configuration file, selected device, loaded model architecture, input size, output channels, and current segmentation settings.

  • Initialized (Attributes)

  • ----------------------

  • config_path – Path to the active TOML configuration file.

  • config (dict) – Configuration dictionary loaded from the TOML file and merged with the default configuration.

  • model_path – Path to the model checkpoint that will be loaded.

  • class_names (list of str) – Output class names. For the standard MEYELens model these are ["pupil", "eye"].

  • thresholds (dict) – Segmentation thresholds for each class.

  • device (torch.device) – Device used for inference.

  • model (torch.nn.Module) – Loaded PyTorch model in evaluation mode.

  • input_size (int) – Input image size inferred from the checkpoint.

  • required_frame_size (tuple of int) – Required model input size as (input_size, input_size).

  • normalization (str) – Image normalization strategy selected from the detected model architecture.

  • last_result (MeyeResult or None) – Last result returned by predict(). Initialized as None.

Raises:
  • FileNotFoundError – If the model checkpoint file does not exist.

  • RuntimeError – If the checkpoint architecture cannot be detected or if the model state cannot be loaded.

  • ImportError – If the checkpoint requires an optional dependency that is not installed, for example timm for EfficientFormerV2 checkpoints.

Notes

The constructor may create or update the TOML configuration file.

The model architecture is inferred automatically from the checkpoint. The current implementation supports full PyTorch modules, SegFormer-style checkpoints, and EfficientFormerV2 two-head FPN checkpoints.

Half precision is applied only after the model is loaded and only when the selected device is CUDA.

predict(frame)[source]

Predict pupil and eye masks from one image frame.

This method runs the loaded MEYELens neural network on a single input frame, converts the model output logits to probability maps, thresholds the probabilities into binary masks, optionally applies mask post-processing, optionally extracts geometric features, and returns all results in a MeyeResult object.

Parameters:

frame (numpy.ndarray) –

Input image.

The frame can be either:

  • a grayscale image with shape (height, width);

  • a BGR OpenCV image with shape (height, width, 3).

BGR images are internally converted to RGB before model inference. Grayscale images are internally converted to RGB.

Returns:

  • MeyeResult – Prediction result for the input frame.

  • Attributes Modified

  • ——————-

  • last_result (MeyeResult) – Updated to the result returned by this method.

Raises:
  • RuntimeError – If the model output cannot be interpreted as a tensor of logits with shape (batch, channels, height, width).

  • ValueError – If the input frame has an unsupported shape or if internal preprocessing encounters an unsupported normalization mode.

static fill_holes_in_mask(mask)[source]

Fill internal holes in a binary mask.

Input and output are uint8 masks:

0 = background 255 = object

preview(cam, window_name='Meye Preview')[source]

Run an interactive MEYELens segmentation preview.

This method acquires frames from the camera object, runs predict() on each frame, draws the prediction overlay with overlay(), and displays the result in an OpenCV window.

The preview is useful for checking segmentation quality before recording, tuning pupil and eye thresholds, enabling or disabling morphology, and selecting which features should be drawn on the overlay.

Parameters:
  • cam (object) – Camera-like object used for frame acquisition and display. A Camera instance satisfies these requirements.

  • window_name (str, default="Meye Preview") – Name of the OpenCV window used to display the live preview.

Returns:

  • None – This method runs an interactive loop until the user presses q or ESC.

  • Keyboard Controls

  • —————–

  • q or ESC – Quit preview.

  • + or = – Increase pupil threshold.

  • - or _ – Decrease pupil threshold.

  • ] – Increase eye threshold.

  • [ – Decrease eye threshold.

  • m – Toggle morphological opening/closing.

  • b – Toggle keeping only the largest connected component.

  • u – Toggle hole filling.

  • p – Toggle pupil mask overlay.

  • o – Toggle eye mask overlay.

  • a – Toggle area text.

  • c – Toggle centroid drawing.

  • e – Toggle ellipse drawing.

  • x – Toggle major/minor ellipse axis drawing.

  • f – Toggle feature computation.

  • t – Toggle status text overlay.

  • s – Print current settings.

  • r – Reset the saved TOML configuration while keeping the current model path.

  • h – Print preview help.

Notes

When a setting is changed interactively, the updated value is saved to the active TOML configuration file. This means that threshold and preview settings persist across sessions.

Frames are processed using the current Meye settings, including thresholds, morphology, connected-component filtering, hole filling, feature computation, and overlay options.

If cam.get_frame() returns None, the method prints a warning and continues the preview loop.

preview_camera(camera_index=0, flip_180=False, camera_width=0, camera_height=0, window_name='Meye Preview')[source]

Run live preview directly from an OpenCV camera index.

Example

meye = Meye() meye.preview_camera(camera_index=0)

class meyelens.meye.MeyeRecorder(cam, meye, filename='meye', path_to_file=None, buffer_size=1000, sep=';', show_preview=False, preview_window_name='Meye Recording', save_inference_timing=True, flush_every=30, flush_interval=0.0, overflow_policy='raise')[source]

Bases: object

Initialize a MEYELens recorder.

The constructor stores the camera and MEYELens objects, prepares output-file settings, initializes trigger values, and creates the list of output column names. It does not start recording and does not open the output file. Recording begins only after calling start().

Parameters:
  • cam (object) –

    Camera-like object used to acquire frames.

    The object must provide:

    cam.get_frame()

    Acquire and return one image frame as a NumPy array, or return None if acquisition fails.

    cam.close()

    Release camera resources.

    If show_preview=True, the object must also provide:

    cam.show(image, name=...)

    Display an image in an OpenCV window.

    cam.refresh(delay_ms=...)

    Refresh OpenCV windows.

    A Camera instance satisfies these requirements.

  • meye (Meye) –

    MEYELens inference object used to predict pupil and eye masks.

    The object must provide:

    meye.predict(frame)

    Run segmentation on one frame and return a MeyeResult.

    meye.overlay(frame, result, draw_text=True)

    Create a preview image showing masks, features, and optional status text.

  • filename (str, default="meye") –

    Base name of the output recording file.

    A timestamp is prepended and the file extension is added by BufferedFileWriter. For example, filename="subject01" may produce a file such as 20260603_121530-subject01.txt.

  • path_to_file (pathlib.Path) –

    Directory where the recording file will be saved.

    If None, the default output directory is:

    ~/Documents/meyeDATA

    The directory is created automatically when recording starts.

  • buffer_size (int, default=1000) –

    Maximum number of completed data rows that can wait in the asynchronous writer queue.

    If the acquisition loop produces rows faster than the background writer can save them, the queue grows up to this limit. The behavior when the queue is full is controlled by overflow_policy.

  • sep (str, default=";") – Separator used between columns in the output text file.

  • show_preview (bool, default=False) –

    If True, display a live MEYELens overlay during recording.

    For best recording performance, especially when high frame rates are needed, keep this set to False.

  • preview_window_name (str, default="Meye Recording") – Name of the OpenCV preview window used when show_preview=True.

  • save_inference_timing (bool, default=True) – If True, include inference_ms and inference_fps columns in the output file.

  • flush_every (int, default=30) –

    Flush the file buffer after this many written rows.

    This controls how often already written rows are pushed from Python’s file buffer to the operating system. It does not control how often rows are removed from the writer queue.

  • flush_interval (float, default=0.0) –

    Flush the file buffer at least every this many seconds.

    If 0.0, time-based flushing is disabled. The file is always flushed when stop() or close_all() closes the writer.

  • overflow_policy ({"raise", "block", "drop"}, default="raise") –

    Behavior when the asynchronous writer queue is full.

    "raise"

    Raise a RuntimeError. Recommended for experiments, because it makes missed writes explicit.

    "block"

    Wait until queue space is available. This prevents data loss but can pause the acquisition loop.

    "drop"

    Drop the new row and print a warning. This avoids blocking but can lose data.

  • Initialized (Attributes)

  • ----------------------

  • cam – Camera-like object passed to the constructor.

  • meye – MEYELens inference object passed to the constructor.

  • path_to_file – Output directory.

  • writer (BufferedFileWriter or None) – Buffered writer used during recording. Initialized as None and created by start().

  • time_start (float or None) – Reference timestamp for the recording clock. Initialized as None and set by start().

  • running (bool) – Whether recording is active. Initialized as False.

  • frame (numpy.ndarray or None) – Last acquired frame. Initialized as None.

  • result (MeyeResult or None) – Last MEYELens prediction result. Initialized as None.

  • frame_index (int) – Index of the next frame to be recorded. Initialized as 0.

  • trg1 (int) – Trigger channels. All initialized to 0.

  • trg2 (int) – Trigger channels. All initialized to 0.

  • ... (int) – Trigger channels. All initialized to 0.

  • trg9 (int) – Trigger channels. All initialized to 0.

  • headers (list of str) – Output column names generated by the internal header builder.

Notes

The constructor does not create the output file. The file is created when start() is called.

Trigger values are provided later to save_frame(). They are stored in the output row corresponding to the exact frame acquired during that call.

start(metadata=None)[source]

Start recording and open the output file.

This method creates a BufferedFileWriter, writes metadata and the column header to the output file, resets the recording clock and frame index, and sets self.running=True.

Parameters:

metadata (dict or None, default=None) –

Optional user-defined metadata describing the recording session.

Metadata are written at the top of the output file as comment lines before the data table. They are useful for storing information needed to interpret the recording later, such as:

  • subject or participant ID;

  • session name or number;

  • experimental condition;

  • task name;

  • stimulus parameters;

  • acquisition notes.

Example:

{"subject": "S01", "session": "pre", "condition": "baseline"}

If None, only automatically generated MEYELens and recorder metadata are written.

Return type:

None

Notes

If recording is already active, this method prints a message and returns without creating a new file.

User metadata are combined with automatically generated metadata describing the MEYELens model, configuration file, class names, thresholds, morphology settings, camera crop, and writer settings.

If self.meye.compute_features is False, this method enables it automatically because the recorder output columns require mask features.

The recording clock starts when this method is called. The timestamps saved by save_frame() are relative to this start time.

stop()[source]

Stop recording and close the output file.

This method stops the active recording, drains the writer queue, flushes the file buffer, closes the output file, and sets self.running=False.

Return type:

None

Notes

This method does not release the camera. To release camera resources, call close(). To both stop recording and release the camera, call close_all().

It is safe to call this method even when no writer is active. In that case, the method simply sets self.running=False.

close()[source]

Release camera resources.

This method calls self.cam.close() when a camera object is available.

Return type:

None

Notes

This method does not stop the file writer by itself. If recording is active, call stop() before releasing the camera, or use close_all().

close_all()[source]

Stop recording and release all recorder resources.

This convenience method calls stop() and then close(). It is the recommended cleanup method at the end of an experiment because it ensures that queued rows are written to disk and that camera resources are released.

Return type:

None

Notes

This method flushes and closes the writer through stop(), then closes the camera through close().

save_frame(trg1=0, trg2=0, trg3=0, trg4=0, trg5=0, trg6=0, trg7=0, trg8=0, trg9=0)[source]

Capture one frame, run MEYELens prediction, and save one data row.

This method is the main recording operation of MeyeRecorder. It acquires one camera frame, runs Meye.predict() on that exact frame, extracts pupil and eye features, attaches the provided trigger values, and queues one complete row for writing to the output file.

Frame acquisition, prediction, feature extraction, and trigger assignment are synchronous. Only the final file-writing step is buffered through BufferedFileWriter.

Parameters:
  • trg1 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg2 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg3 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg4 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg5 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg6 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg7 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg8 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

  • trg9 (int or float, default=0) –

    User-defined trigger values saved in the output row.

    Trigger values are arbitrary numeric codes defined by the experiment. They can be used to mark stimulus onset, trial number, condition, response events, task phase, or other experimental variables.

    The trigger values belong to the frame acquired during this exact save_frame() call.

Returns:

Dictionary containing the extracted data for the saved frame, or None if recording has not started or if frame acquisition fails.

The returned dictionary includes timing values, pupil features, eye features, and inference timing. Trigger values are written to the file row but are not included in the returned dictionary.

Return type:

dict or None

Notes

Recording must be started with start() before calling this method. If the recorder is not running, the method prints a warning and returns None.

The method records three timestamps, all relative to the time when start() was called:

t_call

Time when save_frame() was called.

t_frame

Time immediately after camera frame acquisition.

t_pred

Time immediately after MEYELens prediction.

If frame acquisition fails and cam.get_frame() returns None, no row is written and the method returns None.

If show_preview=True, the method also draws and displays a MEYELens overlay after writing the row. Live preview can reduce acquisition performance.

The output file row is queued for asynchronous writing. Calling this method does not necessarily mean that the row has already been physically written to disk, but stop() and close_all() flush and close the writer.

get_data()[source]

Acquire one new frame and return extracted data without writing to disk.

This method captures a new frame from the camera, runs Meye.predict(), extracts pupil and eye features, and returns the result as a dictionary. Unlike save_frame(), it does not queue a row for file writing and does not save anything to the output file.

Returns:

Dictionary containing timing values, pupil features, eye features, and inference timing for the newly acquired frame.

Returns None if frame acquisition fails.

Return type:

dict or None

Notes

This method can be used before or during recording.

If recording has already been started with start(), timestamps are relative to the recording start time.

If recording has not been started, a temporary local reference time is used for the returned timestamps.

This method updates self.frame and self.result with the newly acquired frame and prediction result.

No trigger values are attached and no data are written to disk.

get_last_data()[source]

Return extracted data from the most recent prediction.

This method does not acquire a new frame and does not run a new MEYELens prediction. It reuses self.result, which is the most recent result produced by save_frame() or get_data(), and converts it to the same dictionary format used for recorder output.

Returns:

Dictionary containing pupil features, eye features, and inference timing from the most recent prediction.

Returns None if no prediction result is available yet.

Return type:

dict or None

Notes

Because no new frame is acquired, this method is useful when the latest result should be inspected or reused without changing the camera/model state.

The returned timing fields t_call, t_frame, and t_pred are set to math.nan because no new acquisition or prediction is performed.

The returned frame_index corresponds to the last saved frame when used after save_frame(). If no frame has been saved yet, it returns 0.

preview()[source]

Run the interactive MEYELens preview using the recorder camera.

This is a convenience method that calls Meye.preview() with the camera object stored in the recorder. It can be used to check the camera image, inspect segmentation quality, tune pupil and eye thresholds, and adjust preview options before starting an acquisition.

Returns:

This method runs an interactive preview loop until the user quits the preview with q or ESC.

Return type:

None

Notes

This method does not start recording and does not write data to disk.

It uses the same camera object stored in self.cam and the same MEYELens model stored in self.meye.

Any threshold or preview setting changed during the interactive preview is handled by Meye.preview(). In the standard Meye implementation, these changes are saved to the active TOML configuration file.

class meyelens.meye.MeyeGazeCalibrator(screen_width, screen_height, num_points=9, random_points=False, random_seed=None, feature_columns=None, model_type='ridge_poly')[source]

Bases: object

Initialize an in-memory MEYELens gaze calibrator.

The constructor defines the calibration coordinate space, generates the calibration target positions, selects the feature columns used for model fitting, and initializes the internal sample list and regression model state.

Parameters:
  • screen_width (float) –

    Width of the calibration coordinate space.

    Target coordinates are centered around zero. For example, if screen_width=1.8, generated x coordinates span approximately -0.9 to +0.9.

  • screen_height (float) –

    Height of the calibration coordinate space.

    Target coordinates are centered around zero. For example, if screen_height=1.8, generated y coordinates span approximately -0.9 to +0.9.

  • num_points (int) –

    Number of calibration target positions to generate.

    If num_points <= 5, the target list is built from the center and four corners.

    If num_points > 5 and random_points=False, target positions are selected from a regular grid.

    If random_points=True, the target list contains the center, four corners, and additional random positions.

  • random_points (bool) –

    If True, generate additional random calibration target positions.

    If False, generate calibration targets from a regular grid when num_points > 5.

  • random_seed (int or None) –

    Seed for NumPy’s random number generator.

    Use a fixed value to make target generation and target order reproducible.

  • feature_columns (list of str) –

    Names of the feature columns used as predictors during calibration model fitting.

    If None, DEFAULT_FEATURE_COLUMNS is used.

  • model_type (str) –

    Default model type used by fit().

    "ridge_poly"

    Ridge regression on polynomial features. Recommended when the number of calibration points is limited.

    "ridge"

    Linear ridge regression.

    "mlp"

    Multi-layer perceptron regression. More flexible, but usually requires more calibration samples.

  • Initialized (Attributes)

  • ----------------------

  • screen_width – Width of the calibration coordinate space.

  • screen_height – Height of the calibration coordinate space.

  • num_points – Number of generated calibration targets.

  • random_points – Whether random target positions are used.

  • random_seed – Random seed used for target generation.

  • rng (numpy.random.Generator) – Random generator used to generate and shuffle target positions.

  • feature_columns – Feature names used as model predictors.

  • target_columns (list of str) – Target coordinate names, initialized as ["target_x", "target_y"].

  • model_type – Default regression model type.

  • positions (list of tuple) – Generated calibration target positions as (x, y) tuples.

  • current_index (int) – Index of the current calibration target. Initialized to -1 because no target is active yet.

  • current_target (dict or None) – Current target dictionary. Initialized as None.

  • current_target_id (int or None) – ID of the current target. Initialized as None.

  • current_target_sample_index (int) – Sample counter within the current target. Initialized as 0.

  • samples (list) – In-memory list of collected calibration samples. Initialized as an empty list.

  • model (sklearn estimator or None) – Fitted calibration model. Initialized as None.

  • target_scaler (sklearn.preprocessing.StandardScaler) – Scaler used internally to standardize target coordinates before model fitting.

  • is_fitted (bool) – Whether the calibration model has been fitted. Initialized as False.

  • fit_info (dict) – Summary dictionary from the most recent model fit. Initialized as an empty dictionary.

Notes

The generated target coordinates use the same coordinate system that should later be used for gaze predictions. For example, if calibration targets are shown in PsychoPy units="norm", predicted gaze coordinates will also be in that same coordinate system.

The constructor only prepares the calibrator. Use next_target() to iterate through calibration positions, add_sample() or add_features() to collect data, and fit() to train the gaze model.

reset_targets(reshuffle=True)[source]

Reset the calibration target sequence.

This method resets the current target state so that calibration can start again from the first target. Optionally, it regenerates and reshuffles the target positions.

Parameters:

reshuffle (bool, default=True) –

If True, regenerate the calibration target positions by calling the internal target-generation method.

If False, keep the existing target positions and only reset the current target index.

Returns:

  • None

  • Attributes Modified

  • ——————-

  • positions (list of tuple) – Regenerated if reshuffle=True.

  • current_index (int) – Reset to -1.

  • current_target (dict or None) – Reset to None.

  • current_target_id (int or None) – Reset to None.

  • current_target_sample_index (int) – Reset to 0.

Notes

This method does not delete collected calibration samples. To remove existing samples, call clear_samples().

next_target()[source]

Advance to the next calibration target.

This method moves the calibrator to the next target position in the current target sequence and stores it as self.current_target. The returned target dictionary can be used to draw the calibration stimulus on screen.

Returns:

  • dict or None – Dictionary describing the next calibration target, or None if all targets have already been completed.

    The dictionary contains:

    target_idint

    Integer identifier of the target within the current sequence.

    target_xfloat

    Horizontal target coordinate.

    target_yfloat

    Vertical target coordinate.

  • Attributes Modified

  • ——————-

  • current_index (int) – Incremented by one.

  • current_target (dict or None) – Set to the new target dictionary, or None when the sequence is finished.

  • current_target_id (int or None) – Set to the current target index, or None when the sequence is finished.

  • current_target_sample_index (int) – Reset to 0 every time a new target is selected.

Notes

Target coordinates are expressed in the coordinate system defined by screen_width and screen_height when the calibrator was initialized.

This method does not draw anything on screen. The user is responsible for presenting the returned target position in the experiment interface.

get_current_target()[source]

Return the current calibration target.

Returns:

Current target dictionary, or None if no target is currently active.

When a target is active, the dictionary contains:

target_idint

Integer identifier of the current target.

target_xfloat

Horizontal target coordinate.

target_yfloat

Vertical target coordinate.

Return type:

dict or None

Notes

This method does not advance the calibration sequence. Use next_target() to move to the next target.

static extract_features_from_result(result)[source]

Extract gaze features from a Meye result.

Expected Meye features:

result.features[“pupil”][“centroid”] = (row, col) result.features[“eye”][“centroid”] = (row, col) result.features[“pupil”][“ellipse”] result.features[“eye”][“ellipse”]

add_sample(result, timestamp=None, extra=None)[source]

Add one calibration sample from a MEYELens result.

This method extracts gaze-calibration features from a MeyeResult and associates them with the current calibration target. The resulting sample is stored in memory in self.samples.

Parameters:
  • result (MeyeResult) –

    MEYELens prediction result from which gaze features are extracted.

    The result is expected to contain pupil and eye features in result.features.

  • timestamp (float or None, default=None) –

    Optional timestamp assigned to the sample.

    If None, the current value of time.perf_counter() is used.

  • extra (dict or None, default=None) –

    Optional additional fields to add to the sample dictionary.

    This can be used to store extra information such as trial number, condition, fixation duration, frame index, or quality flags.

Returns:

Sample dictionary added to self.samples.

The dictionary contains target information, timestamp, extracted gaze features, and any additional fields provided through extra.

Return type:

dict

Raises:

RuntimeError – If no calibration target is currently active.

Notes

Before calling this method, call next_target() to activate a calibration target.

This method is a convenience wrapper around add_features(). It first calls extract_features_from_result() and then stores the resulting feature dictionary with the current target.

add_features(feature_dict, target=None, timestamp=None, extra=None)[source]

Add one calibration sample from an already-extracted feature dictionary.

This method stores one feature dictionary together with a target position. It is useful when MEYELens features have already been extracted, or when calibration samples are being created from previously stored data.

Parameters:
  • feature_dict (dict) –

    Dictionary of gaze features.

    The keys should include the feature names used by self.feature_columns if the sample will later be used for model fitting.

  • target (dict or tuple or list or None, default=None) –

    Target position associated with this sample.

    Supported formats are:

    None

    Use the current target stored in self.current_target.

    (target_x, target_y)

    Manual target position. In this case, target_id and target_sample_index are stored as np.nan.

    dict

    Target dictionary. It must contain "target_x" and "target_y". It may also contain "target_id".

    If the provided target is exactly self.current_target, the internal current_target_sample_index counter is incremented after adding the sample.

  • timestamp (float or None, default=None) –

    Optional timestamp assigned to the sample.

    If None, the current value of time.perf_counter() is used.

  • extra (dict or None, default=None) –

    Optional additional fields to merge into the sample dictionary.

    Values in extra are added after the feature dictionary, so they can be used to attach trial information, frame indices, quality flags, or other experiment-specific variables.

Returns:

Sample dictionary added to self.samples.

The dictionary contains:

time

Sample timestamp.

target_id

Target identifier, if available.

target_sample_index

Index of the sample within the current target, if available.

target_x

Horizontal target coordinate.

target_y

Vertical target coordinate.

plus all fields from feature_dict and extra.

Return type:

dict

Raises:
  • RuntimeError – If target=None and no current target is active.

  • ValueError – If target is not None, a tuple/list, or a dictionary.

Notes

This method does not check whether all features required by self.feature_columns are present. Missing or invalid features are filtered later by prepare_training_data().

Target coordinates should be expressed in the same coordinate system used when the calibrator was initialized.

clear_samples()[source]

Remove all collected calibration samples.

This method clears the in-memory sample list used for model fitting.

Return type:

None

Notes

This method does not reset the calibration target sequence and does not modify the fitted model. To restart the target sequence, use reset_targets().

get_samples()[source]

Return a copy of the collected calibration samples.

Returns:

List containing the currently stored calibration samples.

A new list object is returned, but the sample dictionaries inside the list are not deep-copied.

Return type:

list of dict

Notes

The returned list can be inspected or saved externally by the user.

prepare_training_data(skip_samples=5, aggregate='median', min_pupil_area=None, min_eye_area=None)[source]

Prepare calibration samples for model fitting.

This method converts the in-memory calibration samples stored in self.samples into predictor and target arrays suitable for fitting a gaze calibration model.

It filters out samples that are likely to be unreliable and optionally aggregates valid samples within each calibration target.

Parameters:
  • skip_samples (int or None, default=5) –

    Number of initial samples to discard for each calibration target.

    This is useful because the participant’s eye may still be moving immediately after a new target appears. For example, with skip_samples=5, the first five samples collected after each target onset are excluded.

    If None, no samples are skipped based on target_sample_index.

  • aggregate ({"median", "mean", None}, default="median") –

    How to combine valid samples within each calibration target.

    "median"

    Return one median feature vector and one median target coordinate per target. This is the recommended default because it is robust to occasional noisy samples.

    "mean"

    Return one mean feature vector and one mean target coordinate per target.

    None

    Return all valid samples without target-wise aggregation.

  • min_pupil_area (int or float or None, default=None) –

    Optional minimum pupil area required for a sample to be included.

    Samples with sample["pupil_area"] < min_pupil_area are discarded. If None, no pupil-area threshold is applied.

  • min_eye_area (int or float or None, default=None) –

    Optional minimum eye area required for a sample to be included.

    Samples with sample["eye_area"] < min_eye_area are discarded. If None, no eye-area threshold is applied.

Returns:

  • X (numpy.ndarray) – Predictor matrix with shape (n_samples, n_features).

    Columns correspond to self.feature_columns.

  • y (numpy.ndarray) – Target coordinate matrix with shape (n_samples, 2).

    The two columns are target_x and target_y.

  • valid (list of dict) – List of valid sample entries used to build X and y.

    Each entry contains:

    target_id

    Target identifier.

    X

    Feature vector for one valid sample.

    y

    Target coordinate vector for one valid sample.

    If aggregate is "median" or "mean", this list still contains the valid pre-aggregation samples.

Raises:
  • RuntimeError – If no calibration samples are available.

  • RuntimeError – If no valid samples remain after filtering.

  • ValueError – If aggregate is not "median", "mean", or None.

Notes

A sample is excluded if any feature listed in self.feature_columns is missing, None, or NaN.

A sample is also excluded if target_x or target_y is missing or NaN.

This method does not modify self.samples. Filtering and aggregation are applied only to the returned training arrays.

This method does not perform blink interpolation or signal cleaning. For calibration, unreliable samples should generally be rejected before fitting, for example by using skip_samples, min_pupil_area, and min_eye_area.

fit(model_type=None, degree=2, alpha=1.0, skip_samples=5, aggregate='median', min_pupil_area=None, min_eye_area=None, mlp_hidden_layer_sizes=(32, 16), mlp_max_iter=2000)[source]

Fit the gaze calibration model.

This method prepares the collected calibration samples, fits a regression model that maps MEYE pupil/eye features to target coordinates, stores the fitted model in self.model, and returns a summary of the fitting procedure.

Parameters:
  • model_type ({"ridge_poly", "ridge", "mlp"} or None, default=None) –

    Type of regression model to fit.

    If None, the current value of self.model_type is used.

    "ridge_poly"

    Polynomial feature expansion followed by ridge regression. This is the recommended default when the number of calibration targets is limited.

    "ridge"

    Linear ridge regression.

    "mlp"

    Multi-layer perceptron regression. This can model nonlinear mappings, but usually requires more calibration samples than ridge models.

  • degree (int, default=2) –

    Polynomial degree used when model_type="ridge_poly".

    Ignored when model_type is "ridge" or "mlp".

  • alpha (float, default=1.0) –

    Regularization strength.

    For ridge models, this is the ridge penalty. For the MLP model, this is the L2 penalty passed to MLPRegressor.

  • skip_samples (int or None, default=5) –

    Number of initial samples to discard for each calibration target before fitting.

    Passed to prepare_training_data().

  • aggregate ({"median", "mean", None}, default="median") –

    How to combine valid samples within each calibration target before fitting.

    Passed to prepare_training_data().

  • min_pupil_area (int or float or None, default=None) –

    Optional minimum pupil area required for a sample to be used for fitting.

    Passed to prepare_training_data().

  • min_eye_area (int or float or None, default=None) –

    Optional minimum eye area required for a sample to be used for fitting.

    Passed to prepare_training_data().

  • mlp_hidden_layer_sizes (tuple of int, default=(32, 16)) –

    Hidden-layer sizes used when model_type="mlp".

    Ignored for ridge models.

  • mlp_max_iter (int, default=2000) –

    Maximum number of optimization iterations used when model_type="mlp".

    Ignored for ridge models.

Returns:

  • dict – Fit summary dictionary stored in self.fit_info.

    The dictionary contains:

    model_type

    Fitted model type.

    degree

    Polynomial degree for "ridge_poly", otherwise None.

    alpha

    Regularization strength.

    skip_samples

    Number of initial samples skipped per target.

    aggregate

    Aggregation method used before fitting.

    n_samples

    Number of samples used for fitting after filtering and aggregation.

    n_raw_samples

    Number of raw samples stored in self.samples.

    feature_columns

    Feature columns used as predictors.

    target_columns

    Target coordinate columns.

    mse

    Mean squared error computed on the training data.

    r2

    Coefficient of determination computed on the training data.

  • Attributes Modified

  • ——————-

  • model (sklearn estimator) – Set to the fitted regression pipeline.

  • model_type (str) – Updated to the fitted model type.

  • is_fitted (bool) – Set to True after fitting succeeds.

  • fit_info (dict) – Updated with the returned fit summary.

Raises:
  • RuntimeError – If there are no calibration samples.

  • RuntimeError – If no valid samples remain after filtering.

  • RuntimeError – If fewer than three calibration samples are available after preparation.

  • ValueError – If model_type is not "ridge_poly", "ridge", or "mlp".

Notes

Target coordinates are standardized internally before model fitting using self.target_scaler. Predictions are transformed back to the original target coordinate system.

The reported mse and r2 are computed on the same data used for fitting. They are useful as quick diagnostics, but they should not be interpreted as independent validation performance.

predict_features(features)[source]

Predict gaze coordinates from feature values.

This method applies the fitted calibration model to one or more feature vectors and returns predicted gaze coordinates in the calibration coordinate system.

Parameters:

features (dict or array-like) –

Feature values used for prediction.

If a dictionary is provided, values are extracted in the order defined by self.feature_columns.

If an array is provided, it must contain feature values in the same order as self.feature_columns. A one-dimensional array is interpreted as one sample. A two-dimensional array is interpreted as multiple samples.

Returns:

Predicted gaze coordinates with shape (n_samples, 2).

The two columns correspond to predicted x and y coordinates in the same coordinate system used during calibration.

Return type:

numpy.ndarray

Raises:
  • RuntimeError – If the calibration model has not been fitted yet.

  • RuntimeError – If the input feature array contains NaN values.

Notes

The calibration model must be fitted with fit() before calling this method.

predict_result(result)[source]

Predict gaze coordinates from a MEYE result.

This method extracts gaze-calibration features from a MeyeResult and applies the fitted calibration model.

Parameters:

result (MeyeResult) – MEYE prediction result containing pupil and eye features.

Returns:

Predicted gaze coordinates with shape (1, 2).

The two columns correspond to predicted x and y coordinates in the calibration coordinate system.

Return type:

numpy.ndarray

Raises:
  • RuntimeError – If the calibration model has not been fitted yet.

  • RuntimeError – If the extracted features contain NaN values.

Notes

This is a convenience wrapper around extract_features_from_result() and predict_features().

predict_xy(result)[source]

Predict gaze coordinates as scalar x and y values.

This method predicts gaze position directly from a MeyeResult and returns the first predicted sample as two Python floats.

Parameters:

result (MeyeResult) – MEYELens prediction result containing pupil and eye features.

Returns:

  • x (float) – Predicted horizontal gaze coordinate.

  • y (float) – Predicted vertical gaze coordinate.

Raises:
  • RuntimeError – If the calibration model has not been fitted yet.

  • RuntimeError – If the extracted features contain NaN values.

Notes

This is the most convenient method for live gaze display, because it returns scalar coordinates that can be assigned directly to a visual stimulus position.