Skip to main content

Real-time Screen Gaze

This package is designed to allow users of the Pupil Labs eyetracking hardware, especially Neon, to acquire screen-based gaze coordinates in realtime without relying on Pupil Core software.

This works by identifying the image of the display as it appears in the scene camera. We accomplish this with AprilTags, 2D barcodes similar to QR codes. This package provides a marker_generator module to create AprilTag image data.

from pupil_labs.real_time_screen_gaze import marker_generator
...

marker_pixels = marker_generator.generate_marker(marker_id=0)

More markers will yield higher accuracy, and we recommend a minimum of four. Each marker must be unique, and the marker_id parameter is provided for this purpose.

Once you’ve drawn the markers to the screen using your GUI toolkit of choice, you’ll next need to setup a GazeMapper object. This requires calibration data for the scene camera. For Neon, this is very simple:

from pupil_labs.realtime_api.simple import discover_one_device
from pupil_labs.real_time_screen_gaze.gaze_mapper import GazeMapper
...

device = discover_one_device()
calibration = device.get_calibration()
gaze_mapper = GazeMapper(calibration)

For Pupil Invisible, you’ll need to extract the scene_camera.json file the Time Series Data of a recording which has been been uploaded to Pupil Cloud. This method will also work with Neon recordings in a non-realtime context.

import json
from pupil_labs.real_time_screen_gaze.gaze_mapper import GazeMapper
...

with open("scene_camera.json") as calibration_file:
   calibration_data = json.load(calibration_file)
   if "dist_coefs" in calibration_data:
      calibration_data["distortion_coefficients"] = calibration_data["dist_coefs"]

   calibration = {
      "scene_camera_matrix": [calibration_data["camera_matrix"]],
      "scene_distortion_coefficients": [calibration_data["distortion_coefficients"]],
   }

gaze_mapper = GazeMapper(calibration)

Now that we have a GazeMapper object, we need to specify which AprilTag markers we’re using and where they appear on the screen.

marker_verts = {
   0: [ # marker id 0
      (32, 32), # Top left marker corner
      (96, 32), # Top right
      (96, 96), # Bottom right
      (32, 96), # Bottom left
   ],
   ...
}

screen_size = (1920, 1080)

screen_surface = gaze_mapper.add_surface(
   marker_verts,
   screen_size
)

Here, marker_verts is a dictionary whose keys are the IDs of the markers we’ll be drawing to the screen. The value for each key is a list of the 2D coordinates of the four corners of the marker, starting with the top left and going clockwise.

With that, setup is complete and we’re ready to start mapping gaze to the screen! On each iteration of our main loop we’ll grab a video frame from the scene camera and gaze data from the Realtime API. We pass those along to our GazeMapper instance for processing, and it returns our gaze positions mapped to screen coordinates.

from pupil_labs.realtime_api.simple import discover_one_device
...

device = discover_one_device(max_search_duration_seconds=10)

while True:
   frame, gaze = device.receive_matched_scene_video_frame_and_gaze()
   result = gaze_mapper.process_frame(frame, gaze)

   for surface_gaze in result.mapped_gaze[screen_surface.uid]:
      printf(f"Gaze at {surface_gaze.x}, {surface_gaze.y}")

Metadata

Release files for real-time-screen-gaze 1.1.2

For a detailed explanation of source distributions (sdists) and built distributions (wheels), please see the package formats documentation.

Source distribution (sdist)

Source distribution for real-time-screen-gaze 1.1.2
File Size Uploaded Provenance
real_time_screen_gaze-1.1.2.tar.gz 15.0 kB Without provenance Details

Built distribution (wheel)

Table of built distributions (wheels) for real-time-screen-gaze 1.1.2
File Interpreter ABI Platform
real_time_screen_gaze-1.1.2-py3-none-any.whl Python 3 none any Details

Total release size: 23.8 kB

Release files / real_time_screen_gaze-1.1.2.tar.gz

Download URL real_time_screen_gaze-1.1.2.tar.gz
Size 15.0 kB
Tags Source
SHA-256 checksum
How to use checksums
de409e326de2717d1a759750422697a3e5d186aaec4c8370b670057cb15af517
BLAKE2b-256 checksum
How to use checksums
11dcb7118db9c8c20d9301ab1c5537ad735ea36210b0f03dd047c16e36e8e888
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.9.18

Release files / real_time_screen_gaze-1.1.2-py3-none-any.whl

Download URL real_time_screen_gaze-1.1.2-py3-none-any.whl
Size 8.8 kB
Tags Python 3
SHA-256 checksum
How to use checksums
deab457c2d4e253fecc683a0a9862b819ba583dfeb219f61cf1d88d3fd33e115
BLAKE2b-256 checksum
How to use checksums
2e38c19c2982db1e1f028283dc3b83c886b4ca177b0b48e1f75d131abf0b94f4
Upload date
Uploaded using Trusted Publishing?
What is trusted publishing?
No
Uploaded via twine/6.0.1 CPython/3.9.18

Security for real-time-screen-gaze 1.1.2

Provenance

Provenance describes where a file came from. On PyPI, provenance is shared via attestations, which provide a verifiable record of the build or publishing details. View details, limitations and caveats.

No provenance found

None of the files in this release were uploaded with provenance metadata.

A note on package security

PyPI is a repository for distributing packages, not a service for auditing them. While third-party security researchers and our staff do their best to detect and remove malicious packages, PyPI cannot guarantee the quality, security or suitability of any given package.

To learn more about protecting yourself from malicious actors, visit our package security documentation.

Anthropic, PBC Visionary sponsor Bloomberg Visionary sponsor Hudson River Trading Visionary sponsor Meta Visionary sponsor NVIDIA Visionary sponsor Microsoft Sustainability sponsor Depot Continuous Integration AWS Cloud computing and Security Sponsor Datadog Monitoring Fastly CDN Google Download Analytics Sentry Error logging StatusPage Status page