pyETA
  • Documentaion (pyETA)
  • Getting Started
    • Installation
    • Launching the Application
    • Development
  • Description
    • Methodology
    • Stream Generation
    • Plots
    • Validation
  • Other Resources
Powered by GitBook

Quicklinks

  • Developed by, Binay Pradhan
  • Github
  • Assets/Releases
On this page
  • Stream Generation
  • Stream Properties
  • Stream reading for plotting
  1. Description

Stream Generation

PreviousMethodologyNextPlots

Last updated 2 months ago

The pyETA GUI initiates a 22-channel (LSL) stream named 'tobii_gaze_fixation' for real-time eye-tracking analysis. This stream supports gaze tracking and fixation detection, with data sourced from either a Tobii eye tracker or a .


Stream Generation

  • Script: track.py

  • Class: Tracker

    • In application.py, the start_stream method creates a StreamThread thread with user-defined parameters and starts it:

      self.stream_thread = StreamThread()
      self.stream_thread.set_variables(tracker_params=tracker_params)
      self.stream_thread.start()
    • StreamThread spawns a TrackerThread, which instantiates and runs a Tracker object from track.py.

  • Stream Creation: When push_stream=True (set via GUI checkbox), Tracker creates an LSL stream or when --push_stream flag is passed in CLI pyeta track --push_stream

  • Channel modification: Combines raw, filtered, and metadata into a 22-channel array.

    • Applies OneEuroFilter to raw gaze coordinates.

    • Computes velocity and fixation status using velocity_threshold.

    • Produces left_filtered_gaze_x, left_filtered_gaze_y, right_filtered_gaze_x and right_filtered_gaze_y used for fixation detection.

OneEuroFilter Algorithm

This algorithm reduces noise and jitters in raw gaze data while preserving responsiveness, which is later used for fixation detection.,

  • Steps:

    1. Derivative: Calculates rate of change:

      current_derivative = (current_value - self.previous_value) / time_elapsed
    2. Derivative Smoothing: Applies fixed cutoff (1.0 Hz):

      alpha_derivative = self.smoothing_factor(time_elapsed, self.derivative_cutoff)
      filtered_derivative = self.exp_smoothing(alpha_derivative, current_derivative, self.previous_derivative)
    3. Adaptive Cutoff: Adjusts based on velocity:

      adaptive_cutoff = self.min_cutoff + self.beta * abs(filtered_derivative)
    4. Value Smoothing: Applies exponential smoothing:

      alpha = self.smoothing_factor(time_elapsed, adaptive_cutoff)
      filtered_value = self.exp_smoothing(alpha, current_value, self.previous_value)

Stream Properties

  • LSL stream Name: 'tobii_gaze_fixation'

  • Channels: 22

Channel Structure of the stream is described below:

Channel Name
Type
Unit
Description

Left Eye

1

left_gaze_x

gaze

normalized

Raw X gaze position (0-1)

2

left_gaze_y

gaze

normalized

Raw Y gaze position (0-1)

3

left_pupil_diameter

pupil

mm

Pupil diameter

4

left_fixated

fixation

boolean

Fixation status (True/False)

5

left_velocity

velocity

px

Gaze velocity

6

left_fixation_timestamp

timestamp

s

Time of fixation start

7

left_fixation_elapsed

duration

s

Fixation duration

8

left_filtered_gaze_x

filtered_gaze

normalized

Smoothed X gaze position

9

left_filtered_gaze_y

filtered_gaze

normalized

Smoothed Y gaze position

Right Eye

10

right_gaze_x

gaze

normalized

Raw X gaze position (0-1)

11

right_gaze_y

gaze

normalized

Raw Y gaze position (0-1)

12

right_pupil_diameter

pupil

mm

Pupil diameter

13

right_fixated

fixation

boolean

Fixation status (True/False)

14

right_velocity

velocity

px

Gaze velocity

15

right_fixation_timestamp

timestamp

s

Time of fixation start

16

right_fixation_elapsed

duration

s

Fixation duration

17

right_filtered_gaze_x

filtered_gaze

normalized

Smoothed X gaze position

18

right_filtered_gaze_y

filtered_gaze

normalized

Smoothed Y gaze position

Screen Data

19

screen_width

screen

px

Screen width

20

screen_height

screen

px

Screen height

21

timestamp

timestamp

s

Data timestamp

22

local_clock

timestamp

s

Local system clock


Stream reading for plotting

  • Script: reader.py

  • Class: StreamThread

  • Resolves and connects to 'tobii_gaze_fixation'

  • Continuously pulls samples

  • Upon requests, gaze data is being parsed.

# For gaze data
StreamThread.get_data()

# For fixation data
StreamThread.get_data(fixation=True)
Lab Streaming Layer
mock service