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:
objectOpen a camera and configure acquisition settings.
- Parameters:
camera_index (int, default=0) – Camera index passed to
cv2.VideoCapture. The default value0usually 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_matrixA 3 x 3 OpenCV camera intrinsic matrix.
distortion_coefficientsOpenCV 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 byget_frame(), provided that valid calibration parameters were loaded fromcalibration_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_WIDTHandcv2.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 inexposure.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.topandleftdefine the upper-left corner of the crop.heightandwidthdefine the crop size.If
None, no crop is applied.
- Raises:
RuntimeError – If the camera cannot be opened with the requested
camera_index.ValueError – If
cropis notNoneand 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:
cv2.VideoCapture(camera_index)set_resolution()set_auto_exposure()set_framerate(), only whenauto_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 byget_frame()can be undistorted using OpenCV.The file must contain the following top-level TOML keys:
camera_matrixA 3 x 3 OpenCV intrinsic camera matrix.
distortion_coefficientsOpenCV 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
Noneif loading fails.dist_coeffs (numpy.ndarray or None) – Set to the loaded distortion coefficients if loading succeeds. Set to
Noneif 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 usingcv2.flip(frame, 0).apply_crop (bool, default=True) – If
Trueandself.cropis notNone, return only the selected crop region.
- Returns:
The acquired frame as an OpenCV image array, or
Noneif frame acquisition failed.- Return type:
numpy.ndarray or None
Notes
If
self.undistort=Trueand 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):
oincreases the exposure value by 1;pdecreases the exposure value by 1;ESCcloses 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.cropas:(top, left, height, width)The selected crop is then automatically applied by
get_frame()whenapply_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.cropin 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:
objectContainer for the output of a MEYELens prediction.
A
MeyeResultobject is returned byMeye.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
uint8NumPy arrays with the same height and width as the input frame. Mask pixels are encoded as:0for background;255for 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 byMeyeMaskFeatures.compute_mask.Each feature dictionary may include:
validareacentroidellipse
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:
objectExtract geometric features from MEYELens binary masks.
MeyeMaskFeaturesis a stateless helper class used to compute simple geometric measurements from segmentation masks, usually the"pupil"and"eye"masks returned byMeye.predict().The class is intentionally separate from
Meye: theMeyeclass handles neural-network inference, thresholding, morphology, and preview logic, whileMeyeMaskFeatureshandles 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
Trueif the mask contains at least one positive pixel.Falseif 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
rowcorresponds to the vertical image coordinate andcolcorresponds 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=Falseand all numeric values areNaN.
Ellipse Features
The
ellipsedictionary contains:- validbool
Trueif an ellipse was successfully fitted.Falseotherwise.- 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_diameterValues close to
0indicate 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
0indicate a nearly circular ellipse. Values closer to1indicate a more elongated ellipse.- major_axisdict
Endpoints of the major axis. Contains:
p1First endpoint as
(row, col).p2Second endpoint as
(row, col).
- minor_axisdict
Endpoints of the minor axis. Contains:
p1First endpoint as
(row, col).p2Second 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=Truewhileellipse["valid"]isFalse.- 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, andellipsefields.- Return type:
dict
Notes
If the mask is empty,
validisFalse,areais0,centroidis(np.nan, np.nan), andellipseis 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:
objectInitialize 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
Meyeinstances 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.tomlIf 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
0for"cuda:0".- str
Any valid PyTorch device string, for example
"cuda:0".
If CUDA or MPS is requested but unavailable,
Meyeprints 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 asNone.
- 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
timmfor 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
MeyeResultobject.- 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 withoverlay(), 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
Camerainstance 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
qorESC.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
Meyesettings, including thresholds, morphology, connected-component filtering, hole filling, feature computation, and overlay options.If
cam.get_frame()returnsNone, the method prints a warning and continues the preview loop.
- 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:
objectInitialize 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
Noneif 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
Camerainstance 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 as20260603_121530-subject01.txt.path_to_file (pathlib.Path) –
Directory where the recording file will be saved.
If
None, the default output directory is:~/Documents/meyeDATAThe 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, includeinference_msandinference_fpscolumns 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 whenstop()orclose_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
Noneand created bystart().time_start (float or None) – Reference timestamp for the recording clock. Initialized as
Noneand set bystart().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 setsself.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_featuresisFalse, 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, callclose_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 useclose_all().
- close_all()[source]
Stop recording and release all recorder resources.
This convenience method calls
stop()and thenclose(). 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 throughclose().
- 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, runsMeye.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
Noneif 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 returnsNone.The method records three timestamps, all relative to the time when
start()was called:t_callTime when
save_frame()was called.t_frameTime immediately after camera frame acquisition.
t_predTime immediately after MEYELens prediction.
If frame acquisition fails and
cam.get_frame()returnsNone, no row is written and the method returnsNone.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()andclose_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. Unlikesave_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
Noneif 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.frameandself.resultwith 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 bysave_frame()orget_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
Noneif 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, andt_predare set tomath.nanbecause no new acquisition or prediction is performed.The returned
frame_indexcorresponds to the last saved frame when used aftersave_frame(). If no frame has been saved yet, it returns0.
- 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
qorESC.- 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.camand the same MEYELens model stored inself.meye.Any threshold or preview setting changed during the interactive preview is handled by
Meye.preview(). In the standardMeyeimplementation, 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:
objectInitialize 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.9to+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.9to+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 > 5andrandom_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 whennum_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_COLUMNSis 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
-1because 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()oradd_features()to collect data, andfit()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
Noneif all targets have already been completed.The dictionary contains:
target_idintInteger identifier of the target within the current sequence.
target_xfloatHorizontal target coordinate.
target_yfloatVertical target coordinate.
Attributes Modified
——————-
current_index (int) – Incremented by one.
current_target (dict or None) – Set to the new target dictionary, or
Nonewhen the sequence is finished.current_target_id (int or None) – Set to the current target index, or
Nonewhen the sequence is finished.current_target_sample_index (int) – Reset to
0every time a new target is selected.
Notes
Target coordinates are expressed in the coordinate system defined by
screen_widthandscreen_heightwhen 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
Noneif no target is currently active.When a target is active, the dictionary contains:
target_idintInteger identifier of the current target.
target_xfloatHorizontal target coordinate.
target_yfloatVertical 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
MeyeResultand associates them with the current calibration target. The resulting sample is stored in memory inself.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 oftime.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 callsextract_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_columnsif 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:
NoneUse the current target stored in
self.current_target.(target_x, target_y)Manual target position. In this case,
target_idandtarget_sample_indexare stored asnp.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 internalcurrent_target_sample_indexcounter is incremented after adding the sample.timestamp (float or None, default=None) –
Optional timestamp assigned to the sample.
If
None, the current value oftime.perf_counter()is used.extra (dict or None, default=None) –
Optional additional fields to merge into the sample dictionary.
Values in
extraare 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:
timeSample timestamp.
target_idTarget identifier, if available.
target_sample_indexIndex of the sample within the current target, if available.
target_xHorizontal target coordinate.
target_yVertical target coordinate.
plus all fields from
feature_dictandextra.- Return type:
dict
- Raises:
RuntimeError – If
target=Noneand no current target is active.ValueError – If
targetis notNone, a tuple/list, or a dictionary.
Notes
This method does not check whether all features required by
self.feature_columnsare present. Missing or invalid features are filtered later byprepare_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.samplesinto 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 ontarget_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.
NoneReturn 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_areaare discarded. IfNone, 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_areaare discarded. IfNone, 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_xandtarget_y.valid (list of dict) – List of valid sample entries used to build
Xandy.Each entry contains:
target_idTarget identifier.
XFeature vector for one valid sample.
yTarget coordinate vector for one valid sample.
If
aggregateis"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
aggregateis not"median","mean", orNone.
Notes
A sample is excluded if any feature listed in
self.feature_columnsis missing,None, orNaN.A sample is also excluded if
target_xortarget_yis missing orNaN.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, andmin_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 ofself.model_typeis 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_typeis"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_typeFitted model type.
degreePolynomial degree for
"ridge_poly", otherwiseNone.alphaRegularization strength.
skip_samplesNumber of initial samples skipped per target.
aggregateAggregation method used before fitting.
n_samplesNumber of samples used for fitting after filtering and aggregation.
n_raw_samplesNumber of raw samples stored in
self.samples.feature_columnsFeature columns used as predictors.
target_columnsTarget coordinate columns.
mseMean squared error computed on the training data.
r2Coefficient 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
Trueafter 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_typeis 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
mseandr2are 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
xandycoordinates 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
NaNvalues.
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
MeyeResultand 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
xandycoordinates 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
NaNvalues.
Notes
This is a convenience wrapper around
extract_features_from_result()andpredict_features().
- predict_xy(result)[source]
Predict gaze coordinates as scalar x and y values.
This method predicts gaze position directly from a
MeyeResultand 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
NaNvalues.
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.