EyeTrax

repository·master·Indexed 43 days ago

https://github.com/ck-zhang/eyetrax

A Python library for webcam-based eye tracking that enables developers to extract facial features, train gaze models, and predict gaze coordinates. It includes the GazeEstimator class, various calibration workflows (9-point, 5-point, dense grid, and Lissajous), and smoothing filters such as Kalman, KalmanEMA, and KDE. The library also provides CLI tools like eyetrax-demo for on-screen overlays and eyetrax-virtualcam for streaming gaze data to virtual webcams.

Tokens
6.2K
Snippets
21
Records
24
Agent score
55%

What's inside EyeTrax

  1. Install EyeTrax

    master

    You can install EyeTrax via PyPI or from source.

    From PyPI:

    pip install eyetrax

    From source:

    git clone https://github.com/ck-zhang/eyetrax && cd eyetrax
    
    # For an editable install, pick one:
    python -m pip install -e .
    # OR
    pip install uv && uv sync
    pip install eyetrax
  2. Implement a custom gaze model by subclassing BaseModel

    master

    To create a custom gaze-prediction model in EyeTrax, you must subclass BaseModel and implement three internal methods. BaseModel handles feature scaling (using StandardScaler) and provides high-level train, predict, save, and load methods.

    When implementing your subclass, you must provide implementations for:

    • _init_native(**kwargs): Initialize your model's internal state.
    • _native_train(X: np.ndarray, y: np.ndarray): The core training logic using scaled features.
    • _native_predict(X: np.ndarray) -> np.ndarray: The core prediction logic using scaled features.

    Note that the public train and predict methods automatically apply feature scaling before calling your native implementations.

    import numpy as np
    from eyetrax.models.base import BaseModel
    
    class MyCustomModel(BaseModel):
        def _init_native(self, **kwargs):
            # Initialize your specific model here
            pass
    
        def _native_train(self, X: np.ndarray, y: np.ndarray):
            # Implement training logic using scaled X
            pass
    
        def _native_predict(self, X: np.ndarray) -> np.ndarray:
            # Implement prediction logic using scaled X
            return np.zeros((len(X), 2))
    
    # Usage
    model = MyCustomModel()
    model.train(X_train, y_train)
    predictions = model.predict(X_test)
  3. Use GazeEstimator in Python

    master

    The GazeEstimator class is the core interface for eye tracking. You can use it to extract facial features, perform calibration, save/load models, and predict gaze coordinates from video frames.

    Workflow:

    1. Initialize GazeEstimator.
    2. Calibrate using a routine like run_9_point_calibration(estimator).
    3. (Optional) Save the model using estimator.save_model(path).
    4. In a loop, capture frames and use estimator.extract_features(frame) to get features and blink status.
    5. Use estimator.predict([features]) to get screen coordinates.

    Example:

    from eyetrax import GazeEstimator, run_9_point_calibration
    import cv2
    
    # Create estimator and calibrate
    estimator = GazeEstimator()
    run_9_point_calibration(estimator)
    
    # Save model
    estimator.save_model("gaze_model.pkl")
    
    # Load model
    estimator = GazeEstimator()
    estimator.load_model("gaze_model.pkl")
    
    cap = cv2.VideoCapture(0)
    
    while True:
        # Extract features from frame
        ret, frame = cap.read()
        features, blink = estimator.extract_features(frame)
    
        # Predict screen coordinates
        if features is not None and not blink:
            x, y = estimator.predict([features])[0]
            print(f"Gaze: ({x:.0f}, {y:.0f})")
    from eyetrax import GazeEstimator, run_9_point_calibration
    import cv2
    
    estimator = GazeEstimator()
    run_9_point_calibration(estimator)
    
    # ... later in a loop ...
    features, blink = estimator.extract_features(frame)
    if features is not None and not blink:
        x, y = estimator.predict([features])[0]
  4. Configure KalmanEMASmoother smoothing strength with ema_alpha

    master

    The ema_alpha parameter in KalmanEMASmoother controls the strength of the Exponential Moving Average applied after the Kalman filter step.

    • Value 0.0: EMA is disabled; the smoother returns pure Kalman filter output.
    • Value closer to 1.0: Increases smoothing strength, which reduces jitter but introduces more lag (latency).
    • Constraint: Must be a float in the range [0.0, 1.0]. Passing a value outside this range raises a ValueError.
  5. Use the eyetrax-virtualcam CLI

    master

    The eyetrax-virtualcam command streams the gaze overlay to a virtual webcam, which can be integrated into streaming software like OBS.

    Available Flags:

    • --filter: Smoothing filter. Options: kalman, kalman_ema, kde, none (default: none).
    • --ema-alpha: (Only for kalman_ema) EMA smoothing strength (0–1, default: 0.25).
    • --camera: Physical webcam index (default: 0).
    • --calibration: Calibration routine. Options: 9p, 5p, lissajous, dense (default: 9p).
    • --grid-rows: (Only for dense calibration) Number of rows (default: 5).
    • --grid-cols: (Only for dense calibration) Number of columns (default: 5).
    • --grid-margin: (Only for dense calibration) Margin ratio from edges (default: 0.10).
    • --confidence: (Only for kde) Contour probability (0–1, default: 0.5).

    Example:

    eyetrax-virtualcam --filter kde --calibration 5p
    eyetrax-virtualcam --filter kde --calibration 5p
  6. Use the eyetrax-demo CLI

    master

    The eyetrax-demo command runs an on-screen gaze overlay demo. It supports various smoothing filters and calibration routines via command-line flags.

    Available Flags:

    • --filter: Smoothing filter. Options: kalman, kalman_ema, kde, none (default: none).
    • --ema-alpha: (Only for kalman_ema) EMA smoothing strength (0–1, default: 0.25).
    • --camera: Physical webcam index (default: 0).
    • --calibration: Calibration routine. Options: 9p, 5p, lissajous, dense (default: 9p).
    • --grid-rows: (Only for dense calibration) Number of rows (default: 5).
    • --grid-cols: (Only for dense calibration) Number of columns (default: 5).
    • --grid-margin: (Only for dense calibration) Margin ratio from edges (default: 0.10).
    • --background: (Demo only) Path to a background image.
    • --confidence: (Only for kde) Contour probability (0–1, default: 0.5).

    Examples:

    # Run with Kalman filtering
    eyetrax-demo --filter kalman
    
    # Run with Kalman + EMA smoothing (tuned strength)
    eyetrax-demo --filter kalman_ema --ema-alpha 0.5
    
    # Run with dense grid calibration for higher spatial coverage
    eyetrax-demo --calibration dense --grid-rows 7 --grid-cols 7
    eyetrax-demo --filter kalman
  7. Compute grid points for calibration

    master

    Use the following utility functions to calculate the spatial coordinates for calibration points:

    • compute_grid_points(...): Computes specific grid points.
    • compute_grid_points_from_shape(...): Computes grid points based on a provided shape.

    These are useful if you need to manually define or manipulate the points used during a calibration sequence.

  8. Run eye tracking calibration workflows

    master

    The eyetrax.calibration module provides several high-level functions to execute different calibration routines. Use these functions to map eye gaze coordinates to screen coordinates based on the desired calibration pattern:

    • run_9_point_calibration(): Performs a standard 9-point calibration.
    • run_5_point_calibration(): Performs a faster 5-point calibration.
    • run_dense_grid_calibration(): Performs a calibration using a dense grid for higher spatial coverage.
    • run_lissajous_calibration(): Performs a calibration using a Lissajous curve pattern.
    from eyetrax.calibration import run_9_point_calibration
    
    # Execute the 9-point calibration routine
    run_9_point_calibration()
  9. Create a Kalman Filter with make_kalman()

    master

    Use make_kalman() to generate a pre-configured cv2.KalmanFilter instance. This is useful if you want to bypass the eyetrax smoother classes and interact directly with OpenCV's Kalman implementation. The function sets up a constant velocity model by default.

    import numpy as np
    from eyetrax.filters import make_kalman
    
    # Create a Kalman filter with custom noise parameters
    kf = make_kalman(
        state_dim=4,
        meas_dim=2,
        dt=1.0,
        process_var=50.0,
        measurement_var=0.2,
        init_state=np.array([0, 0, 0, 0])
    )
  10. Use KalmanEMASmoother for hybrid Kalman + EMA smoothing

    master

    The KalmanEMASmoother class provides a hybrid smoothing approach by applying Exponential Moving Average (EMA) on top of a Kalman filter's output. This is useful for reducing jitter in eye-tracking data at the cost of increased latency.

    To use it, initialize the class with an ema_alpha parameter. The step(x, y) method processes new coordinates and returns the smoothed integer coordinates.

    from eyetrax.filters.kalman_ema import KalmanEMASmoother
    
    # Initialize with ema_alpha
    # 0.0: EMA disabled (pure Kalman)
    # Closer to 1.0: Stronger smoothing / more lag
    smoother = KalmanEMASmoother(ema_alpha=0.25)
    
    # Process new coordinates
    smoothed_x, smoothed_y = smoother.step(x, y)
  11. Instantiate a model using create_model()

    master

    The create_model function is the primary factory for creating gaze model instances. It automatically performs model discovery if no models are currently registered. You provide the registered name of the model as the first argument, followed by any keyword arguments (**kwargs) required by that model's constructor.

    from eyetrax.models import create_model
    
    # Assuming 'some_model' is a registered model name
    model = create_model("some_model", param1=value1, param2=value2)