Demonstration
Picture Free-viewing Task
In the previous section, we gained a preliminary understanding of the basic workflow of Pupilio. Now, we can implement a simple picture free-view task. This demonstration will guide you through the main usage of Pupilio.
PyGame implementation:
#!/usr/bin/env python
# Copyright (c) 2024, Hangzhou Deep Gaze Science and Technology Co., Ltd
# All Rights Reserved
#
# For use by Hangzhou Deep Gaze Science and Technology Co., Ltd customers
# only. Redistribution and use in source and binary forms, with or without
# modification, are NOT permitted.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the distribution.
#
# Neither name of Hangzhou Deep Gaze Sci & Tech Ltd nor the name of
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# DESCRIPTION:
# This is a demo showing how to use deep gaze pythonic library
# In this script, we connect to the tracker, perform a calibration,
# validate the calibration results, then we subscribe to the sample data
# stream, with which we constantly update the position of a gaze cursor
# Author: Gancheng Zhu
# Last updated: 10/28/2024 by ZW
# Load libraries
import os
import time
import pygame
from pygame.locals import *
from pupilio import Pupilio
# use the Pygame library for graphics, first init pygame and open a full screen window
pygame.init()
scn_width, scn_height = (1920, 1080)
win = pygame.display.set_mode((scn_width, scn_height), FULLSCREEN|HWSURFACE)
# instantiate a tracker object
pupil_io = Pupilio()
# create a task session, and set a session name
# The session name must contain only letters, digits or underscores without any special characters.
pupil_io.create_session(session_name="deepgaze_demo")
# set 'validate' to True if you would like to verify the calibration results
pupil_io.calibration_draw(validate=True, hands_free=False, screen=win)
# start retrieving gaze
pupil_io.start_sampling()
pygame.time.wait(100) # sleep for 100 ms so the tracker cache some sample
# A free viewing task, in which we show a picture and overlay the gaze cursor
img_folder = 'images'
images = ['gray_grid.jpg', 'west_lake.jpg', 'old_town.jpg']
# show the images one by one in a loop, press a ENTER key to exit the program
for _img in images:
# show the image on screen
win.fill((128, 128, 128))
im = pygame.image.load(os.path.join(img_folder, _img))
win.blit(im, (0, 0))
pygame.display.flip()
# send a trigger to record in the eye movement data to mark picture onset
pupil_io.set_trigger(202)
# now lets show the gaze point, press any key to close the window
got_key = False
max_duration = 10000
t_start = pygame.time.get_ticks()
pygame.event.clear() # clear all cached events if there were any
gx, gy = -65536, -65536
while not (got_key or (pygame.time.get_ticks() - t_start)>=max_duration):
# get the newest gaze position
left, right, bino = pupil_io.get_current_gaze()
status, gx, gy = bino
gx = int(gx)
gy = int(gy)
# check key presses
for ev in pygame.event.get():
if ev.type == KEYDOWN:
if ev.key == K_RETURN:
got_key = True
# if ev.key == K_SPACE:
# update the visual (image and cursor)
win.blit(im, (0,0))
pygame.draw.circle(win, (0, 255, 0), (gx, gy), 50, 5) # cursor for the left eye
pygame.display.flip()
# stop sampling
pygame.time.wait(100) # sleep for 100 ms to capture ending samples
pupil_io.stop_sampling()
# save the sample data to file
data_dir = "./data"
if not os.path.exists(data_dir):
os.makedirs(data_dir)
file_name = "deepgaze_demo.csv"
pupil_io.save_data(os.path.join(data_dir, file_name))
# release the tracker instance
pupil_io.release()
# quit pygame
pygame.quit()
PsychoPy implementation:
#!/usr/bin/env python
# Copyright (c) 2024, Hangzhou Deep Gaze Science and Technology Co., Ltd
# All Rights Reserved
#
# For use by Hangzhou Deep Gaze Science and Technology Co., Ltd customers
# only. Redistribution and use in source and binary forms, with or without
# modification, are NOT permitted.
#
# Redistributions in binary form must reproduce the above copyright
# notice, this list of conditions and the following disclaimer in
# the documentation and/or other materials provided with the distribution.
#
# Neither name of Hangzhou Deep Gaze Sci & Tech Ltd nor the name of
# contributors may be used to endorse or promote products derived from
# this software without specific prior written permission.
#
# THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS ``AS
# IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
# TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
# PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR
# CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
# EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
# PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
# PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
# LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
# NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
# SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
#
# DESCRIPTION:
# This is a demo showing how to use deep gaze pythonic library
# In this script, we connect to the tracker, perform a calibration,
# validate the calibration results, then we subscribe to the sample data
# stream, with which we constantly update the position of a gaze cursor
# Author: Gancheng Zhu
# Last updated: 10/28/2024 by ZW
# Load libraries
import os
from psychopy import visual, core, event
from pupilio import Pupilio
# use the Psychopy library for graphics, first open a full screen window
scn_width, scn_height = (1920, 1080)
win = visual.Window((scn_width, scn_height), fullscr=True, units='pix')
# instantiate a tracker object
pupil_io = Pupilio()
# create a task session, and set a session name
# The session name must contain only letters,
# digits or underscores without any special characters.
pupil_io.create_session(session_name="deepgaze_demo")
# set 'validate' to True if you would like to verify the calibration results
pupil_io.calibration_draw(screen=win, validate=True, hands_free=False)
# start retrieving gaze
pupil_io.start_sampling()
core.wait(0.1) # sleep for 100 ms so the tracker cache some sample
# A free viewing task, in which we show a picture and overlay the gaze cursor
img_folder = 'images'
images = ['gray_grid.jpg', 'west_lake.jpg', 'old_town.jpg']
# show the images one by one in a loop, press a ENTER key to exit the program
for _img in images:
# show the image on screen
im = visual.ImageStim(win, os.path.join(img_folder, _img))
im.draw()
win.flip()
# send a trigger to record in the eye movement data to mark picture onset
pupil_io.set_trigger(202)
# now lets show the gaze point, press any key to close the window
got_key = False
max_duration = 10
t_start = core.getTime()
event.clearEvents() # clear all cached events if there were any
gx, gy = -65536, -65536
while not (got_key or (core.getTime() - t_start)>=max_duration):
# get the newest gaze position
left, right, bino = pupil_io.get_current_gaze()
status, gx, gy = bino
# convert to psychopy coordinates, screen center = (0,0)
gx = gx -960
gy = 540 - gy
# check keyboard events
if event.getKeys():
got_key = True
# redraw the screen
win.color =(0,0,0)
im.draw()
gaze_cursor = visual.Circle(win, 50, pos=(gx, gy), lineColor=(-1, 1, -1), lineWidth=5, fillColor=None)
gaze_cursor.draw()
win.flip()
# stop sampling
core.wait(0.1) # sleep for 100 ms to capture ending samples
pupil_io.stop_sampling()
# save the sample data to file
data_dir = "./data"
if not os.path.exists(data_dir):
os.makedirs(data_dir)
file_name = "deepgaze_demo.csv"
pupil_io.save_data(os.path.join(data_dir, file_name))
# release the tracker instance
pupil_io.release()
# quit pygame
core.quit()