Esempio n. 1
0
	def __init__(self, display):

		"""Initiates an eyetracker dummy object, that simulates gaze position using the mouse
		
		arguments
		display		--	a pygaze display.Display instance
		
		keyword arguments
		None
		"""

		# try to copy docstrings (but ignore it if it fails, as we do
		# not need it for actual functioning of the code)
		try:
			copy_docstr(BaseEyeTracker, Dummy)
		except:
			# we're not even going to show a warning, since the copied
			# docstring is useful for code editors; these load the docs
			# in a non-verbose manner, so warning messages would be lost
			pass

		self.recording = False
		self.blinking = False
		self.bbpos = (settings.DISPSIZE[0]/2, settings.DISPSIZE[1]/2)
		self.resolution = settings.DISPSIZE[:]
		self.simulator = Mouse(disptype=settings.DISPTYPE, mousebuttonlist=None,
			timeout=2, visible=False)
		self.kb = Keyboard(disptype=settings.DISPTYPE, keylist=None,
			timeout=None)
		self.angrybeep = Sound(osc='saw',freq=100, length=100, attack=0,
			decay=0, soundfile=None)
		self.display = display
		self.screen = Screen(disptype=settings.DISPTYPE, mousevisible=False)
Esempio n. 2
0
    def __init__(self, display):
        """Initiates a 'dumb dummy' object, that doesn't do a thing
		
		arguments
		display		--	a pygaze display.Display instance
		
		keyword arguments
		None
		"""

        # try to copy docstrings (but ignore it if it fails, as we do
        # not need it for actual functioning of the code)
        try:
            copy_docsafe_decode(BaseEyeTracker, DumbDummy)
        except:
            # we're not even going to show a warning, since the copied
            # docstring is useful for code editors; these load the docs
            # in a non-verbose manner, so warning messages would be lost
            pass

        self.recording = False
        self.blinking = False
        self.bbpos = (settings.DISPSIZE[0] / 2, settings.DISPSIZE[1] / 2)

        self.display = display
        self.screen = Screen(disptype=settings.DISPTYPE, mousevisible=False)
Esempio n. 3
0
    def confirm_abort_experiment(self):
        """
		Asks for confirmation before aborting the experiment. Displays a
		confirmation screen, collects the response, and acts accordingly.

		Exceptions:
		Raises a response_error upon confirmation.

		Returns:
		False if no confirmation was given.
		"""

        # Display the confirmation screen
        scr = Screen(disptype=DISPTYPE)
        kb = Keyboard(timeout=5000)
        yc = DISPSIZE[1] / 2
        xc = DISPSIZE[0] / 2
        ld = 40  # Line height
        scr.draw_text(u'Really abort experiment?', pos=(xc, yc - 3 * ld))
        scr.draw_text(u'Press \'Y\' to abort', pos=(xc, yc - 0.5 * ld))
        scr.draw_text(u'Press any other key or wait 5s to go to setup', \
         pos=(xc, yc+0.5*ld))
        self.display.fill(scr)
        self.display.show()
        # process the response:
        try:
            key, time = kb.get_key()
        except:
            return False
        # if confirmation, close experiment
        if key == u'y':
            raise Exception(u'The experiment was aborted')
        self.eyelink_graphics.esc_pressed = False
        return False
    multicast_ip = 0
    _print("No multicast IP found.")

# GENERAL
# Total number of points.
total = 0.0

# Create a colour wheel to select colours from for the stimuli.
cw = create_colourwheel(STIML, STIMR, savefile='colourwheel.png')

# PYGAZE
# Initialise a new Display instance
disp = Display()

# Initialise a Screen instance for arbitrary drawing.
scr = Screen()
scr.draw_text(text="Initialising the experiment...", fontsize=FONTSIZE)
disp.fill(scr)
disp.show()

# Initialise the ka-ching sound.
kaching = Sound(soundfile=KACHING)

# Initialise a Keyboard and a Mouse instance for participant interaction.
kb = Keyboard()
mouse = Mouse()

# COMMUNICATIONS
timer.pause(5000)
_print("Initialising Client.")
# Initialise a new Client instance.
mouse = Mouse(mousebuttonlist=None, timeout=None)

# Initialise a log.
log = Logfile()
header = ['trialnr', 'nstim', 'fixonset', 'stimonset', 'maintenanceonset', \
    'probeonset', 'RT', 'response']
for i in range(max(NSTIM)):
    header.extend(['stimx%d' % (i), 'stimy%d' % (i), 'stimori%d' % (i), \
        'stimerror%d' % (i)])
header.extend(['E', 'X', 'T'])
for i in range(max(NSTIM)-1):
    header.append('NT%d' % i)
log.write(header)

# Initialise a blank Screen for ad-hoc drawing.
scr = Screen()

# Initialise a blank Screen.
blankscr = Screen()

# Initialise a fixation Screen.
fixscr = Screen()
fixscr.draw_fixation(fixtype=FIXTYPE, diameter=FIXSIZE, pw=FIXPW)

# Initialise stimulus and probe Screens.
stimscr = {}
probescr = {}
for nstim in NSTIM:
    locs = nstim * [DISPCENTRE]
    oris = nstim * [0]
    stimscr[nstim] = StimScreen(nstim, locs, oris, \
Esempio n. 6
0
    def __init__(self, display, logfile=settings.LOGFILE, \
        alea_key=settings.ALEAKEY, \
        animated_calibration=settings.ALEAANIMATEDCALIBRATION, \
        eventdetection=settings.EVENTDETECTION, \
        saccade_velocity_threshold=35, \
        saccade_acceleration_threshold=9500, \
        blink_threshold=settings.BLINKTHRESH, \
        **args):
        """Initializes the AleaTracker object
        
        arguments
        display    -- a pygaze.display.Display instance
        
        keyword arguments
        logfile    -- logfile name (string value); note that this is the
                   name for the eye data log file (default = LOGFILE)
        """

        # try to copy docstrings (but ignore it if it fails, as we do
        # not need it for actual functioning of the code)
        try:
            copy_docstr(BaseEyeTracker, AleaTracker)
        except:
            # we're not even going to show a warning, since the copied
            # docstring is useful for code editors; these load the docs
            # in a non-verbose manner, so warning messages would be lost
            pass

        # object properties
        self.disp = display
        self.screen = Screen()
        self.dispsize = self.disp.dispsize  # display size in pixels
        self.screensize = settings.SCREENSIZE  # display size in cm
        self.kb = Keyboard(keylist=['space', 'escape', 'q'], timeout=1)
        self.errorbeep = Sound(osc='saw', freq=100, length=100)

        # show a message
        self.screen.clear()
        self.screen.draw_text(
            text="Initialising the eye tracker, please wait...", fontsize=20)
        self.disp.fill(self.screen)
        self.disp.show()

        # output file properties
        self.outputfile = logfile + '.tsv'

        # calibration properties
        self.animated_calibration = animated_calibration == True

        # eye tracker properties
        self.connected = False
        self.recording = False
        self.errdist = 2  # degrees; maximal error for drift correction
        self.pxerrdist = 30  # initial error in pixels
        self.maxtries = 100  # number of samples obtained before giving up (for obtaining accuracy and tracker distance information, as well as starting or stopping recording)
        self.prevsample = (-1, -1)
        self.prevps = -1

        # event detection properties
        self.fixtresh = 1.5  # degrees; maximal distance from fixation start (if gaze wanders beyond this, fixation has stopped)
        self.fixtimetresh = 100  # milliseconds; amount of time gaze has to linger within self.fixtresh to be marked as a fixation
        self.spdtresh = saccade_velocity_threshold  # degrees per second; saccade velocity threshold
        self.accthresh = saccade_acceleration_threshold  # degrees per second**2; saccade acceleration threshold
        self.blinkthresh = blink_threshold  # milliseconds; blink detection threshold used in PyGaze method
        self.eventdetection = eventdetection
        self.set_detection_type(self.eventdetection)
        self.weightdist = 10  # weighted distance, used for determining whether a movement is due to measurement error (1 is ok, higher is more conservative and will result in only larger saccades to be detected)

        # connect to the tracker
        self.alea = OGAleaTracker(alea_key, file_path=self.outputfile)

        # get info on the sample rate
        # TODO: Compute after streaming some samples?
        self.samplerate = 60.0
        self.sampletime = 1000.0 / self.samplerate

        # initiation report
        self.log("pygaze initiation report start")
        self.log("display resolution: {}x{}".format( \
            self.dispsize[0], self.dispsize[1]))
        self.log("display size in cm: {}x{}".format( \
            self.screensize[0], self.screensize[1]))
        self.log("samplerate: {} Hz".format(self.samplerate))
        self.log("sampletime: {} ms".format(self.sampletime))
        self.log("fixation threshold: {} degrees".format(self.fixtresh))
        self.log("speed threshold: {} degrees/second".format(self.spdtresh))
        self.log("acceleration threshold: {} degrees/second**2".format( \
            self.accthresh))
        self.log("pygaze initiation report end")
Esempio n. 7
0
from pygaze.display import Display
import pygaze.libtime as timer
from pygaze.screen import Screen
from constants import *

fixscreen = Screen()
fixscreen.draw_fixation(fixtype='dot')

disp = Display()
timer.pause(2000)
disp.close()
Esempio n. 8
0
kb = Keyboard()

# Initialise the EyeTracker and let it know which Display instance to use by
# passing it to the EyeTracker.
tracker = EyeTracker(disp)

# Create a Logfile instance that keeps track of when videos start.
log = Logfile()
# Write a header to the log file.
log.write(['date', 'time', 'trialnr', 'video', 'timestamp'])

# # # # #
# SCREENS

# Create a screen to show instructions on.
textscr = Screen()
textscr.draw_text("Press any key to start the next video.", fontsize=24)

# Create a screen to show images on. This will be the screen that we will use
# to display each video frame.
stimscr = Screen()

# # # # #
# PLAY VIDEOS

# Calibrate the eye tracker.
tracker.calibrate()

# Randomise the list of videos. Remove this line if you want the videos to be
# displayed in alphabetical order.
random.shuffle(VIDEOS)
Esempio n. 9
0
	def __init__(self, libeyelink, tracker):

		"""
		Constructor.

		Arguments:
		libeyelink	--	A libeyelink object.
		tracker		--	An tracker object as returned by pylink.EyeLink().
		"""

		pylink.EyeLinkCustomDisplay.__init__(self)

		# objects
		self.libeyelink = libeyelink
		self.display = libeyelink.display
		self.screen = Screen(disptype=DISPTYPE, mousevisible=False)
		self.kb = Keyboard(keylist=None, timeout=0)
		self.mouse = Mouse(timeout=0)
		if DISPTYPE == 'pygame':
			self.kb.set_timeout(timeout=0.001)
		# If we are using a DISPTYPE that cannot be used directly, we have to
		# save the camera image to a temporary file on each frame.
		#if DISPTYPE not in ('pygame', 'psychopy'):
		import tempfile
		import os
		self.tmp_file = os.path.join(tempfile.gettempdir(), '__eyelink__.jpg')
		# drawing properties
		self.xc = self.display.dispsize[0]/2
		self.yc = self.display.dispsize[1]/2
		self.extra_info = True
		self.ld = 40 # line distance
		self.fontsize = libeyelink.fontsize
		self.title = ""
		self.display_open = True
		# menu
		self.menuscreen = Screen(disptype=DISPTYPE, mousevisible=False)		
		self.menuscreen.draw_text(text="Eyelink calibration menu",
			pos=(self.xc,self.yc-6*self.ld), center=True, font='mono',
			fontsize=int(2*self.fontsize), antialias=True)
		self.menuscreen.draw_text(text="%s (pygaze %s, pylink %s)" \
			% (libeyelink.eyelink_model, pygaze.version, pylink.__version__),
			pos=(self.xc,self.yc-5*self.ld), center=True,
			font='mono', fontsize=int(.8*self.fontsize), antialias=True)
		self.menuscreen.draw_text(text="Press C to calibrate", 
			pos=(self.xc, self.yc-3*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)
		self.menuscreen.draw_text(text="Press V to validate",
			pos=(self.xc, self.yc-2*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)
		self.menuscreen.draw_text(text="Press A to auto-threshold",
			pos=(self.xc,self.yc-1*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)
		self.menuscreen.draw_text(text="Press I to toggle extra info in camera image",
			pos=(self.xc,self.yc-0*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)
		self.menuscreen.draw_text(text="Press Enter to show camera image",
			pos=(self.xc,self.yc+1*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)
		self.menuscreen.draw_text(
			text="(then change between images using the arrow keys)",
			pos=(self.xc, self.yc+2*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)
		self.menuscreen.draw_text(text="Press Escape to abort experiment",
			pos=(self.xc, self.yc+4*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)			
		self.menuscreen.draw_text(text="Press Q to exit menu",
			pos=(self.xc, self.yc+5*self.ld), center=True, font='mono',
			fontsize=self.fontsize, antialias=True)
		# beeps
		self.__target_beep__ = Sound(osc='sine', freq=440, length=50, 
			attack=0, decay=0, soundfile=None)
		self.__target_beep__done__ = Sound(osc='sine', freq=880, length=200,
			attack=0, decay=0, soundfile=None)
		self.__target_beep__error__ = Sound(osc='sine', freq=220, length=200,
			attack=0, decay=0, soundfile=None)
		# Colors
		self.color = {
			pylink.CR_HAIR_COLOR:			pygame.Color('white'),
			pylink.PUPIL_HAIR_COLOR:		pygame.Color('white'),
			pylink.PUPIL_BOX_COLOR:			pygame.Color('green'),
			pylink.SEARCH_LIMIT_BOX_COLOR:	pygame.Color('red'),
			pylink.MOUSE_CURSOR_COLOR:		pygame.Color('red'),	
			'font':							pygame.Color('white'),		
			}
		# Font
		pygame.font.init()
		self.font = pygame.font.SysFont('Courier New', 11)
		# further properties
		self.state = None
		self.pal = None
		
		self.size = (0,0)
		self.set_tracker(tracker)
		self.last_mouse_state = -1
		self.bit64 = '64bit' in platform.architecture()
		self.imagebuffer = self.new_array()		
Esempio n. 10
0
# -*- coding: utf-8 -*-
"""
Created on Thu Nov 10 13:29:48 2016

@author: adam
"""

from pygaze.display import Display
from pygaze.screen import Screen
import pygaze.libtime as timer

# disp = Window(size=DISPSIZE, units='pix', fullscr=True)
disp = Display()
fixscreen = Screen()
fixscreen.draw_fixation(fixtype='dot')

imgscreen = Screen()
imgscreen.draw_image('/home/adam/Desktop/experiment0/Example.png')

disp.fill(fixscreen)
disp.show()
timer.pause(1000)

disp.fill(imgscreen)
disp.show()
timer.pause(2000)

disp.close()
Esempio n. 11
0
from pygaze.logfile import Logfile
from pygaze.eyetracker import EyeTracker
import pygaze.libtime as timer

from libmeg import *

#%%

# # # # #
# INITIALISE

# Initialise a new Display instance.
disp = Display()

# Present a start-up screen.
scr = Screen()
scr.draw_text("Loading, please wait...", fontsize=MAIN_FONTSIZE)
disp.fill(scr)
disp.show()



# Open a new log file.
log = Logfile(filename = LOGFILE)
log_det = Logfile(filename = DETAILED_LOGFILE)
log_events = Logfile(filename = EVENT_LOGFILE)
# TODO: Write header.
log.write(["trialnr","left_ang","right_ang", "cue_dir", "targ", "targ_ang", "resp_ang", "perc_diff", "resp_onset", "resp_duration", "iti", "iti_onset", "stim_onset","delay_onset", "cue_onset", "postcue_onset","probe_onset", "prac"])
log_det.write(["trialnr", "timestamp", "angle", "event", "targ_ang", "cue_dir"])
log_events.write(["Trigger", "Timestamp"])
# Initialise the eye tracker.
Esempio n. 12
0
kb = Keyboard()
# Após kb - Criando o logfile para armazenar e salvar os dados coletados
log = Logfile()

# Tela de instruções do experimento


instructions = 'Seja bem vindo(a)!\n' \
               'Neste experimento as letras F e J apareceraão em ambos os lados da tela.\n' \
               'Se você ver a letra F, então pressione a tecla F.\n' \
               'Se você ver a letra J, então pressione a tecla J.\n' \
               'Tente ser tão rápido e preciso quanto possível durante os ensaios.\n\n' \
                'Aperte a barra de espaço do teclado para começar.\n\n' \
               'Boa sorte!'

instscr = Screen()
instscr.draw_text(text=instructions, fontsize=22)

# Criando a tela de fixação

fixscr = Screen()
fixscr.draw_fixation(fixtype='cross', diameter=15)

# draw the left box
fixscr.draw_rect(x=BOXCORS['left'][0],
                 y=BOXCORS['left'][1],
                 w=BOXSIZE,
                 h=BOXSIZE,
                 pw=3,
                 fill=False)
# draw the right box
cy = yax / 2
cx = xax / 2

### Set size of game matrix relative to screen with 'margin'.
margin = 0.7
side = yax * margin
t_side = side / p1
tloc = t_side / p1

owncol = (255, 255, 255)
othercol = (255, 255, 255)

disp = Display(dispsize=DISPSIZE, screennr=2)
mse = Mouse(visible=False, timeout=10)

gamescreen = Screen(dispsize=DISPSIZE)

#tracker = EyeTracker(disp)

fixscr = Screen(dispsize=DISPSIZE)
fixscr.draw_fixation(fixtype='cross', diameter=8)

introscreen = Screen(dispsize=DISPSIZE)
introscreen.draw_text("Welcome to the experiment", fontsize=30)
introscreen.draw_text("\n\n\n (To proceed, press any key)", fontsize=25)

istrscreen = Screen(dispsize=DISPSIZE)
istrscreen.draw_text(
    "In this experiment, you will \n play a sequence of games \n like the one displayed on the right",
    fontsize=30)
istrscreen.draw_text("You", fontsize=25)
Esempio n. 14
0
    def __init__(self, nstim, locs, oris, linewidth=3, \
        stimtypes='gabor', showcolourwheel=False):
        """Initialises a new StimScreen instance.
        
        Arguments
        
        nstim        -      Integer that determines the number of stimuli on
                            this screen.
        
        locs         -      List of (x,y) tuples that determine the positions
                            of all stimuli. The list's length should be equal
                            to the number of stimuli as defined by nstim.
        
        oris         -      List of integers that determine the orientations
                            of all stimuli. The list's length should be equal
                            to the number of stimuli as defined by nstim.
        
        Keyword Arguments
        
        linewidth    -      Integer or a list of integers that determines the
                            width of the lines around stimuli (in pixels).
                            Default value is 3.
        
        stimtypes    -      String or a list of strings that determines the
                            type of stimulus. Options are 'gabor' and 'noise'.
                            Default is 'gabor'.
        
        showcolourwheel-    Boolean that determines whether a central colour
                            wheel should be drawn of not. Default is False.
        """

        # Settings from the constants.
        self._sf = float(STIMSF) / float(STIMSIZE)
        self._alpha = STIMALPHA
        self._contrast = STIMCONTRAST

        # Noise texture.
        self._noisetex = numpy.random.rand(STIMNOISERES, STIMNOISERES)

        # Convert the linewidth to a list (if necessary).
        if type(linewidth) in [int, float]:
            linewidth = nstim * [int(linewidth)]

        # Convert the stimulus types to a list (if necessary).
        if type(stimtypes) in [str, unicode]:
            stimtypes = nstim * [stimtypes]

        # Create a Screen to use its wonderful drawing functions.
        self.scr = Screen()

        # Draw the fixation cross.
        self.scr.draw_fixation(fixtype=FIXTYPE, diameter=FIXSIZE)

        # Draw the colouw wheel
        if showcolourwheel:
            # Load the image.
            self.scr.draw_image(CWIMG, scale=CWIMGSCALE)

        # Create an internal list of stimuli (=PsychoPy stimulus instances) by
        # copying it from the internal screen.
        self.screen = self.scr.screen

        # Keep a list of the index numbers of all stimuli. The indices refer
        # to positions within the self.scr.screen list of PsychoPy stimuli.
        self._stimindexnrs = []
        self._outlineindexnrs = []
        # Draw the stimuli.
        for i in range(nstim):
            # Add the stimulus' index number to the list of indices.
            self._stimindexnrs.append(len(self.screen))
            #            # Create a new Rect stimulus instance.
            #            stim = Rect(pygaze.expdisplay, \
            #                pos=pos2psychopos(locs[i]), \
            #                fillColor=rgb2psychorgb(list(oris[i])), \
            #                lineColor=rgb2psychorgb(list(linecols[i])), \
            #                lineWidth=linewidth[i], \
            #                width=STIMSIZE, \
            #                height=STIMSIZE)
            # Create a Gabor-ish GratingStim.
            if stimtypes[i] == 'gabor':
                tex = 'sin'
            else:
                tex = self._noisetex
            stim = GratingStim(pygaze.expdisplay, \
                pos=pos2psychopos(locs[i]), \
                ori=oris[i], \
                size=STIMSIZE, \
                sf=self._sf, \
                opacity=self._alpha, \
                contrast=self._contrast, \
                tex=tex, \
                mask='circle', \
                color=(1,1,1)
                )
            # Add the new stimulus to our list of stimuli.
            self.screen.append(stim)

            # Add an outline for the stimulus.
            self._outlineindexnrs.append(len(self.screen))
            stim = Circle(pygaze.expdisplay, \
                pos=pos2psychopos(locs[i]), \
                lineWidth=linewidth[i], \
                radius=STIMSIZE//2, \
                edges=32, \
                closeShape=False, \
                fillColor=None, \
                lineColor=(0,0,0)
                )
            # Add the new stimulus to our list of stimuli.
            self.screen.append(stim)
Esempio n. 15
0
kb = Keyboard()

# Create a new Logfile instance.
log = Logfile()
log.write(["trialnr", "trial_type", "stimulus", \
    "fix_onset", "stim_onset", "response", "RT", \
    "correct"])

# Create a BAD sound.
bad_sound = Sound(osc="whitenoise", length=200)
bad_sound.set_volume(1)
good_sound = Sound(osc="sine", freq=440, length=200)
good_sound.set_volume(0.5)

# Create a new Screen instance.
scr = Screen()
scr.draw_text("Welcome!", fontsize=100, \
    colour=(255,100,100))

# Pass the screen to the display.
disp.fill(scr)
disp.show()
timer.pause(3000)

# Create a list of all trials.
trials = []
# Add all the words.
for word in WORDS:
    t = {}
    t["type"] = "word"
    t["stimulus"] = word
Esempio n. 16
0
	def __init__(self, display, logfile=LOGFILE, eventdetection=EVENTDETECTION, \
		saccade_velocity_threshold=35, saccade_acceleration_threshold=9500, \
		**args):

		"""Initializes the EyeTribeTracker object
		
		arguments
		display	-- a pygaze.display.Display instance
		
		keyword arguments
		logfile	-- logfile name (string value); note that this is the
				   name for the eye data log file (default = LOGFILE)
		"""

		# try to copy docstrings (but ignore it if it fails, as we do
		# not need it for actual functioning of the code)
		try:
			copy_docstr(BaseEyeTracker, EyeTribeTracker)
		except:
			# we're not even going to show a warning, since the copied
			# docstring is useful for code editors; these load the docs
			# in a non-verbose manner, so warning messages would be lost
			pass

		# object properties
		self.disp = display
		self.screen = Screen()
		self.dispsize = DISPSIZE # display size in pixels
		self.screensize = SCREENSIZE # display size in cm
		self.kb = Keyboard(keylist=['space', 'escape', 'q'], timeout=1)
		self.errorbeep = Sound(osc='saw',freq=100, length=100)
		
		# output file properties
		self.outputfile = logfile
		
		# eye tracker properties
		self.connected = False
		self.recording = False
		self.errdist = 2 # degrees; maximal error for drift correction
		self.pxerrdist = 30 # initial error in pixels
		self.maxtries = 100 # number of samples obtained before giving up (for obtaining accuracy and tracker distance information, as well as starting or stopping recording)
		self.prevsample = (-1,-1)
		self.prevps = -1
		
		# event detection properties
		self.fixtresh = 1.5 # degrees; maximal distance from fixation start (if gaze wanders beyond this, fixation has stopped)
		self.fixtimetresh = 100 # milliseconds; amount of time gaze has to linger within self.fixtresh to be marked as a fixation
		self.spdtresh = saccade_velocity_threshold # degrees per second; saccade velocity threshold
		self.accthresh = saccade_acceleration_threshold # degrees per second**2; saccade acceleration threshold
		self.eventdetection = eventdetection
		self.set_detection_type(self.eventdetection)
		self.weightdist = 10 # weighted distance, used for determining whether a movement is due to measurement error (1 is ok, higher is more conservative and will result in only larger saccades to be detected)

		# connect to the tracker
		self.eyetribe = EyeTribe(logfilename=logfile)

		# get info on the sample rate
		self.samplerate = self.eyetribe._samplefreq
		self.sampletime = 1000.0 * self.eyetribe._intsampletime

		# initiation report
		self.log("pygaze initiation report start")
		self.log("display resolution: %sx%s" % (self.dispsize[0],self.dispsize[1]))
		self.log("display size in cm: %sx%s" % (self.screensize[0],self.screensize[1]))
		self.log("samplerate: %.2f Hz" % self.samplerate)
		self.log("sampletime: %.2f ms" % self.sampletime)
		self.log("fixation threshold: %s degrees" % self.fixtresh)
		self.log("speed threshold: %s degrees/second" % self.spdtresh)
		self.log("acceleration threshold: %s degrees/second**2" % self.accthresh)
		self.log("pygaze initiation report end")
Esempio n. 17
0
    def draw_menu_screen(self):
        """
		desc:
			Draws the menu screen.
		"""

        self.menuscreen = Screen(disptype=settings.DISPTYPE,
                                 mousevisible=False)
        self.menuscreen.draw_text(text="Eyelink calibration menu",
                                  pos=(self.xc, self.yc - 6 * self.ld),
                                  center=True,
                                  font='mono',
                                  fontsize=int(2 * self.fontsize),
                                  antialias=True)
        self.menuscreen.draw_text(text="%s (pygaze %s, pylink %s)" \
         % (self.libeyelink.eyelink_model, pygaze.version,
         pylink.__version__), pos=(self.xc,self.yc-5*self.ld), center=True,
         font='mono', fontsize=int(.8*self.fontsize), antialias=True)
        self.menuscreen.draw_text(text="Press C to calibrate",
                                  pos=(self.xc, self.yc - 3 * self.ld),
                                  center=True,
                                  font='mono',
                                  fontsize=self.fontsize,
                                  antialias=True)
        self.menuscreen.draw_text(text="Press V to validate",
                                  pos=(self.xc, self.yc - 2 * self.ld),
                                  center=True,
                                  font='mono',
                                  fontsize=self.fontsize,
                                  antialias=True)
        self.menuscreen.draw_text(text="Press A to auto-threshold",
                                  pos=(self.xc, self.yc - 1 * self.ld),
                                  center=True,
                                  font='mono',
                                  fontsize=self.fontsize,
                                  antialias=True)
        self.menuscreen.draw_text(
            text="Press I to toggle extra info in camera image",
            pos=(self.xc, self.yc - 0 * self.ld),
            center=True,
            font='mono',
            fontsize=self.fontsize,
            antialias=True)
        self.menuscreen.draw_text(text="Press Enter to show camera image",
                                  pos=(self.xc, self.yc + 1 * self.ld),
                                  center=True,
                                  font='mono',
                                  fontsize=self.fontsize,
                                  antialias=True)
        self.menuscreen.draw_text(
            text="(then change between images using the arrow keys)",
            pos=(self.xc, self.yc + 2 * self.ld),
            center=True,
            font='mono',
            fontsize=self.fontsize,
            antialias=True)
        self.menuscreen.draw_text(text="Press Escape to abort experiment",
                                  pos=(self.xc, self.yc + 4 * self.ld),
                                  center=True,
                                  font='mono',
                                  fontsize=self.fontsize,
                                  antialias=True)
        self.menuscreen.draw_text(text="Press Q to exit menu",
                                  pos=(self.xc, self.yc + 5 * self.ld),
                                  center=True,
                                  font='mono',
                                  fontsize=self.fontsize,
                                  antialias=True)
Esempio n. 18
0
    def __init__(self, display,
        logfile=settings.LOGFILE, \
        eventdetection=settings.EVENTDETECTION, \
        saccade_velocity_threshold=35, \
        saccade_acceleration_threshold=9500, \
        blink_threshold=settings.BLINKTHRESH, \
        **args):

        # try to copy docstrings (but ignore it if it fails, as we do
        # not need it for actual functioning of the code)
        try:
            copy_docstr(BaseEyeTracker, EyeLogicTracker)
        except:
            # we're not even going to show a warning, since the copied
            # docstring is useful for code editors; these load the docs
            # in a non-verbose manner, so warning messages would be lost
            pass

        self.disp = display
        self.screen = Screen()
        self.dispsize = self.disp.dispsize # display size in pixels
        self.screensize = settings.SCREENSIZE # display size in cm
        self.kb = Keyboard(keylist=['space', 'escape', 'q'], timeout=1)
        self.errorbeep = Sound(osc='saw', freq=100, length=100)

        # show a message
        self.screen.clear()
        self.screen.draw_text(
            text="Initialising the eye tracker, please wait...",
            fontsize=20)
        self.disp.fill(self.screen)
        self.disp.show()

        # output file properties
        self.logfile = logfile

        # eye tracker properties
        self._recording = Event()
        self._recording.clear()
        self._calibrated = Event()
        self._calibrated.clear()
        self.eye_used = 2 # 0=left, 1=right, 2=binocular
        self.sampleLock = Lock()
        self.lastSample = None
        self.maxtries = 100 # number of samples obtained before giving up (for obtaining accuracy and tracker distance information, as well as starting or stopping recording)

        # event detection properties
        self.pxfixtresh = 50;
        self.fixtresh = 1.5 # degrees; maximal distance from fixation start (if gaze wanders beyond this, fixation has stopped)
        self.fixtimetresh = 100 # milliseconds; amount of time gaze has to linger within self.fixtresh to be marked as a fixation

        self.spdtresh = saccade_velocity_threshold # degrees per second; saccade velocity threshold
        self.accthresh = saccade_acceleration_threshold # degrees per second**2; saccade acceleration threshold
        self.blinkthresh = blink_threshold # milliseconds; blink detection threshold used in PyGaze method
        self.eventdetection = eventdetection

        self._log_vars = [ \
            "timestampMicroSec", \
            "index", \
            "porFilteredX", \
            "porFilteredY", \
            "porLeftX", \
            "porLeftY", \
            "pupilRadiusLeft", \
            "porRightX", \
            "porRightY", \
            "pupilRadiusRight", \
            ]
        # Open a new log file.
        dir_name = os.path.dirname(logfile)
        file_name = os.path.basename(logfile)
        name, ext = os.path.splitext(file_name)
        self._data_file_path = os.path.join(dir_name, name+".eyelogic.csv")
        self._log_file = open(self._data_file_path, "w")
        # Write a header to the log.
        header = ["TYPE"]
        header.extend(self._log_vars)
        self._sep = ";"
        self._log_file.write("Sep="+self._sep+"\n")
        self._log_file.write(self._sep.join(map(str, header)))
        # Create a lock to prevent simultaneous access to the log file.
        self._logging_queue = Queue()
        self._logging_queue_empty = Event()
        self._logging_queue_empty.set()
        self._connected = Event()
        self._connected.set()
        self._log_counter = 0
        self._log_consolidation_freq = 60
        
        self._logging_thread = Thread( target=self.loggingThread, \
                name='PyGaze_EyeLogic_Logging', args=[])

        global g_api
        g_api = self

        # log
        self.log("pygaze initiation")
        #self.log("experiment = {}".format(self.description))
        #self.log("participant = {}".format(self.participant))
        self.log("display resolution = {}x{}".format(self.dispsize[0], \
            self.dispsize[1]))
        self.log("display size in cm = {}x{}".format(self.screensize[0], \
            self.screensize[1]))
        self.log("fixation threshold = {} degrees".format(self.fixtresh))
        self.log("speed threshold = {} degrees/second".format(self.spdtresh))
        self.log("acceleration threshold = {} degrees/second**2".format( \
            self.accthresh))

        # connect
        self.api = ELApi( "PyGaze" )
        self.api.registerGazeSampleCallback( gazeSampleCallback )
        self.api.registerEventCallback( eventCallback )

        resultConnect = self.api.connect()
        if (resultConnect != ELApi.ReturnConnect.SUCCESS):
            self._connected.clear()
            raise Exception("Cannot connect to EyeLogic server = {}".format(errorstringConnect(resultConnect)))
        self._connected.set()

        screenConfig = self.api.getScreenConfig()
        self.log("eye tracker is mounted on screen {}".format(screenConfig.id))
        self.rawResolution = (screenConfig.resolutionX, screenConfig.resolutionY)
        self.log("raw screen resolution = {}x{}".format(
            self.rawResolution[0], self.rawResolution[1]))
        self.log("end pygaze initiation")

        deviceConfig = self.api.getDeviceConfig()
        if (deviceConfig.deviceSerial == 0):
            raise Exception("no eye tracking device connected")
        if (len(deviceConfig.frameRates) == 0):
            raise Exception("failed to read out device configuration")
        g_api.sampleRate = deviceConfig.frameRates[0]
        g_api.sampleTime = 1000.0 / g_api.sampleRate
        g_api.log("samplerate = {} Hz".format(g_api.sampleRate))
        g_api.log("sampletime = {} ms".format(g_api.sampleTime))
        self._logging_thread.start()

        self.screen.clear()
        self.disp.fill(self.screen)
        self.disp.show()
Esempio n. 19
0
    def __init__(self, libeyelink, tracker):
        """
		Constructor.

		Arguments:
		libeyelink	--	A libeyelink object.
		tracker		--	An tracker object as returned by pylink.EyeLink().
		"""

        pylink.EyeLinkCustomDisplay.__init__(self)

        # objects
        self.libeyelink = libeyelink
        self.display = libeyelink.display
        self.screen = Screen(disptype=settings.DISPTYPE, mousevisible=False)
        self.kb = Keyboard(keylist=None, timeout=0)
        self.mouse = Mouse(timeout=0)
        if settings.DISPTYPE == 'pygame':
            self.kb.set_timeout(timeout=0.001)
        # If we are using a DISPTYPE that cannot be used directly, we have to
        # save the camera image to a temporary file on each frame.
        #if DISPTYPE not in ('pygame', 'psychopy'):
        import tempfile
        import os
        self.tmp_file = os.path.join(tempfile.gettempdir(), '__eyelink__.jpg')
        # drawing properties
        self.xc = self.display.dispsize[0] / 2
        self.yc = self.display.dispsize[1] / 2
        self.extra_info = True
        self.ld = 40  # line distance
        self.fontsize = libeyelink.fontsize
        self.title = ""
        self.display_open = True
        self.draw_menu_screen()
        # beeps
        self.__target_beep__ = Sound(osc='sine',
                                     freq=440,
                                     length=50,
                                     attack=0,
                                     decay=0,
                                     soundfile=None)
        self.__target_beep__done__ = Sound(osc='sine',
                                           freq=880,
                                           length=200,
                                           attack=0,
                                           decay=0,
                                           soundfile=None)
        self.__target_beep__error__ = Sound(osc='sine',
                                            freq=220,
                                            length=200,
                                            attack=0,
                                            decay=0,
                                            soundfile=None)
        # Colors
        self.color = {
            pylink.CR_HAIR_COLOR: pygame.Color('white'),
            pylink.PUPIL_HAIR_COLOR: pygame.Color('white'),
            pylink.PUPIL_BOX_COLOR: pygame.Color('green'),
            pylink.SEARCH_LIMIT_BOX_COLOR: pygame.Color('red'),
            pylink.MOUSE_CURSOR_COLOR: pygame.Color('red'),
            'font': pygame.Color('white'),
        }
        # Font
        pygame.font.init()
        self.font = pygame.font.SysFont('Courier New', 11)
        # further properties
        self.state = None
        self.pal = None

        self.size = (0, 0)
        self.set_tracker(tracker)
        self.last_mouse_state = -1
        self.bit64 = '64bit' in platform.architecture()
        self.imagebuffer = self.new_array()
Esempio n. 20
0
from pygaze.logfile import Logfile
from pygaze.eyetracker import EyeTracker
import pygaze.libtime as timer

from scansync.mri import MRITriggerBox


##############
# INITIALISE #
##############

# Initialise a new Display instance.
disp = Display()

# Present a start-up screen.
scr = Screen()
scr.draw_text("Loading, please wait...", fontsize=24)
disp.fill(scr)
disp.show()

# Open a new log file.
log = Logfile()
# TODO: Write header.
log.write(["trialnr", "block", "run","stim", "keypress", "go_nogo", "face_onset", "signal_onset","resp_onset", "RT", "accuracy", "respmap", "block_type"])

# Open a new log file to log events.
event_log = Logfile(filename=EVENT_LOG)
event_log.write(["time", "event"])

# Initialise the eye tracker.
tracker = EyeTracker(disp)
Esempio n. 21
0
import numpy
from psychopy.visual import GratingStim

# Initialize a new Display instance (specifications are in
# constants.py).
disp = Display()

# Create a new GratingStim. The sinusoidal texture and the
# Gaussian mask will make it into a Gabor. The spatial
# frequency of 0.05 cycles per pixel will make it have
# 1 cycle every 20 pixels.
gabor = GratingStim(pygaze.expdisplay, tex='sin', mask='gauss', \
    sf=0.05, size=200)

# Initialize a new Screen instance for the Gabor.
gaborscreen = Screen()
# Add the GratingStim to the gaborscreen's screen property
# (a list of all PsychoPy stimuli in the screen).
gaborscreen.screen.append(gabor)

# Create random numbers between 0 and 1 (numpy.random.rand),
# converted to numbers between 0 and 2 (*2), and
# then converted to numbers between -1 and 1 (-1). The size
# must be a power of 2!
noise = (numpy.random.rand(64, 64) * 2) - 1

# Create a new GratingStim. Using the noise array as
# texture will result in visual snow. The mask is Gaussian
# (to match the Gabor).
noisepatch = GratingStim(pygaze.expdisplay, tex=noise, \
    mask='gauss', size=200)
Esempio n. 22
0
	# set up function argument types and return type
	XInputSetState = xinput.XInputSetState
	XInputSetState.argtypes = [ctypes.c_uint, ctypes.POINTER(XINPUT_VIBRATION)]
	XInputSetState.restype = ctypes.c_uint
	# define helper function
	def set_vibration(controller, left_motor, right_motor):
	    vibration = XINPUT_VIBRATION(int(left_motor * 65535), int(right_motor * 65535))
	    XInputSetState(controller, ctypes.byref(vibration))


# # # # #
# PYGAZE INSTANCES

# visual
disp = Display()
scr = Screen()
# input
js = Joystick()


# # # # #
# RUN

# run until a minute has passed
t0 = timer.get_time()
t1 = timer.get_time()
text = "Test the joystick!"
while t1 - t0 < 60000:
	# get joystick input
	event, value, t1 = js.get_joyinput(timeout=10)
	# update text
Esempio n. 23
0
    t = threading.Thread(target=run_server)
    t.daemon = True

    eye_lock = threading.Lock()
    eye_event = threading.Event()
    eye_thread = threading.Thread(name='eye_tracking',
                                  target=eye_tracker,
                                  args=(
                                      eye_lock,
                                      eye_event,
                                  ))
    eye_thread.daemon = True

    disp = Display(disptype='psychopy')
    scr = Screen(disptype='psychopy')
    disp.close()
    tracker = EyeTracker(disp, trackertype='eyetribe')

    EYE_DATA = Queue.Queue(500)

    try:
        t.start()

        eye_thread.start()

        with Listener(on_click=on_click) as listener:
            listener.join()

        # listener.start()
Esempio n. 24
0
    def __init__(self,
                 display,
                 ip='127.0.0.1',
                 sendport=4444,
                 receiveport=5555,
                 logfile=settings.LOGFILE,
                 eventdetection=settings.EVENTDETECTION,
                 saccade_velocity_threshold=35,
                 saccade_acceleration_threshold=9500,
                 **args):
        """Initializes the SMItracker object
		
		arguments
		display	-- a pygaze.display.Display instance
		
		keyword arguments
		ip		-- internal ip address for iViewX (default = 
				   '127.0.0.1')
		sendport	-- port number for iViewX sending (default = 4444)
		receiveport	-- port number for iViewX receiving (default = 5555)
		logfile	-- logfile name (string value); note that this is the
				   name for the SMI logfile, NOT the .idf file
				   (default = LOGFILE)
		"""

        # try to copy docstrings (but ignore it if it fails, as we do
        # not need it for actual functioning of the code)
        try:
            copy_docstr(BaseEyeTracker, SMITracker)
        except:
            # we're not even going to show a warning, since the copied
            # docstring is useful for code editors; these load the docs
            # in a non-verbose manner, so warning messages would be lost
            pass

        # object properties
        self.disp = display
        self.screen = Screen()
        self.dispsize = settings.DISPSIZE  # display size in pixels
        self.screensize = settings.SCREENSIZE  # display size in cm
        self.kb = Keyboard(keylist=['space', 'escape', 'q'], timeout=1)
        self.errorbeep = Sound(osc='saw', freq=100, length=100)

        # output file properties
        self.outputfile = logfile
        self.description = "experiment"  # TODO: EXPERIMENT NAME
        self.participant = "participant"  # TODO: PP NAME

        # eye tracker properties
        self.connected = False
        self.recording = False
        self.eye_used = 0  # 0=left, 1=right, 2=binocular
        self.left_eye = 0
        self.right_eye = 1
        self.binocular = 2
        self.errdist = 2  # degrees; maximal error for drift correction
        self.maxtries = 100  # number of samples obtained before giving up (for obtaining accuracy and tracker distance information, as well as starting or stopping recording)
        self.prevsample = (-1, -1)
        self.prevps = -1

        # event detection properties
        self.fixtresh = 1.5  # degrees; maximal distance from fixation start (if gaze wanders beyond this, fixation has stopped)
        self.fixtimetresh = 100  # milliseconds; amount of time gaze has to linger within self.fixtresh to be marked as a fixation
        self.spdtresh = saccade_velocity_threshold  # degrees per second; saccade velocity threshold
        self.accthresh = saccade_acceleration_threshold  # degrees per second**2; saccade acceleration threshold
        self.eventdetection = eventdetection
        self.set_detection_type(self.eventdetection)
        self.weightdist = 10  # weighted distance, used for determining whether a movement is due to measurement error (1 is ok, higher is more conservative and will result in only larger saccades to be detected)

        # set logger
        res = iViewXAPI.iV_SetLogger(c_int(1),
                                     c_char_p(logfile + '_SMILOG.txt'))
        if res != 1:
            err = errorstring(res)
            raise Exception(
                "Error in libsmi.SMItracker.__init__: failed to set logger; %s"
                % err)
        # first logger argument is for logging type (I'm guessing these are decimal bit codes)
        # LOG status					bitcode
        # 1 = LOG_LEVEL_BUG			 00001
        # 2 = LOG_LEVEL_iV_FCT		  00010
        # 4 = LOG_LEVEL_ETCOM		   00100
        # 8 = LOG_LEVEL_ALL			 01000
        # 16 = LOG_LEVEL_IV_COMMAND	 10000
        # these can be used together, using a bitwise or, e.g.: 1|2|4 (bitcode 00111)

        # connect to iViewX
        res = iViewXAPI.iV_Connect(c_char_p(ip), c_int(sendport), c_char_p(ip),
                                   c_int(receiveport))
        if res == 1:
            res = iViewXAPI.iV_GetSystemInfo(byref(systemData))
            self.samplerate = systemData.samplerate
            self.sampletime = 1000.0 / self.samplerate
            if res != 1:
                err = errorstring(res)
                raise Exception(
                    "Error in libsmi.SMItracker.__init__: failed to get system information; %s"
                    % err)
        # handle connection errors
        else:
            self.connected = False
            err = errorstring(res)
            raise Exception(
                "Error in libsmi.SMItracker.__init__: establishing connection failed; %s"
                % err)

        # initiation report
        self.log("pygaze initiation report start")
        self.log("experiment: %s" % self.description)
        self.log("participant: %s" % self.participant)
        self.log("display resolution: %sx%s" %
                 (self.dispsize[0], self.dispsize[1]))
        self.log("display size in cm: %sx%s" %
                 (self.screensize[0], self.screensize[1]))
        self.log("samplerate: %s Hz" % self.samplerate)
        self.log("sampletime: %s ms" % self.sampletime)
        self.log("fixation threshold: %s degrees" % self.fixtresh)
        self.log("speed threshold: %s degrees/second" % self.spdtresh)
        self.log("acceleration threshold: %s degrees/second**2" %
                 self.accthresh)
        self.log("pygaze initiation report end")
Esempio n. 25
0
    def __init__(self, display, logfile=settings.LOGFILE,
                 eventdetection=settings.EVENTDETECTION,
                 saccade_velocity_threshold=35,
                 saccade_acceleration_threshold=9500,
                 blink_threshold=settings.BLINKTHRESH, **args):
        """Initializes a TobiiProTracker instance

        arguments
        display	--	a pygaze.display.Display instance

        keyword arguments
        None
        """
        self.gaze = []

        self.disp = display

        # initialize a screen
        self.screen = Screen()

        # initialize keyboard
        self.kb = Keyboard(keylist=['space', 'escape', 'q','enter'], timeout=1)

        self.recording = False

        self.screendist = settings.SCREENDIST

        if hasattr(settings, 'TRACKERSERIALNUMBER'):
            # Search for a specific eye tracker
            self.eyetrackers = [t for t in tr.find_all_eyetrackers() if t.serial_number == settings.TRACKERSERIALNUMBER]
        else:
            # Search for all eye trackers (The first one found will be selected)
            self.eyetrackers = tr.find_all_eyetrackers()

        if self.eyetrackers:
            self.eyetracker = self.eyetrackers[0]
        else:
            print("WARNING! libtobii.TobiiProTracker.__init__: no eye trackers found!")


        self.LEFT_EYE = 0
        self.RIGHT_EYE = 1
        self.BINOCULAR = 2
        self.eye_used = 0  # 0=left, 1=right, 2=binocular

        # calibration and validation points
        lb = 0.1  # left bound
        xc = 0.5  # horizontal center
        rb = 0.9  # right bound
        ub = 0.1  # upper bound
        yc = 0.5  # vertical center
        bb = 0.9  # bottom bound

        self.points_to_calibrate = [self._norm_2_px(p) for p in [(lb, ub), (xc,ub), (rb, ub), (lb,yc), (xc, yc),(rb,yc), (lb, bb),(xc,bb),(rb, bb)]]

        # event detection properties
        self.fixtresh = 1.5  # degrees; maximal distance from fixation start (if gaze wanders beyond this, fixation has stopped)
        self.fixtimetresh = 100  # milliseconds; amount of time gaze has to linger within self.fixtresh to be marked as a fixation
        self.spdtresh = saccade_velocity_threshold  # degrees per second; saccade velocity threshold
        self.accthresh = saccade_acceleration_threshold  # degrees per second**2; saccade acceleration threshold
        self.blinkthresh = blink_threshold  # milliseconds; blink detection threshold used in PyGaze method
        self.eventdetection = eventdetection
        self.weightdist = 10  # weighted distance, used for determining whether a movement is due to measurement error (1 is ok, higher is more conservative and will result in only larger saccades to be detected)

        self.screensize = settings.SCREENSIZE  # display size in cm
        self.pixpercm = (self.disp.dispsize[0] / float(self.screensize[0]) + self.disp.dispsize[1] / float(self.screensize[1])) / 2.0
        self.errdist = 2  # degrees; maximal error for drift correction
        self.pxerrdist = self._deg2pix(self.screendist, self.errdist, self.pixpercm)

        self.event_data = []

        self.t0 = None
        self._write_enabled = True

        self.datafile = open("{0}_TOBII_output.tsv".format(logfile), 'w')

        # initiation report
        self.datafile.write("pygaze initiation report start\n")
        self.datafile.write("display resolution: %sx%s\n" % (self.disp.dispsize[0], self.disp.dispsize[1]))
        self.datafile.write("display size in cm: %sx%s\n" % (self.screensize[0], self.screensize[1]))
        self.datafile.write("fixation threshold: %s degrees\n" % self.fixtresh)
        self.datafile.write("speed threshold: %s degrees/second\n" % self.spdtresh)
        self.datafile.write("acceleration threshold: %s degrees/second**2\n" % self.accthresh)
        self.datafile.write("pygaze initiation report end\n")
# PyGaze
from constants import *
from pygaze.display import Display
from pygaze.screen import Screen
from pygaze.eyetracker import EyeTracker
from pygaze.keyboard import Keyboard
from pygaze.libtime import clock


# # # # #
# SETUP

# visuals
disp = Display()
scr = Screen()

# input
tracker = EyeTracker(disp)
kb = Keyboard(keylist=None, timeout=None)

# calibrate
tracker.calibrate()

# starting screen
scr.clear()
scr.draw_text(text="Press Space to start")
disp.fill(scr)
disp.show()
kb.get_key(keylist=['space'], timeout=None, flush=True)
Esempio n. 27
0
    def __init__(self,
                 display,
                 address='192.168.71.50',
                 udpport=49152,
                 logfile=settings.LOGFILE,
                 eventdetection=settings.EVENTDETECTION,
                 saccade_velocity_threshold=35,
                 saccade_acceleration_threshold=9500,
                 blink_threshold=settings.BLINKTHRESH,
                 **args):
        """Initializes a TobiiProGlassesTracker instance

		arguments
		display	--	a pygaze.display.Display instance

		keyword arguments
		address	-- internal ipv4/ipv6 address for Tobii Pro Glasses 2 (default =
				   '192.168.71.50', for IpV6 address use square brackets [fe80::xxxx:xxxx:xxxx:xxxx])
		udpport	-- UDP port number for Tobii Pro Glasses data streaming (default = 49152)
		"""

        # try to copy docstrings (but ignore it if it fails, as we do
        # not need it for actual functioning of the code)
        try:
            copy_docstr(BaseEyeTracker, TobiiProGlassesTracker)
        except:
            # we're not even going to show a warning, since the copied
            # docstring is useful for code editors; these load the docs
            # in a non-verbose manner, so warning messages would be lost
            pass

        # object properties
        self.disp = display
        self.screen = Screen()
        self.dispsize = settings.DISPSIZE  # display size in pixels
        self.screensize = settings.SCREENSIZE  # display size in cm
        self.screendist = settings.SCREENDIST  # distance between participant and screen in cm
        self.pixpercm = (self.dispsize[0] / float(self.screensize[0]) +
                         self.dispsize[1] / float(self.screensize[1])) / 2.0
        self.kb = Keyboard(keylist=['space', 'escape', 'q'], timeout=1)
        self.errorbeep = Sound(osc='saw', freq=100, length=100)

        # output file properties
        self.outputfile = logfile
        self.description = "experiment"  # TODO: EXPERIMENT NAME
        self.participant = "participant"  # TODO: PP NAME

        # eye tracker properties
        self.eye_used = 0  # 0=left, 1=right, 2=binocular
        self.left_eye = 0
        self.right_eye = 1
        self.binocular = 2

        self.maxtries = 100  # number of samples obtained before giving up (for obtaining accuracy and tracker distance information, as well as starting or stopping recording)
        self.prevsample = (-1, -1)

        # validation properties
        self.nvalsamples = 1000  # samples for one validation point

        # event detection properties
        self.fixtresh = 1.5  # degrees; maximal distance from fixation start (if gaze wanders beyond this, fixation has stopped)
        self.fixtimetresh = 100  # milliseconds; amount of time gaze has to linger within self.fixtresh to be marked as a fixation
        self.spdtresh = saccade_velocity_threshold  # degrees per second; saccade velocity threshold
        self.accthresh = saccade_acceleration_threshold  # degrees per second**2; saccade acceleration threshold
        self.blinkthresh = blink_threshold  # milliseconds; blink detection threshold used in PyGaze method
        self.eventdetection = eventdetection
        self.set_detection_type(self.eventdetection)
        self.weightdist = 10  # weighted distance, used for determining whether a movement is due to measurement error (1 is ok, higher is more conservative and will result in only larger saccades to be detected)

        self.tobiiglasses = TobiiGlassesController(udpport, address)

        self.triggers_values = {}

        self.logging = False
        self.current_recording_id = None
        self.current_participant_id = None
        self.current_project_id = None
Esempio n. 28
0
    def __init__(self,
                 display,
                 resolution=settings.DISPSIZE,
                 data_file=settings.LOGFILENAME + ".edf",
                 fg_color=settings.FGC,
                 bg_color=settings.BGC,
                 eventdetection=settings.EVENTDETECTION,
                 saccade_velocity_threshold=35,
                 saccade_acceleration_threshold=9500,
                 blink_threshold=settings.BLINKTHRESH,
                 force_drift_correct=True,
                 pupil_size_mode=settings.EYELINKPUPILSIZEMODE,
                 **args):
        """See pygaze._eyetracker.baseeyetracker.BaseEyeTracker"""

        # try to import copy docstring (but ignore it if it fails, as we do
        # not need it for actual functioning of the code)
        try:
            copy_docstr(BaseEyeTracker, libeyelink)
        except:
            # we're not even going to show a warning, since the copied
            # docstring is useful for code editors; these load the docs
            # in a non-verbose manner, so warning messages would be lost
            pass

        global _eyelink

        # Make sure that we have a valid data file. The local_data_file may
        # contain a folder. The eyelink_data_file is only a basename, i.e.
        # without folder. The eyelink_data_file must be at most eight characters
        # and end with a `.edf` extension.

        self.local_data_file = data_file
        self.eyelink_data_file = os.path.basename(data_file)
        stem, ext = os.path.splitext(self.eyelink_data_file)
        if len(stem) > 8 or ext.lower() != '.edf':
            raise Exception(
                "The EyeLink cannot handle filenames longer than eight "
                "characters (excluding '.edf' extension).")

        # properties
        self.display = display
        self.fontsize = 18
        self.scr = Screen(disptype=settings.DISPTYPE, mousevisible=False)
        self.kb = Keyboard(keylist=["escape", "q"], timeout=1)
        self.resolution = resolution
        self.recording = False
        self.saccade_velocity_treshold = saccade_velocity_threshold
        self.saccade_acceleration_treshold = saccade_acceleration_threshold
        self.blink_threshold = blink_threshold
        self.eye_used = None
        self.left_eye = 0
        self.right_eye = 1
        self.binocular = 2
        self.pupil_size_mode = pupil_size_mode
        self.prevsample = (-1, -1)
        self.prevps = -1

        # event detection properties
        # degrees; maximal distance from fixation start (if gaze wanders beyond
        # this, fixation has stopped)
        self.fixtresh = 1.5
        # milliseconds; amount of time gaze has to linger within self.fixtresh
        # to be marked as a fixation
        self.fixtimetresh = 100
        # degrees per second; saccade velocity threshold
        self.spdtresh = self.saccade_velocity_treshold
        # degrees per second**2; saccade acceleration threshold
        self.accthresh = self.saccade_acceleration_treshold
        self.set_detection_type(eventdetection)
        # weighted distance, used for determining whether a movement is due to
        # measurement error (1 is ok, higher is more conservative and will
        # result in only larger saccades to be detected)
        self.weightdist = 10
        # distance between participant and screen in cm
        self.screendist = settings.SCREENDIST
        # distance between participant and screen in cm
        self.screensize = settings.SCREENSIZE
        self.pixpercm = (self.resolution[0]/float(self.screensize[0]) + \
         self.resolution[1]/float(self.screensize[1])) / 2.0
        # only initialize eyelink once
        if _eyelink == None:
            try:
                _eyelink = pylink.EyeLink()
            except:
                raise Exception(
                    "Error in libeyelink.libeyelink.__init__(): Failed to "
                    "connect to the tracker!")
        # determine software version of tracker
        self.tracker_software_ver = 0
        self.eyelink_ver = pylink.getEYELINK().getTrackerVersion()
        if self.eyelink_ver == 3:
            tvstr = pylink.getEYELINK().getTrackerVersionString()
            vindex = tvstr.find("EYELINK CL")
            self.tracker_software_ver = int(float(tvstr[(vindex + \
             len("EYELINK CL")):].strip()))
        if self.eyelink_ver == 1:
            self.eyelink_model = 'EyeLink I'
        elif self.eyelink_ver == 2:
            self.eyelink_model = 'EyeLink II'
        elif self.eyelink_ver == 3:
            self.eyelink_model = 'EyeLink 1000'
        else:
            self.eyelink_model = 'EyeLink (model unknown)'
        # Open graphics
        self.eyelink_graphics = EyelinkGraphics(self, _eyelink)
        pylink.openGraphicsEx(self.eyelink_graphics)
        # Optionally force drift correction. For some reason this must be done
        # as (one of) the first things, otherwise a segmentation fault occurs.
        if force_drift_correct:
            try:
                self.send_command('driftcorrect_cr_disable = OFF')
            except:
                print('Failed to force drift correction (EyeLink 1000 only)')
        # Set pupil-size mode
        if self.pupil_size_mode == 'area':
            pylink.getEYELINK().setPupilSizeDiameter(False)
        elif self.pupil_size_mode == 'diameter':
            pylink.getEYELINK().setPupilSizeDiameter(True)
        else:
            raise Exception(
             "pupil_size_mode should be 'area' or 'diameter', not %s" \
             % self.pupil_size_mode)
        pylink.getEYELINK().openDataFile(self.eyelink_data_file)
        pylink.flushGetkeyQueue()
        pylink.getEYELINK().setOfflineMode()
        # notify eyelink of display resolution
        self.send_command("screen_pixel_coords = 0 0 %d %d" % \
         (self.resolution[0], self.resolution[1]))
        # get some configuration stuff
        if self.eyelink_ver >= 2:
            self.send_command("select_parser_configuration 0")
            if self.eyelink_ver == 2:  # turn off scenelink camera stuff
                self.send_command("scene_camera_gazemap = NO")
        # set EDF file contents (this specifies which data is written to the EDF
        # file)
        self.send_command(
            "file_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,MESSAGE,BUTTON"
        )
        if self.tracker_software_ver >= 4:
            self.send_command(
                "file_sample_data  = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS,HTARGET"
            )
        else:
            self.send_command(
                "file_sample_data  = LEFT,RIGHT,GAZE,AREA,GAZERES,STATUS")
        # set link data (this specifies which data is sent through the link and
        # thus can be used in gaze contingent displays)
        self.send_command(
            "link_event_filter = LEFT,RIGHT,FIXATION,SACCADE,BLINK,BUTTON")
        if self.tracker_software_ver >= 4:
            self.send_command(
                "link_sample_data  = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS,HTARGET"
            )
        else:
            self.send_command(
                "link_sample_data  = LEFT,RIGHT,GAZE,GAZERES,AREA,STATUS")
        # not quite sure what this means (according to Sebastiaan Mathot, it
        # might be the button that is used to end drift correction?)
        self.send_command("button_function 5 'accept_target_fixation'")

        if not self.connected():
            raise Exception(
                "Error in libeyelink.libeyelink.__init__(): Failed to connect "
                "to the eyetracker!")
Esempio n. 29
0
    def __init__(self, libeyelink, tracker):
        """
        Constructor.

        Arguments:
        libeyelink    --    A libeyelink object.
        tracker        --    An tracker object as returned by pylink.EyeLink().
        """

        pylink.EyeLinkCustomDisplay.__init__(self)

        # objects
        self.libeyelink = libeyelink
        self.display = libeyelink.display
        self.screen = Screen(disptype=settings.DISPTYPE, mousevisible=False)
        self.kb = Keyboard(keylist=None, timeout=1)
        self.mouse = Mouse(timeout=1)
        # If we are using a DISPTYPE that cannot be used directly, we have to
        # save the camera image to a temporary file on each frame.
        #if DISPTYPE not in ('pygame', 'psychopy'):
        import tempfile
        import os
        self.tmp_file = os.path.join(tempfile.gettempdir(), "__eyelink__.jpg")
        # drawing properties
        self.xc = self.display.dispsize[0] / 2
        self.yc = self.display.dispsize[1] / 2
        self.extra_info = True
        self.ld = 40  # line distance
        self.fontsize = libeyelink.fontsize
        self.title = ""
        self.display_open = True
        self.draw_menu_screen()
        # A crosshair is drawn onto the eye image. This should be scaled in
        # pylink 1.1.0.5 (tested on Python 2.7) but not on pylink 1.11.0.0
        # (tested on Python 3.6). I'm not sure when this change happened, so
        # it's quite likely we'll have to update the minor version used here.
        pl_version = pylink.__version__.split(".")
        if int(pl_version[0]) > 1 or int(pl_version[1]) >= 11:
            self.scale_lines_in_eye_image = False
        else:
            self.scale_lines_in_eye_image = True
        # Beeps
        self.__target_beep__ = Sound(osc="sine",
                                     freq=440,
                                     length=50,
                                     attack=0,
                                     decay=0,
                                     soundfile=None)
        self.__target_beep__done__ = Sound(osc="sine",
                                           freq=880,
                                           length=200,
                                           attack=0,
                                           decay=0,
                                           soundfile=None)
        self.__target_beep__error__ = Sound(osc="sine",
                                            freq=220,
                                            length=200,
                                            attack=0,
                                            decay=0,
                                            soundfile=None)
        # Colors
        self.color = {
            pylink.CR_HAIR_COLOR: pygame.Color("white"),
            pylink.PUPIL_HAIR_COLOR: pygame.Color("white"),
            pylink.PUPIL_BOX_COLOR: pygame.Color("green"),
            pylink.SEARCH_LIMIT_BOX_COLOR: pygame.Color("red"),
            pylink.MOUSE_CURSOR_COLOR: pygame.Color("red"),
            'font': pygame.Color("white"),
        }
        # Font
        pygame.font.init()
        self.font = pygame.font.SysFont("Courier New", 11)
        # further properties
        self.state = None
        self.pal = None

        self.size = (0, 0)
        self.set_tracker(tracker)
        self.last_mouse_state = -1
        self.bit64 = "64bit" in platform.architecture()
        self.imagebuffer = self.new_array()