def calibrate(self): # instantiate calibration object self.cal = tr.ScreenBasedCalibration(self.tracker) self.cal.enter_calibration_mode() # enter calibration mode for row, col in list(zip(self.r, self.c)): img = np.zeros([self.ht, self.wd]) # initialize images with zeros img[row - self.point_size:row + self.point_size, col - self.point_size:col + self.point_size] = 255. row, col = float(row) / self.ht, float( col) / self.wd # normalize the points for calibration cv2.namedWindow('test', cv2.WINDOW_NORMAL) cv2.imshow('test', img) cv2.waitKey(800) #if cal.collect_data(col, row) != tr.CALIBRATION_STATUS_SUCCESS: self.cal.collect_data(col, row) result = self.cal.compute_and_apply() print "Compute and apply returned {0} and collected at {1} points.".\ format(result.status, len(result.calibration_points)) self.cal.leave_calibration_mode() cv2.destroyAllWindows() return result.status, len(result.calibration_points)
def __init__(self, win, id=0, filename="gaze_TOBII_output.tsv"): self.eyetracker_id = id self.win = win self.filename = filename self.numkey_dict = self._default_numkey_dict self.calibration_dot_size = self._default_calibration_dot_size[ self.win.units] self.calibration_disc_size = self._default_calibration_disc_size[ self.win.units] eyetrackers = tr.find_all_eyetrackers() if len(eyetrackers) == 0: raise RuntimeError("No Tobii eyetrackers") try: self.eyetracker = eyetrackers[self.eyetracker_id] except: raise ValueError( "Invalid eyetracker ID {}\n({} eyetrackers found)".format( self.eyetracker_id, len(eyetrackers))) self.calibration = tr.ScreenBasedCalibration(self.eyetracker) self.update_calibration = self._update_calibration_auto self.gaze_data = []
def notifications(eyetracker): all_notifications = \ (tr.EYETRACKER_NOTIFICATION_CONNECTION_LOST, tr.EYETRACKER_NOTIFICATION_CONNECTION_RESTORED, tr.EYETRACKER_NOTIFICATION_CALIBRATION_MODE_ENTERED, tr.EYETRACKER_NOTIFICATION_CALIBRATION_MODE_LEFT, tr.EYETRACKER_NOTIFICATION_CALIBRATION_CHANGED, tr.EYETRACKER_NOTIFICATION_TRACK_BOX_CHANGED, tr.EYETRACKER_NOTIFICATION_DISPLAY_AREA_CHANGED, tr.EYETRACKER_NOTIFICATION_GAZE_OUTPUT_FREQUENCY_CHANGED, tr.EYETRACKER_NOTIFICATION_EYE_TRACKING_MODE_CHANGED, tr.EYETRACKER_NOTIFICATION_DEVICE_FAULTS, tr.EYETRACKER_NOTIFICATION_DEVICE_WARNINGS) # Subscribe to all notifications. for notification in all_notifications: eyetracker.subscribe_to(notification, lambda x, notification=notification: notification_callback(notification, x)) print( "Subscribed to {0} for eye tracker with serial number {1}.".format( notification, eyetracker.serial_number)) # Trigger some notifications calibration = tr.ScreenBasedCalibration(eyetracker) calibration.enter_calibration_mode() calibration.leave_calibration_mode() # Unsubscribe from notifications. for notification in all_notifications: eyetracker.unsubscribe_from(notification) print("Unsubscribed from {0}.".format(notification))
def execute(eyetracker): global time, tr if eyetracker is None: return # キャリブレーションモードに切り替える calibration = tr.ScreenBasedCalibration(eyetracker) calibration.enter_calibration_mode() print(('Entered calibration mode for eye tracker with serial number {0}.').format( eyetracker.serial_number)) # キャリブレーションのための点を表示する座標 points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)] for point in points_to_calibrate: print(('Show a point on screen at {0}.').format(point)) draw_caribration_points(point) print(('Collecting data at {0}.').format(point)) # 視線をキャリブレートする if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS: calibration.collect_data(point[0], point[1]) # キャリブレーションの結果を表示 print('Computing and applying calibration.') calibration_result = calibration.compute_and_apply() print(('Compute and apply returned {0} and collected at {1} points.'). format(calibration_result.status, len(calibration_result.calibration_points))) # キャリブレーションモードに終了 calibration.leave_calibration_mode() print('Left calibration mode.')
def execute(eyetracker): if eyetracker is None: return # <BeginExample> import time import tobii_research as tr calibration = tr.ScreenBasedCalibration(eyetracker) # Enter calibration mode. calibration.enter_calibration_mode() print("Entered calibration mode for eye tracker with serial number {0}.". format(eyetracker.serial_number)) # Define the points on screen we should calibrate at. # The coordinates are normalized, i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner. points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)] for point in points_to_calibrate: print("Show a point on screen at {0}.".format(point)) # Wait a little for user to focus. time.sleep(0.7) print("Collecting data at {0}.".format(point)) if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS: # Try again if it didn't go well the first time. # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply. calibration.collect_data(point[0], point[1]) print("Computing and applying calibration.") calibration_result = calibration.compute_and_apply() print("Compute and apply returned {0} and collected at {1} points.".format( calibration_result.status, len(calibration_result.calibration_points))) # Analyze the data and maybe remove points that weren't good. recalibrate_point = (0.1, 0.1) print("Removing calibration point at {0}.".format(recalibrate_point)) calibration.discard_data(recalibrate_point[0], recalibrate_point[1]) # Redo collection at the discarded point print("Show a point on screen at {0}.".format(recalibrate_point)) calibration.collect_data(recalibrate_point[0], recalibrate_point[1]) # Compute and apply again. print("Computing and applying calibration.") calibration_result = calibration.compute_and_apply() print("Compute and apply returned {0} and collected at {1} points.".format( calibration_result.status, len(calibration_result.calibration_points))) # See that you're happy with the result. # The calibration is done. Leave calibration mode. calibration.leave_calibration_mode() print("Left calibration mode.")
def __init__(self, win, id=0, filename='gaze_TOBII_output.tsv'): """Tobii controller for PsychoPy. tobii_research are required for this module. Args: win: psychopy.visual.Window object. id: the id of eyetracker. filename: the name of the data file. Attributes: shrink_speed: the shrinking speed of target in calibration. Defaults to 1.5. calibration_dot_size: the size of the central dot in the calibration target. Defaults to default_calibration_dot_size according to the units of self.win. calibration_dot_color: the color of the central dot in the calibration target. Defaults to grey. calibration_disc_size: the size of the disc in the calibration target. Defaults to default_calibration_disc_size according to the units of self.win. calibration_disc_color: the color of the disc in the calibration target. Defaults to deep blue. calibration_target_min: the minimum size of the calibration target. Defaults to 0.2. numkey_dict: keys used for calibration. Defaults to the number pad. update_calibration: the presentation of calibration target. Defaults to auto calibration. """ self.eyetracker_id = id self.win = win self.filename = filename self._calibration_dot_size = default_calibration_dot_size[self.win. units] self._calibration_disc_size = default_calibration_disc_size[self.win. units] self.calibration_dot_size = self._calibration_dot_size self.calibration_disc_size = self._calibration_disc_size self.calibration_dot_color = self._calibration_dot_color self.calibration_disc_color = self._calibration_disc_color self.calibration_target_min = self._calibration_target_min eyetrackers = tr.find_all_eyetrackers() if len(eyetrackers) == 0: raise RuntimeError('No Tobii eyetrackers') try: self.eyetracker = eyetrackers[self.eyetracker_id] except: raise ValueError( 'Invalid eyetracker ID {}\n({} eyetrackers found)'.format( self.eyetracker_id, len(eyetrackers))) self.calibration = tr.ScreenBasedCalibration(self.eyetracker) self.update_calibration = self._update_calibration_auto self.gaze_data = []
def __init__(self, win, id=0): """ Initialize tobii_controller object. :param win: PsychoPy Window object. :param int id: ID of Tobii unit to connect with. Default value is 0. """ self.eyetracker_id = id self.win = win self.calibration_target_dot_size = default_calibration_target_dot_size[ self.win.units] self.calibration_target_disc_size = default_calibration_target_disc_size[ self.win.units] self.calibration_target_dot = psychopy.visual.Circle( self.win, radius=self.calibration_target_dot_size, fillColor='white', lineColor=None, lineWidth=1, autoLog=False) self.calibration_target_disc = psychopy.visual.Circle( self.win, radius=self.calibration_target_disc_size, fillColor='lime', lineColor='white', lineWidth=1, autoLog=False) self.update_calibration = self.update_calibration_default if self.win.units == 'norm': # fix oval self.calibration_target_dot.setSize( [float(self.win.size[1]) / self.win.size[0], 1.0]) self.calibration_target_disc.setSize( [float(self.win.size[1]) / self.win.size[0], 1.0]) eyetrackers = tobii_research.find_all_eyetrackers() if len(eyetrackers) == 0: raise RuntimeError('No Tobii eyetrackers') try: self.eyetracker = eyetrackers[self.eyetracker_id] except: raise ValueError( 'Invalid eyetracker ID {}\n({} eyetrackers found)'.format( self.eyetracker_id, len(eyetrackers))) self.calibration = tobii_research.ScreenBasedCalibration( self.eyetracker)
def execute (eyetracker): if eyetracker is None:" return import time import tobii_research as tr calibration = tr.ScreenBasedCalibration(eyetracker) #Inicia calibragem calibration.enter_calibration_mode() print("Serial Number do disposítivo Eye Tracker{0}.".format(eyetracker.serial_number)) #Define os pontos da tela onde devemos calibrar #As coordenadas padrão são (0.0 , 0.0) sendo o lado superior esquero e (1.0 , 1.0) o lado inferior direito points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)] for point in points_to_calibrate: print("Mostre um ponto na tela em {0}.".format(point)) #Esperar um pouco para o usuário focar no ponto time.sleep(0.7) print("Coletando dados em {0}.".format(point) ) if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS: #Tente novamente se não deu certo na primeira vez #Nem todos os eye trackers irão falhar nesse ponto, porém, é bom fazer um fail safe calibration.collect_data(point[0], point[1]) print("Calculando e aplicando calibragem.") calibration_result = calibration.compute_and_apply() print("Calculado e aplicado retornado em {0} e colletado em {1} pontos.".format(calibration_result.status, len(calibration_result.calibration_points))) #Analise os dados e talvez remova os pontos que não são bons. recalibrate_point = (0.1. 0.1) print ("Removendo pontos de calibração em {0}.".format(recalibrate_point)) calibration.discard_data(recalibrate_point[0], recalibrate_point[1]) #Calcule e aplique novamente print("Calculando e aplicando calibragem.") calibration_result = calibration.compute_and_apply() print("Calculado e aplicado retornado em {0} e colletado em {1} pontos.".format(calibration_result.status, len(calibration_result.calibration_points))) #verifique se você está satisfeito com o resultado #Agora que a calibragem está completa, saia do modo de calibragem. calibragem.leave_calibration_mode() print("Saindo no modo de Calibragem.")
def exec_calibration(self): calibration = tr.ScreenBasedCalibration(self.eyetracker) calibration.enter_validation_mode() points = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)] for point in points: print("Show a point on screen at {0}.".format(point)) time.sleep(0.7) if calibration.compute_and_apply( ).status != tr.CALIBRATION_STATUS_SUCCESS: calibration.collect_data(point[0], point[1]) print("Apply calibration.") result = calibration.compute() print("result:{}".format(result.status)) calibration.leave_validation_mode() print("Completed calibration.")
def calibrate(self): """ 画面上5点でキャリブレーションを行う. :return: """ calibrator = tb.ScreenBasedCalibration(self.eye_tracker) calibrator.enter_calibration_mode() if tb.EYETRACKER_NOTIFICATION_CALIBRATION_MODE_ENTERED: print("calibration mode") else: print("oops, something occurred. terminating the program") is_data_collected = False for i in range(5): while not is_data_collected: print("Calibration at the point " + str(i + 1)) self.screen.fill((0, 0, 0)) x, y = self.calibration_points[i] # pygame.draw.circle(self.screen, color=(255, 255, 255), center=(20, 20), radius=10) # pygame.draw.circle(self.screen, color=(255, 255, 255), center=(1900, 1080), radius=10) pygame.draw.circle(self.screen, color=(255, 255, 255), center=(x, y), radius=10) pygame.display.update() time.sleep(1.0) calibration_status = calibrator.collect_data(x, y) time.sleep(2.0) is_data_collected = calibration_status == "calibration_status_success" is_data_collected = False #TODO: 画面上の点を見るように指示をだす calibration_result = calibrator.compute_and_apply() if calibration_result is None: print("calibration failed") else: print("probably went well") pygame.quit() calibrator.leave_calibration_mode()
def cali_start(self): global EYE_TRACKER if EYE_TRACKER is None: self.finish_cali = True return time.sleep(1.0) calibration = tr.ScreenBasedCalibration(EYE_TRACKER) # Enter calibration mode. calibration.enter_calibration_mode() logging.info( "Entered calibration mode for eye tracker with serial number {0}.". format(EYE_TRACKER.serial_number)) for (x, y) in zip( [0.2, 0.2, 0.5, 0.8, 0.8], [0.2, 0.8, 0.5, 0.2, 0.8] ): # for (x, y) in zip([0.1, 0.1, 0.5, 0.9, 0.9], [0.1, 0.9, 0.5, 0.1, 0.9]): self.show_point(x * SCREEN_X, y * SCREEN_Y) time.sleep(0.7) if calibration.collect_data(x, y) != tr.CALIBRATION_STATUS_SUCCESS: # Try again if it didn't go well the first time. calibration.collect_data(x, y) time.sleep(0.3) try: self.cali_result = calibration.compute_and_apply() logging.info( "Compute and apply returned {0} and collected at {1} points.". format(self.cali_result.status, len(self.cali_result.calibration_points))) except ValueError: logging.error("Calibration failed") calibration.leave_calibration_mode() self.finish_cali = True
# Find Eye Tracker ft = tr.find_all_eyetrackers() #if len(ft) == 0: # print "No Eye Trackers found!?" # exit(1) while len(ft) == 0: print "No Eye Trackers found!? - retry in 5 seconds..." time.sleep(5) ft = tr.find_all_eyetrackers() # Pick first tracker mt = ft[0] print "Found Tobii Tracker at '%s'" % (mt.address) calibration = tr.ScreenBasedCalibration(mt) # Enter calibration mode. calibration.enter_calibration_mode() print "Enter Calibration for EyeTracker at '%s'" % (mt.address) # Define the points on screen we should calibrate at. # The coordinates are normalized, i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner. points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)] for point in points_to_calibrate: print("Show a point on screen at {0}.".format(point)) # Wait a little for user to focus. time.sleep(1)
def initCalibration(self, Visu): self.RecSound = libsound.Sound( soundfile='/home/eyetracker/Downloads/2.wav') self.calibrated_point = [] self._write_enabled = False self.start_recording() self.screen.set_background_colour(colour=(0, 0, 0)) origin = (int(self.disp.dispsize[0] / 4), int(self.disp.dispsize[1] / 4)) size = (int(2 * self.disp.dispsize[0] / 4), int(2 * self.disp.dispsize[1] / 4)) while not self.kb.get_key(keylist=['space'], flush=False)[0]: gaze_sample = copy.copy(self.gaze[-1]) self.screen.clear() validity_colour = (255, 0, 0) col = 'red' Visu.effacer_mouvement() if gaze_sample['right_gaze_origin_validity'] and gaze_sample[ 'left_gaze_origin_validity']: left_validity = 0.15 < gaze_sample[ 'left_gaze_origin_in_trackbox_coordinate_system'][2] < 0.85 right_validity = 0.15 < gaze_sample[ 'right_gaze_origin_in_trackbox_coordinate_system'][2] < 0.85 if left_validity and right_validity: validity_colour = (0, 255, 0) col = 'green' self.screen.draw_line(colour=validity_colour, spos=origin, epos=(origin[0] + size[0], origin[1]), pw=1) self.screen.draw_line(colour=validity_colour, spos=origin, epos=(origin[0], origin[1] + size[1]), pw=1) self.screen.draw_line(colour=validity_colour, spos=(origin[0], origin[1] + size[1]), epos=(origin[0] + size[0], origin[1] + size[1]), pw=1) self.screen.draw_line(colour=validity_colour, spos=(origin[0] + size[0], origin[1] + size[1]), epos=(origin[0] + size[0], origin[1]), pw=1) right_eye, left_eye, distance = None, None, [] if gaze_sample['right_gaze_origin_validity']: right_eye = ( (1 - gaze_sample[ 'right_gaze_origin_in_trackbox_coordinate_system'][0]) * size[0] + origin[0], gaze_sample[ 'right_gaze_origin_in_trackbox_coordinate_system'][1] * size[1] + origin[1]) self.screen.draw_circle(colour=validity_colour, pos=right_eye, r=int(self.disp.dispsize[0] / 100), pw=5, fill=True) Visu.Show_droit(right_eye[0], right_eye[1], col, int(self.disp.dispsize[0] / 200)) if gaze_sample['left_gaze_origin_validity']: left_eye = ( (1 - gaze_sample[ 'left_gaze_origin_in_trackbox_coordinate_system'][0]) * size[0] + origin[0], gaze_sample[ 'left_gaze_origin_in_trackbox_coordinate_system'][1] * size[1] + origin[1]) self.screen.draw_circle(colour=validity_colour, pos=left_eye, r=int(self.disp.dispsize[0] / 100), pw=5, fill=True) Visu.Show_gauche(left_eye[0], left_eye[1], col, int(self.disp.dispsize[0] / 200)) Visu.VisuShow() self.disp.fill(self.screen) self.disp.show() if self.kb.get_key(keylist=['tab'], flush=False)[0]: self.screen.clear() self.disp.fill(self.screen) self.disp.show() Visu.effacer_mouvement() Visu.VisuShow() return () Visu.effacer_mouvement() Visu.VisuShow() # # # # # # # # calibration self.screen.clear() if not self.eyetracker: print( "WARNING! libtobii.TobiiProTracker.calibrate: no eye trackers found for the calibration!" ) self.stop_recording() return False self.calibration = tr.ScreenBasedCalibration(self.eyetracker) self.disp.show() self.calibration.enter_calibration_mode() self.RecSound.play()
def calibrate(self, calibrate=True, validate=True): self.start_recording() self.screen.set_background_colour(colour=(0, 0, 0)) if calibrate: origin = (int(self.disp.dispsize[0] / 4), int(self.disp.dispsize[1] / 4)) size = (int(2 * self.disp.dispsize[0] / 4), int(2 * self.disp.dispsize[1] / 4)) while not self.kb.get_key(keylist=['space'], flush=False)[0]: # TODO: What should we do when there are no gaze samples yet? # Should we wait or raise an Exception to indicate that # something went wrong. if not self.gaze_data: continue gaze_sample = self.gaze_data[-1] self.screen.clear() validity_colour = (255, 0, 0) if gaze_sample['right_gaze_origin_validity'] and gaze_sample[ 'left_gaze_origin_validity']: left_validity = 0.15 < gaze_sample[ 'left_gaze_origin_in_trackbox_coordinate_system'][ 2] < 0.85 right_validity = 0.15 < gaze_sample[ 'right_gaze_origin_in_trackbox_coordinate_system'][ 2] < 0.85 if left_validity and right_validity: validity_colour = (0, 255, 0) self.screen.draw_text( text= "When correctly positioned press \'space\' to start the calibration.", pos=(int(self.disp.dispsize[0] / 2), int(self.disp.dispsize[1] * 0.1)), colour=(255, 255, 255), fontsize=20) self.screen.draw_line(colour=validity_colour, spos=origin, epos=(origin[0] + size[0], origin[1]), pw=1) self.screen.draw_line(colour=validity_colour, spos=origin, epos=(origin[0], origin[1] + size[1]), pw=1) self.screen.draw_line(colour=validity_colour, spos=(origin[0], origin[1] + size[1]), epos=(origin[0] + size[0], origin[1] + size[1]), pw=1) self.screen.draw_line(colour=validity_colour, spos=(origin[0] + size[0], origin[1] + size[1]), epos=(origin[0] + size[0], origin[1]), pw=1) right_eye, left_eye, distance = None, None, [] if gaze_sample['right_gaze_origin_validity']: distance.append( round( gaze_sample[ 'right_gaze_origin_in_user_coordinate_system'] [2] / 10, 1)) right_pos = gaze_sample[ 'right_gaze_origin_in_trackbox_coordinate_system'] right_eye = ((1 - right_pos[0]) * size[0] + origin[0], right_pos[1] * size[1] + origin[1]) self.screen.draw_circle(colour=validity_colour, pos=right_eye, r=int(self.disp.dispsize[0] / 100), pw=5, fill=True) if gaze_sample['left_gaze_origin_validity']: distance.append( round( gaze_sample[ 'left_gaze_origin_in_user_coordinate_system'] [2] / 10, 1)) left_pos = gaze_sample[ 'left_gaze_origin_in_trackbox_coordinate_system'] left_eye = ((1 - left_pos[0]) * size[0] + origin[0], left_pos[1] * size[1] + origin[1]) self.screen.draw_circle(colour=validity_colour, pos=left_eye, r=int(self.disp.dispsize[0] / 100), pw=5, fill=True) self.screen.draw_text( text="Current distance to the eye tracker: {0} cm.".format( self._mean(distance)), pos=(int(self.disp.dispsize[0] / 2), int(self.disp.dispsize[1] * 0.9)), colour=(255, 255, 255), fontsize=20) self.disp.fill(self.screen) self.disp.show() # # # # # # # # calibration if not self.eyetracker: if DEBUG: print( "WARNING! libtobii.TobiiProTracker.calibrate: no eye trackers found for the calibration!" ) self.stop_recording() return False calibration = tr.ScreenBasedCalibration(self.eyetracker) calibrating = True while calibrating: calibration.enter_calibration_mode() for point in self.points_to_calibrate: self.screen.clear() self.screen.draw_circle(colour=(255, 255, 255), pos=point, r=int(self.disp.dispsize[0] / 100.0), pw=5, fill=True) self.screen.draw_circle(colour=(255, 0, 0), pos=point, r=int(self.disp.dispsize[0] / 400.0), pw=5, fill=True) self.disp.fill(self.screen) self.disp.show() # Wait a little for user to focus. time.sleep(1) normalized_point = self._px_2_norm(point) collect_result = calibration.collect_data( normalized_point[0], normalized_point[1]) if collect_result != tr.CALIBRATION_STATUS_SUCCESS: # Try again if it didn't go well the first time. # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply. calibration.collect_data(normalized_point[0], normalized_point[1]) self.screen.clear() self.screen.draw_text("Calculating calibration result....", colour=(255, 255, 255), fontsize=20) self.disp.fill(self.screen) self.disp.show() calibration_result = calibration.compute_and_apply() calibration.leave_calibration_mode() if DEBUG: print( "Compute and apply returned {0} and collected at {1} points." .format(calibration_result.status, len(calibration_result.calibration_points))) if calibration_result.status != tr.CALIBRATION_STATUS_SUCCESS: self.stop_recording() if DEBUG: print( "WARNING! libtobii.TobiiProTracker.calibrate: Calibration was unsuccessful!" ) return False self.screen.clear() for point in calibration_result.calibration_points: self.screen.draw_circle( colour=(255, 255, 255), pos=self._norm_2_px(point.position_on_display_area), r=self.disp.dispsize[0] / 200, pw=1, fill=False) for sample in point.calibration_samples: if sample.left_eye.validity == tr.VALIDITY_VALID_AND_USED: self.screen.draw_circle( colour=(255, 0, 0), pos=self._norm_2_px( sample.left_eye.position_on_display_area), r=self.disp.dispsize[0] / 450, pw=self.disp.dispsize[0] / 450, fill=False) self.screen.draw_line( colour=(255, 0, 0), spos=self._norm_2_px( point.position_on_display_area), epos=self._norm_2_px( sample.left_eye.position_on_display_area), pw=1) if sample.right_eye.validity == tr.VALIDITY_VALID_AND_USED: self.screen.draw_circle( colour=(0, 0, 255), pos=self._norm_2_px( sample.right_eye.position_on_display_area), r=self.disp.dispsize[0] / 450, pw=self.disp.dispsize[0] / 450, fill=False) self.screen.draw_line( colour=(0, 0, 255), spos=self._norm_2_px( point.position_on_display_area), epos=self._norm_2_px( sample.right_eye.position_on_display_area), pw=1) self.screen.draw_text( "Press the \'R\' key to recalibrate or \'Space\' to continue....", pos=(0.5 * self.disp.dispsize[0], 0.95 * self.disp.dispsize[1]), colour=(255, 255, 255), fontsize=20) self.screen.draw_text("Left Eye", pos=(0.5 * self.disp.dispsize[0], 0.01 * self.disp.dispsize[1]), colour=(255, 0, 0), fontsize=20) self.screen.draw_text("Right Eye", pos=(0.5 * self.disp.dispsize[0], 0.03 * self.disp.dispsize[1]), colour=(0, 0, 255), fontsize=20) self.disp.fill(self.screen) self.disp.show() pressed_key = self.kb.get_key(keylist=['space', 'r'], flush=True, timeout=None) if pressed_key[0] == 'space': calibrating = False if validate: # # # show menu self.screen.clear() self.screen.draw_text(text="Press space to start validation", colour=(255, 255, 255), fontsize=20) self.disp.fill(self.screen) self.disp.show() # # # wait for spacepress self.kb.get_key(keylist=['space'], flush=True, timeout=None) # # # # # # # # validation # # # arrays for data storage lxacc, lyacc, rxacc, ryacc = [], [], [], [] # # loop through all calibration positions for pos in self.points_to_calibrate: # show validation point self.screen.clear() self.screen.draw_fixation(fixtype='dot', pos=pos, colour=(255, 255, 255)) self.disp.fill(self.screen) self.disp.show() # allow user some time to gaze at dot time.sleep(1) lxsamples, lysamples, rxsamples, rysamples = [], [], [], [] for sample in self.gaze_data: if sample["left_gaze_point_validity"]: gaze_point = self._norm_2_px( sample["left_gaze_point_on_display_area"]) lxsamples.append(abs(gaze_point[0] - pos[0])) lysamples.append(abs(gaze_point[1] - pos[1])) if sample["right_gaze_point_validity"]: gaze_point = self._norm_2_px( sample["right_gaze_point_on_display_area"]) rxsamples.append(abs(gaze_point[0] - pos[0])) rysamples.append(abs(gaze_point[1] - pos[1])) # calculate mean deviation lxacc.append(self._mean(lxsamples)) lyacc.append(self._mean(lysamples)) rxacc.append(self._mean(rxsamples)) ryacc.append(self._mean(rysamples)) # wait for a bit to slow down validation process a bit time.sleep(1) # calculate mean accuracy self.pxaccuracy = [(self._mean(lxacc), self._mean(lyacc)), (self._mean(rxacc), self._mean(ryacc))] # sample rate # calculate intersample times timestamps = [] gaze_samples = self.gaze_data for i in range(0, len(gaze_samples) - 1): next_sample = gaze_samples[i + 1]['system_time_stamp'] current_sample = gaze_samples[i]['system_time_stamp'] timestamps.append((next_sample - current_sample) / 1000.0) # mean intersample time self.sampletime = self._mean(timestamps) self.samplerate = int(1000.0 / self.sampletime) # # # # # # # # RMS noise # # present instructions self.screen.clear() self.screen.draw_text( text= "Noise calibration: please look at the dot\n\n(press space to start)", pos=(self.disp.dispsize[0] / 2, int(self.disp.dispsize[1] * 0.2)), colour=(255, 255, 255), fontsize=20) self.screen.draw_fixation(fixtype='dot', colour=(255, 255, 255)) self.disp.fill(self.screen) self.disp.show() # # wait for spacepress self.kb.get_key(keylist=['space'], flush=True, timeout=None) # # show fixation self.screen.draw_fixation(fixtype='dot', colour=(255, 255, 255)) self.disp.fill(self.screen) self.disp.show() self.screen.clear() # # wait for a bit, to allow participant to fixate time.sleep(1) # # get samples # samplelist, prefilled with 1 sample to prevent sl[-1] from producing an error # first sample will be ignored for RMS calculation sl = [self.sample()] t0 = self.millis() # starting time while self.millis() - t0 < 1000: s = self.sample() # sample if s != sl[-1] and self.is_valid_sample(s) and s != (0, 0): sl.append(s) # # calculate RMS noise Xvar, Yvar = [], [] for i in range(2, len(sl)): Xvar.append((sl[i][0] - sl[i - 1][0])**2) Yvar.append((sl[i][1] - sl[i - 1][1])**2) XRMS = (self._mean(Xvar))**0.5 YRMS = (self._mean(Yvar))**0.5 self.pxdsttresh = (XRMS, YRMS) # # # # # # # # # # calibration report # # # # recalculate thresholds (degrees to pixels) self.pxfixtresh = self._deg2pix(self.screendist, self.fixtresh, self.pixpercm) # in pixels per millisecons self.pxspdtresh = self._deg2pix(self.screendist, self.spdtresh / 1000.0, self.pixpercm) # in pixels per millisecond**2 self.pxacctresh = self._deg2pix(self.screendist, self.accthresh / 1000.0, self.pixpercm) data_to_write = '' data_to_write += "pygaze calibration report start\n" data_to_write += "samplerate: %s Hz\n" % self.samplerate data_to_write += "sampletime: %s ms\n" % self.sampletime data_to_write += "accuracy (in pixels): LX=%s, LY=%s, RX=%s, RY=%s\n" % ( self.pxaccuracy[0][0], self.pxaccuracy[0][1], self.pxaccuracy[1][0], self.pxaccuracy[1][1]) data_to_write += "precision (RMS noise in pixels): X=%s, Y=%s\n" % ( self.pxdsttresh[0], self.pxdsttresh[1]) data_to_write += "fixation threshold: %s pixels\n" % self.pxfixtresh data_to_write += "speed threshold: %s pixels/ms\n" % self.pxspdtresh data_to_write += "accuracy threshold: %s pixels/ms**2\n" % self.pxacctresh data_to_write += "pygaze calibration report end\n" self.screen.clear() self.screen.draw_text(text=data_to_write, pos=(self.disp.dispsize[0] / 2, int(self.disp.dispsize[1] / 2)), colour=(255, 255, 255), fontsize=20) self.disp.fill(self.screen) self.disp.show() self.kb.get_key(keylist=['space'], flush=True, timeout=None) self.stop_recording() self.disp.close() return True
def calibrate_start(self): self.calibration = tr.ScreenBasedCalibration(self.eyetracker) self.calibration.enter_calibration_mode()
def calibrate(self, eventlog, calibrate=True): """Calibrates the eye tracker with custom child-friendly screens. arguments eventlog -- logfile instance keyword arguments calibrate -- Boolean indicating if calibration should be performed (default = True). returns success -- nowt, but a calibration log is added to the log file and some properties are updated (i.e. the thresholds for detection algorithms) """ # # # #calculate thresholds (degrees to pixels) # NOT USED self.pxfixtresh = self._deg2pix(self.screendist, self.fixtresh, self.pixpercm) # in pixels per millisecons self.pxspdtresh = self._deg2pix(self.screendist, self.spdtresh / 1000.0, self.pixpercm) # in pixels per millisecond**2 self.pxacctresh = self._deg2pix(self.screendist, self.accthresh / 1000.0, self.pixpercm) # calibration image file calibImg = c.CALIBIMG # initialize a sound snd = sound.Sound(value=c.CALIBSOUNDFILE) snd.setVolume(0.5) # image scaling range bit = 0.02 scale_range = ([x / 100.0 for x in range(60, 30, -2)] + [x / 100.0 for x in range(30, 60, 2)]) if calibrate: if not self.eyetracker: print( "WARNING! libtobii.TobiiProTracker.calibrate: no eye trackers found for the calibration!" ) self.stop_recording() return False # Tobii calibration object calibration = tr.ScreenBasedCalibration(self.eyetracker) calibrating = True calibration.enter_calibration_mode() while calibrating: eventlog.write(["Calibration started at ", clock.get_time()]) # original (normalised) points_to_calibrate = [(0.5, 0.5), (0.9, 0.1), (0.1, 0.1), (0.9, 0.9), (0.1, 0.9)] # pixel values are calculated ( based on the normalised points, with (1920,1200) (see __init__). # self.points_to_calibrate calculated values: [(960, 600), (192, 1080), (192, 120), (1728, 1080), (1728, 120)] # calibration for all calibration points for i in range(0, len(self.points_to_calibrate)): point = self.points_to_calibrate[i] eventlog.write([ "\nCalibrating point {0} at: ".format(point), clock.get_time() ]) # print "----------> Calibrating at point ", point # play the soundfile snd.play() # shrink scale = 1 for frameN in range( 20): # 20 frames -> 1/3 sec shrinking (180 to 108) self.c_screen.clear() self.c_screen.draw_image(calibImg, pos=point, scale=scale) drawCoreImage(self.c_screen, point, i) self.disp.fill(self.c_screen) self.disp.show() scale = scale - bit # grow and shrink until 'space' is pressed s = 0 for frameN in range( 12000 ): # scale down from 108 to 54, (15 frames) and back up, according to scale_range list s = frameN % 30 scale = scale_range[s] self.c_screen.clear() self.c_screen.draw_image(calibImg, pos=point, scale=scale) drawCoreImage(self.c_screen, point, i) self.disp.fill(self.c_screen) self.disp.show() if self.kb.get_key(keylist=['space'], timeout=10, flush=False)[0] == 'space': break # collect results for point (Tobii) normalized_point = self._px_2_norm(point) collect_result = calibration.collect_data( normalized_point[0], normalized_point[1]) eventlog.write([ "Collecting result for point {0} at: ".format(point), clock.get_time() ]) if collect_result != tr.CALIBRATION_STATUS_SUCCESS: eventlog.write([ "Recollecting result for point {0} at: ".format( point), clock.get_time() ]) # Try again if it didn't go well the first time. # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply. calibration.collect_data(normalized_point[0], normalized_point[1]) # grow back to original size up_scale = [ x / 100.0 for x in range(int(scale * 100), 100, 2) ] for scale in up_scale: self.c_screen.clear() self.c_screen.draw_image(calibImg, pos=point, scale=scale) drawCoreImage(self.c_screen, point, i) self.disp.fill(self.c_screen) self.disp.show() # image rolling to next point # pixelised self.points_to_calibrate = [(960, 600), (192, 1080), (192, 120), (1728, 1080), (1728, 120)] if (i < len(self.points_to_calibrate) - 1): """ screen ratio: 16/10 -> the steps for moving the images should be (16, 10) or (8, 5) """ # center -> bottom left / (960, 600) -> (192, 1080) - 48 frames while point[0] >= self.points_to_calibrate[i + 1][0]: self.c_screen.clear() point = (point[0] - 16, point[1] + 10) self.c_screen.draw_image(calibImg, pos=point) self.disp.fill(self.c_screen) self.disp.show() # bottom-left -> top-left / (192, 1080) -> (192, 120) # AND # bottom-right -> top-right / (1728, 1080) -> (1728, 120) - 80 frames while point[1] > self.points_to_calibrate[i + 1][1]: self.c_screen.clear() point = (point[0], point[1] - 12) self.c_screen.draw_image(calibImg, pos=point) self.disp.fill(self.c_screen) self.disp.show() # top-left -> bottom-right / (192, 120) -> (1728, 1080) - 96 frames while point[0] < self.points_to_calibrate[ i + 1][0] and not point[ 1] == self.points_to_calibrate[i + 1][1]: self.c_screen.clear() point = (point[0] + 16, point[1] + 10) self.c_screen.draw_image(calibImg, pos=point) self.disp.fill(self.c_screen) self.disp.show() # Tobii calibration_result = calibration.compute_and_apply() eventlog.write([ "\nCompute and apply returned {0} and collected at {1} points.\n" .format(calibration_result.status, len(calibration_result.calibration_points)) ]) print("\tCalibration: {0} - collected at {1} points.".format( calibration_result.status, len(calibration_result.calibration_points))) # Post-calibration image (while control monitor shows calibration results) self.c_screen.clear() self.c_screen.draw_image(c.ATT_IMG) self.disp.fill(self.c_screen) self.disp.show() if calibration_result.status != tr.CALIBRATION_STATUS_SUCCESS: eventlog.write([ "\n\nWARNING! libtobii.TobiiProTracker.calibrate: Calibration was unsuccessful!\n\n" ]) print("""\tCalibration was unsuccessful.\n ->Press 'R' to recalibrate all points ->or 'SPACE' to continue without calibration\n""") key = self.kb.get_key(keylist=['space', 'r'], timeout=None)[0] if key == 'r': recalibration_points = [0] elif key == 'space': recalibration_points = [] else: # call showCalibrationResults function to present the results on screen 0. The function returns a list of recalibration points logfile_dir = os.path.dirname( os.path.abspath(self.datafilepath)) recalibration_points = showCalibrationResults( logfile_dir, calibration_result) # if the list is empty, calibration is finished if len(recalibration_points) == 0: eventlog.write( ["\nCalibration finished at ", clock.get_time()]) calibrating = False # if the list contains only '0', the calibration was unsuccessful, relalibrate all points elif (recalibration_points[0] == 0): eventlog.write(["\nRecalibrating all points..."]) calibrating = True # if the list contains only '1', recalibrate all points despite successful calibration elif (recalibration_points[0] == 1): eventlog.write(["\nRecalibrating all points..."]) for point in self.points_to_calibrate: calibration.discard_data(point[0], point[1]) calibrating = True # relalibrate the returned points else: eventlog.write([ "\nRecalibrating {0} points...".format( len(recalibration_points)) ]) self.points_to_calibrate = [ self._norm_2_px(p) for p in recalibration_points ] for point in self.points_to_calibrate: calibration.discard_data(point[0], point[1]) calibrating = True calibration.leave_calibration_mode() eventlog.write([" Leaving calibration mode...", clock.get_time()]) self.stop_recording() self._write_enabled = True self.disp.close() # leaving pygaze display
import time import tobii_research as tr import tkinter as tk import random import os import sys # Connection eyetracker found_eyetrackers = tr.find_all_eyetrackers() eyetracker = found_eyetrackers[0] calibration = tr.ScreenBasedCalibration(eyetracker) # Enter calibration mode. calibration.enter_calibration_mode() print "Entered calibration mode for eye tracker with serial number {0}.".format( eyetracker.serial_number) # Define the points on screen we should calibrate at. # The coordinates are normalized, i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner. points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)] for point in points_to_calibrate: time.sleep(1) print "Show a point on screen at {0}.".format(point) print "Collecting data at {0}.".format(point) if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS: # Try again if it didn't go well the first time. # Not all eye tracker models will fail at this point, but instead fail on ComputeAndApply.
def newScreenCalibration(self): if self._eyetracker: return tobii_research.ScreenBasedCalibration(self._eyetracker)
def phase06_calibration(): button_quit.autoDraw = False calibration = tr.ScreenBasedCalibration(eyetracker) # Enter calibration mode. calibration.enter_calibration_mode() print(f"Entered calibration mode for eye tracker with serial number {eyetracker.serial_number}.") # Define the points on screen # Normalized coordinates! i.e. (0.0, 0.0) is the upper left corner and (1.0, 1.0) is the lower right corner. points_to_calibrate = [(0.5, 0.5), (0.1, 0.1), (0.1, 0.9), (0.9, 0.1), (0.9, 0.9)] points_to_calibrate_psySpace = toPPnorm(np.array(points_to_calibrate)) fixDisc = visual.ImageStim(win, os.path.join(cfg.stimDir, 'fixationDisc.png'), size=[.01, .01*win.aspect]) win.flip() for point_idx in range(len(points_to_calibrate)): point = points_to_calibrate[point_idx] point_psy = points_to_calibrate_psySpace[point_idx] print(f"Show a point on screen at {point}") for i in range(1,150): scalingFactor = .98 fixDisc.size *= [1/scalingFactor,1/scalingFactor] fixDisc.draw() win.flip() time.sleep(.01) for i in range(1,150): fixDisc.size *= [scalingFactor,scalingFactor] now = np.array(fixDisc.pos) tarPos = np.array(point_psy) fixDisc.pos += tuple((tarPos-now)*i/149) fixDisc.draw() win.flip() time.sleep(.01) # let user focus time.sleep(.5) print("Collecting data at {0}.".format(point)) if calibration.collect_data(point[0], point[1]) != tr.CALIBRATION_STATUS_SUCCESS: print('not successfull, trying a second time') # Tobii API suggests to try again if it didn't go well the first time. calibration.collect_data(point[0], point[1]) calibration_result = calibration.compute_and_apply() print(f"Computed and applied calibration: returned {calibration_result.status} and \ collected at {len(calibration_result.calibration_points)} points.") # here or later after validation we could think of running points through calibration.discard_data(x,y) # The calibration done calibration.leave_calibration_mode() updatePhase()
def calibrate(): global tracker root = Tk() calibrator = tobii_research.ScreenBasedCalibration(tracker) calibrator.enter_calibration_mode() calibration_points = [(.1, .1), (.9, .1), (.1, .9), (.9, .9), (.1, .5), (.9, .5), (.5, .1), (.5, .9), (.5, .5)] random.shuffle(calibration_points) root.overrideredirect(1) root.geometry("%dx%d+0+0" % (width, height)) root.focus_set() # <-- move focus to this widget root.bind("<Escape>", lambda e: e.widget.quit()) canvas = Canvas(root, width=width, height=height, scrollregion=(0, 0, width, height)) canvas.pack() canvas.create_text(width / 2, height / 2, text="Calibration is about to begin.", font=('Times', '28')) root.update_idletasks() root.update() time.sleep(5) canvas.delete("all") for pos in calibration_points: x, y = pos point = canvas.create_oval(x * width - 10, y * height - 10, x * width + 10, y * height + 10, fill="blue") root.update_idletasks() root.update() print(x, y) time.sleep(.7) if calibrator.collect_data( x, y) != tobii_research.CALIBRATION_STATUS_SUCCESS: # Try again if first try was not successful. calibrator.collect_data(x, y) canvas.delete(point) canvas.create_text(width / 2, height / 2, text="Calibration finished. Please wait for results.", font=('Times', '28')) root.update_idletasks() root.update() calibration_result = calibrator.compute_and_apply() print("Compute and apply returned %s and collected at %s points" % (calibration_result.status, len( calibration_result.calibration_points))) if calibration_result.status == tobii_research.CALIBRATION_STATUS_SUCCESS: w = QMessageBox(QMessageBox.Information, "Calibration Result", "Calibration successful!") w.exec_() calibrator.leave_calibration_mode() root.destroy()