class Application(tk.Frame): analyzer = gda.GazeDataAnalyzer() session_path = "session_data/" + datetime.datetime.now().strftime( "%Y-%m-%d %H.%M.%S") + "/" config_filename = session_path + "config.csv" test_folder = None def __init__(self, master=None): tk.Frame.__init__(self, master) self.master = master # Get width and height of screen self.screen_width = self.master.winfo_screenwidth() self.screen_height = self.master.winfo_screenheight() self.screen_size_inches = 27 self.pack(fill="both", expand=True) # Initialize tobii_controller with configurations self.controller = tobii_controller(self.screen_width, self.screen_height) self.controller.subscribe_dict() self.status_admin_process = Process( target=self.controller.show_status_admin(screen=0)) self.status_admin_process.start() self.controller.show_status(screen=1) try: os.makedirs(self.session_path) except Exception: # directory already exists pass self.config_setup() def config_setup(self): self.panel_config = tk.Frame(self) fields = ["Age (Months)", "Sex", "Distance to screen (cm)"] values = ["12", "M", "60"] entries = [] for field, value in zip(fields, values): row = tk.Frame(self.panel_config) label = tk.Label(row, width=20, text=field, anchor='w') entry = tk.Entry(row) entry.insert(tk.END, value) row.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5) label.pack(side=tk.LEFT) entry.pack(side=tk.RIGHT, expand=True, fill=tk.X) entries.append((field, entry)) btn_config_save = tk.Button(self.panel_config) btn_config_save["text"] = "Save configuration" btn_config_save["fg"] = "black" btn_config_save["bg"] = "#b2b2b2" btn_config_save["command"] = lambda e=entries: self.config_save(e) btn_config_save.pack(side=tk.LEFT, padx=5, pady=10) self.panel_config.pack(side=tk.TOP, pady=(10, 10)) def config_save(self, entries): # PYTHON 2.x with open(self.config_filename, mode='wb') as csv_file: field_names = [row[0] for row in entries] entry_texts = [row[1].get() for row in entries] field_names.extend([ "Screen size (inches)", "Screen width (px)", "Screen height (px)" ]) entry_texts.extend([ self.screen_size_inches, self.screen_width, self.screen_height ]) config_writer = csv.DictWriter(csv_file, fieldnames=field_names, delimiter=";") config_writer.writeheader() config_dict = {} for f, e in zip(field_names, entry_texts): config_dict[f] = e config_writer.writerow(config_dict) self.controller.set_dist_to_screen( config_dict["Distance to screen (cm)"]) print("Configurations saved") self.panel_config.pack_forget() self.show_main_panel() def show_main_panel(self): self.btn_test = tk.Button(self) self.btn_test["text"] = "TEST" self.btn_test["fg"] = "white" self.btn_test["bg"] = "#000000" self.btn_test["command"] = self.test self.btn_test.pack(side=tk.TOP, pady=(0, 10)) self.btn_test1 = tk.Button(self) self.btn_test1["text"] = "TEST - Fixation" self.btn_test1["fg"] = "white" self.btn_test1["bg"] = "#000000" self.btn_test1["command"] = self.test_fixation self.btn_test1.pack(side=tk.TOP, pady=(0, 10)) self.btn_test2 = tk.Button(self) self.btn_test2["text"] = "TEST - Pursuit (linear)" self.btn_test2["fg"] = "white" self.btn_test2["bg"] = "#000000" self.btn_test2["command"] = lambda t="linear": self.test_pursuit(t) self.btn_test2.pack(side=tk.TOP, pady=(0, 10)) self.btn_test3 = tk.Button(self) self.btn_test3["text"] = "TEST - Pursuit (spiral)" self.btn_test3["fg"] = "white" self.btn_test3["bg"] = "#000000" self.btn_test2["command"] = lambda t="spiral": self.test_pursuit(t) self.btn_test3.pack(side=tk.TOP, pady=(0, 10)) self.btn_default_test = self.make_test_button("Test default", "default") self.btn_2p_test = self.make_test_button("Test 2-point", "custom_2p") self.btn_5p_test = self.make_test_button("Test 5-point", "custom_5p") self.btn_5p_img_test = self.make_test_button("Test 5-point (image)", "custom_5p_img") self.btn_show_status = tk.Button(self) self.btn_show_status["text"] = "Check eye position" self.btn_show_status["fg"] = "white" self.btn_show_status["bg"] = "#2196F3" self.btn_show_status["command"] = self.show_status self.btn_shutdown = tk.Button(self) self.btn_shutdown["text"] = "Shutdown" self.btn_shutdown["fg"] = "white" self.btn_shutdown["bg"] = "#f44336" self.btn_shutdown["command"] = self.client_exit # pack it all self.btn_default_test.pack(side=tk.TOP, pady=(10, 10)) self.btn_2p_test.pack(side=tk.TOP, pady=(0, 10)) self.btn_5p_test.pack(side=tk.TOP, pady=(0, 10)) self.btn_5p_img_test.pack(side=tk.TOP, pady=(0, 10)) self.btn_show_status.pack(side=tk.TOP, pady=(0, 10)) self.btn_shutdown.pack(side=tk.TOP) def test(self): self.controller.make_psycho_window() self.custom_calibration(5, "img") self.controller.close_psycho_window() def test_fixation(self): self.controller.make_psycho_window() # self.controller.start_fixation_exercise(positions=[(-0.5,-0.5), (0.5,-0.5), (-0.5, 0.5), (0.5, 0.5), (0.0, 0.0)], stimuli_paths=["stimuli/star_yellow.png"]) self.controller.start_fixation_exercise_animate_transition( positions=[(-0.5, -0.5), (0.5, -0.5), (-0.5, 0.5), (0.5, 0.5), (0.0, 0.0)], stimuli_paths=["stimuli/star_yellow.png"]) self.controller.close_psycho_window() def test_pursuit(self, path_type): self.controller.make_psycho_window() # if path_type == "linear": # self.controller.start_pursuit_exercise(pathing="linear", positions=[(-0.5,-0.5), (0.3, 0.5), (0.5, -0.5), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"]) # elif path_type == "spiral": # self.controller.start_pursuit_exercise(pathing="spiral", positions=[(-0.7,0.0), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"]) self.controller.start_pursuit_exercise( pathing="linear", positions=[(-0.5, -0.5), (0.3, 0.5), (0.5, -0.5), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"]) self.controller.close_psycho_window() def test_pursuit_horizontal(self): self.controller.make_psycho_window() self.controller.start_pursuit_exercise( pathing="linear", positions=[(-0.85, -0.5), (-0.5, 0.7), (0.0, 0.7), (0.1, -0.7), (0.6, -0.7), (0.85, 0.5)], stimuli_paths=["stimuli/smiley_yellow.png"]) self.controller.close_psycho_window() def make_test_button(self, title, cal_type): btn = tk.Button(self) btn["text"] = title btn["fg"] = "white" btn["bg"] = "#4CAF50" btn["command"] = lambda t=cal_type: self.run_test(t) return btn def run_test(self, cal_type): self.controller.make_psycho_window() self.test_folder = "test_" + cal_type + "/" self.controller.play_sound() self.controller.flash_screen() if cal_type == "default": pass elif cal_type == "custom_2p": self.custom_calibration(2, "img") elif cal_type == "custom_5p": self.custom_calibration(5, "img") elif cal_type == "custom_5p_img": self.custom_calibration(5, "img") self.controller.start_fixation_exercise_animate_transition( positions=[(-0.5, -0.5), (0.5, -0.5), (-0.5, 0.5), (0.5, 0.5), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"]) self.store_data("training_fixation") # self.controller.flash_screen() # self.controller.start_fixation_exercise(positions=[(-0.5,-0.5), (0.5,-0.5), (-0.5, 0.5), (0.5, 0.5), (0.0, 0.0)], stimuli_paths=["stimuli/star_yellow.png"]) # self.controller.start_fixation_exercise_animate_transition(positions=[(-0.8,-0.8), (-0.8,-0.4), (-0.8, 0.0), (-0.8, 0.4), (-0.8, 0.8), (-0.4,-0.8), (-0.4,-0.4), (-0.4, 0.0), (-0.4, 0.4), (-0.4, 0.8), (0.0,-0.8), (0.0,-0.4), (0.0, 0.0), (0.0, 0.4), (0.4, 0.8), (0.4,-0.8), (0.4,-0.4), (0.4, 0.0), (0.4, 0.4), (0.4, 0.8), (0.8,-0.8), (0.8,-0.4), (0.8, 0.0), (0.8, 0.4), (0.8, 0.8)], stimuli_paths=["stimuli/star_yellow.png"], fixation_duration = 1.5) # self.store_data("training_fixation_2") self.controller.start_pursuit_exercise( pathing="circle", positions=[(-0.7, 0.0), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"]) self.store_data("training_pursuit_circle") self.controller.start_pursuit_exercise( pathing="circle", positions=[(-0.7, 0.0), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"], reverse=True) self.store_data("training_pursuit_circle_revert") positions = [(-0.7, 0.0), (0.0, 0.0)] pos = [] for p in positions: pos.append(self.controller.get_tobii_pos(p)) print(pos) # self.controller.flash_screen() self.controller.start_pursuit_exercise( pathing="linear", positions=[(-0.5, -0.5), (0.3, 0.5), (0.5, -0.5), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"]) # self.controller.start_pursuit_exercise(pathing="linear", positions=[(-0.85,-0.5), (-0.5, 0.7), (0.0, 0.7), (0.1, -0.7), (0.6, -0.7), (0.85, 0.5)], stimuli_paths=["stimuli/smiley_yellow.png"]) self.store_data("training_pursuit_linear") # self.controller.flash_screen() self.controller.start_pursuit_exercise( pathing="spiral", positions=[(-0.7, 0.0), (0.0, 0.0)], stimuli_paths=["stimuli/smiley_yellow.png"]) self.store_data("training_pursuit_spiral") self.controller.pause_sound() self.controller.close_psycho_window(screen=1) def show_status(self, screen=1): self.controller.show_status(screen=screen) def custom_calibration(self, num_points, stim_type="default"): # we can only check if there is an existing eye tracking device. # this will still fail whenever the device is there but turned off # TobiiProSDK does not support activity checks this for python it seems.. self.controller.start_custom_calibration(num_points, stim_type=stim_type) def store_data(self, testname): # write data to file try: # just in case we run exercise before calibration os.makedirs(self.session_path + self.test_folder) except Exception: # directory already exists pass filename = self.session_path + self.test_folder + testname + ".csv" # PYTHON 2.x with open(filename, mode='wb') as gaze_data_file: field_names = [data for data in self.controller.gaze_params] gaze_data_writer = csv.DictWriter(gaze_data_file, fieldnames=field_names, delimiter=";") gaze_data_writer.writeheader() for gaze_data in self.controller.global_gaze_data: gaze_data_writer.writerow(gaze_data) def client_exit(self): print("Shutting down") self.controller.unsubscribe_dict() self.quit()
class Application(tk.Frame): analyzer = gda.GazeDataAnalyzer() session_path = "session_data/" + datetime.datetime.now().strftime( "%Y-%m-%d %H.%M.%S/") cal_file_index = 0 training_file_index = 0 config_filename = session_path + "config.csv" cal_path = session_path + "calibrations/" def __init__(self, master=None): tk.Frame.__init__(self, master) self.master = master # Get width and height of screen self.screen_width = self.master.winfo_screenwidth() self.screen_height = self.master.winfo_screenheight() self.pack(fill="both", expand=True) self.create_widgets() # Initialize tobii_controller with configurations self.controller = tobii_controller(self.screen_width, self.screen_height) self.controller.show_status() try: os.makedirs(self.cal_path) except Exception: # directory already exists pass def create_widgets(self): config_fields = [ "Age (Months)", "Sex", "Severity (1-5)", "Screen size (inches)", "Distance to screen (cm)" ] config_values = ["12", "M", "1", "27", "60"] self.config_panel = tk.Frame(self) self.config_setup(self.config_panel, config_fields, config_values) self.config_panel.pack(side=tk.TOP, pady=(self.screen_height / 2, 0)) self.calibrate_button = tk.Button(self) self.calibrate_button["text"] = "Make transformation" self.calibrate_button["fg"] = "white" self.calibrate_button["bg"] = "#FFA500" self.calibrate_button["command"] = self.start_calibration_exercise self.training_fixation_button = tk.Button(self) self.training_fixation_button["text"] = "Start fixation exercise" self.training_fixation_button["fg"] = "white" self.training_fixation_button["bg"] = "#4CAF50" self.training_fixation_button[ "command"] = lambda training_type="fixation": self.training_exercise( training_type) self.training_pursuit_button = tk.Button(self) self.training_pursuit_button["text"] = "Start pursuit exercise" self.training_pursuit_button["fg"] = "white" self.training_pursuit_button["bg"] = "#4CAF50" self.training_pursuit_button[ "command"] = lambda training_type="pursuit": self.training_exercise( training_type) self.custom_cal_2_button = tk.Button(self) self.custom_cal_2_button["text"] = "Custom 2p calibration" self.custom_cal_2_button["fg"] = "white" self.custom_cal_2_button["bg"] = "#2196F3" self.custom_cal_2_button[ "command"] = lambda n=2: self.custom_calibration(n) self.custom_cal_5_button = tk.Button(self) self.custom_cal_5_button["text"] = "Custom 5p calibration" self.custom_cal_5_button["fg"] = "white" self.custom_cal_5_button["bg"] = "#2196F3" self.custom_cal_5_button[ "command"] = lambda n=5: self.custom_calibration(n) self.eye_pos_button = tk.Button(self) self.eye_pos_button["text"] = "Check eye position" self.eye_pos_button["fg"] = "white" self.eye_pos_button["bg"] = "#2196F3" self.eye_pos_button["command"] = self.check_eye_position self.shutdown_button = tk.Button(self) self.shutdown_button["text"] = "Shutdown" self.shutdown_button["fg"] = "white" self.shutdown_button["bg"] = "#f44336" self.shutdown_button["command"] = self.client_exit def config_setup(self, root, fields, values): entries = [] for field, value in zip(fields, values): row = tk.Frame(root) label = tk.Label(row, width=15, text=field, anchor='w') entry = tk.Entry(row) entry.insert(tk.END, value) row.pack(side=tk.TOP, fill=tk.X, padx=5, pady=5) label.pack(side=tk.LEFT) entry.pack(side=tk.RIGHT, expand=True, fill=tk.X) entries.append((field, entry)) btn_config_save = tk.Button(root) btn_config_save["text"] = "Save configuration" btn_config_save["fg"] = "black" btn_config_save["bg"] = "#b2b2b2" btn_config_save["command"] = lambda e=entries: self.config_save(e) btn_config_save.pack(side=tk.LEFT, padx=5, pady=10) def config_save(self, entries): # PYTHON 2.x with open(self.config_filename, mode='wb') as csv_file: field_names = [row[0] for row in entries] entry_texts = [row[1].get() for row in entries] field_names.extend(["Screen width (px)", "Screen height (px)"]) entry_texts.extend([self.screen_width, self.screen_height]) config_writer = csv.DictWriter(csv_file, fieldnames=field_names, delimiter=";") config_writer.writeheader() self.config_dict = {} for f, e in zip(field_names, entry_texts): self.config_dict[f] = e config_writer.writerow(self.config_dict) print("Configurations saved") self.config_panel.pack_forget() self.show_main_panel() self.controller.set_dist_to_screen( self.config_dict["Distance to screen (cm)"]) def show_main_panel(self): self.calibrate_button.pack(side=tk.TOP, pady=(self.screen_height / 2 - 50, 10)) self.training_fixation_button.pack(side=tk.TOP, pady=(0, 10)) self.training_pursuit_button.pack(side=tk.TOP, pady=(0, 10)) self.custom_cal_2_button.pack(side=tk.TOP, pady=(0, 10)) self.custom_cal_5_button.pack(side=tk.TOP, pady=(0, 10)) self.eye_pos_button.pack(side=tk.TOP, pady=(0, 10)) self.shutdown_button.pack(side=tk.TOP) def hide_main_panel(self): self.shutdown_button.pack_forget() self.calibrate_button.pack_forget() self.training_pursuit_button.pack_forget() self.training_fixation_button.pack_forget() self.custom_cal_2_button.pack_forget() self.custom_cal_5_button.pack_forget() self.eye_pos_button.pack_forget() def check_eye_position(self): self.controller.show_status() def training_exercise(self, training_type="fixation"): # Start eye traking if training_type == "fixation": self.controller.start_fixation_exercise() elif training_type == "pursuit": self.controller.start_pursuit_exercise(pathing="spiral") # def training_exercise(self): # print("Simulation ended") # # # Stop eye tracking # if self.controller.eyetracker != None: # pass # self.eye_tracking.end_gaze_tracking() # # self.training_file_index = self.training_file_index + 1 # # training_filename = self.session_path + "training_with_cal_" + str(self.cal_file_index) + "/training_" + str(self.training_file_index) + ".csv" # # # PYTHON 2.x # with open(training_filename, mode='wb') as gaze_data_file: # # field_names = [data for data in self.eye_tracking.gaze_params] # gaze_data_writer = csv.DictWriter(gaze_data_file, fieldnames=field_names, delimiter=";") # # gaze_data_writer.writeheader() # for gaze_data in self.eye_tracking.global_gaze_data: # gaze_data_writer.writerow(gaze_data) # # try: # self.analyzer.analyze(training_filename) # except: # print("Bad data obtained") # Hide canvas # Show button after exercise #self.show_main_panel() def start_calibration_exercise(self): self.controller.make_transformation() def custom_calibration(self, num_points): # we can only check if there is an existing eye tracking device. # this will still fail whenever the device is there but turned off # TobiiProSDK does not support activity checks this for python it seems.. self.controller.start_custom_calibration(num_points) def client_exit(self): print("Shutting down") self.quit()
# Run analyse on type_of_cal = "default" #type_of_cal = "custom_2p" #type_of_cal = "custom_5p" # Session to run session_folder = "ctrl_group_2_louise" #session_folder = "infant_d25_gudrun_5m" # Setting path and files session_path = "session_data/" + session_folder + "/" test_folder = session_path + "test_" + type_of_cal + "/" config_filename = session_path + "config.csv" training_filename = test_folder + "training_fixation.csv" analyzer = gda.GazeDataAnalyzer() print("\nSimulate cross validation") analyzer.cross_validation(config_filename, training_filename, "dbscan_fixation", k=5) #print("\nTEST DATA - FIXATION") #training_filename = test_folder + "training_fixation.csv" #analyzer.analyze(training_filename, "dbscan_fixation", "values") # #print("\nTEST DATA - PURSUIT (CIRCLE)") #training_filename = test_folder + "training_pursuit_circle.csv" #analyzer.analyze(training_filename, "dbscan_pursuit", "values") #
def analyze(session_folder): try: print("Running for " + session_folder) print("------------------------") # Setting path and files session_path = "session_data/" + session_folder + "/" test_folder = session_path + "test_" + type_of_cal + "/" config_filename = session_path + "config.csv" # cal_filename = test_folder + "training_fixation.csv" cal_filename = test_folder + "training_fixation_2.csv" # cal_filename = test_folder + "training_pursuit_circle.csv" # cal_filename = test_folder + "training_pursuit_linear.csv" # cal_filename = test_folder + "training_pursuit_spiral.csv" # remove_outliers = True remove_outliers = False print("") print("Computing analyze linear transformation") print("------------------------") analyzer = gda.GazeDataAnalyzer() print("\nSETUP TRANSFORMATION") # analyzer.cross_validation(config_filename, cal_filename, "dbscan_fixation", k = 2) # analyzer.cross_validation(config_filename, cal_filename, "dbscan_pursuit", k = 5) analyzer.setup_affine2(config_filename, cal_filename, "dbscan_fixation") # analyzer.setup_affine2(config_filename, cal_filename, "dbscan_pursuit") # print("\nTRAINING DATA") # analyzer.analyze(cal_filename, "dbscan_fixation") try: print("\nTEST DATA - FIXATION") training_filename = test_folder + "training_fixation.csv" angle_avg, angle_avg_corrected = analyzer.analyze_affine2( training_filename, "dbscan_fixation", "values", remove_outliers=remove_outliers) # if len(angle_avg) < (5*90*0.3): # raise ValueError('Not enough data') fixation_deg_raw.append(np.mean(angle_avg)) fixation_deg_cor.append(np.mean(angle_avg_corrected)) except: print("-----------------------------") print("SKIPPING FIXATION") print("-----------------------------") fixation_deg_raw.append(0) fixation_deg_cor.append(0) try: print("\nTEST DATA - FIXATION_2") training_filename = test_folder + "training_fixation_2.csv" angle_avg, angle_avg_corrected = analyzer.analyze_affine2( training_filename, "dbscan_fixation", "values", remove_outliers=remove_outliers) # if len(angle_avg) < (5*90*0.3): # raise ValueError('Not enough data') fixation_2_deg_raw.append(np.mean(angle_avg)) fixation_2_deg_cor.append(np.mean(angle_avg_corrected)) except: print("-----------------------------") print("SKIPPING FIXATION 2") print("-----------------------------") fixation_2_deg_raw.append(0) fixation_2_deg_cor.append(0) try: print("\nTEST DATA - PURSUIT (CIRCLE)") training_filename = test_folder + "training_pursuit_circle.csv" angle_avg, angle_avg_corrected = analyzer.analyze_affine2( training_filename, "dbscan_pursuit", "values", remove_outliers=remove_outliers) # if len(angle_avg) < (5*90*0.3): # raise ValueError('Not enough data') pursuit_circle_deg_raw.append(np.mean(angle_avg)) pursuit_circle_deg_cor.append(np.mean(angle_avg_corrected)) except: print("-----------------------------") print("SKIPPING PURSUIT CIRCLE") print("-----------------------------") pursuit_circle_deg_raw.append(0) pursuit_circle_deg_cor.append(0) try: print("\nTEST DATA - PURSUIT (CIRCLE REVERT)") training_filename = test_folder + "training_pursuit_circle_revert.csv" angle_avg, angle_avg_corrected = analyzer.analyze_affine2( training_filename, "dbscan_pursuit", "values", remove_outliers=remove_outliers) # if len(angle_avg) < (5*90*0.3): # raise ValueError('Not enough data') pursuit_circle_revert_deg_raw.append(np.mean(angle_avg)) pursuit_circle_revert_deg_cor.append(np.mean(angle_avg_corrected)) except: print("-----------------------------") print("SKIPPING PURSUIT CIRCLE REVERT") print("-----------------------------") pursuit_circle_revert_deg_raw.append(0) pursuit_circle_revert_deg_cor.append(0) try: print("\nTEST DATA - PURSUIT (LINEAR)") training_filename = test_folder + "training_pursuit_linear.csv" angle_avg, angle_avg_corrected = analyzer.analyze_affine2( training_filename, "dbscan_pursuit", "values", remove_outliers=remove_outliers) # if len(angle_avg) < (5*90*0.3): # raise ValueError('Not enough data') pursuit_linear_deg_raw.append(np.mean(angle_avg)) pursuit_linear_deg_cor.append(np.mean(angle_avg_corrected)) except: print("-----------------------------") print("SKIPPING PURSUIT LINEAR") print("-----------------------------") pursuit_linear_deg_raw.append(0) pursuit_linear_deg_cor.append(0) try: print("\nTEST DATA - PURSUIT (SPIRAL)") training_filename = test_folder + "training_pursuit_spiral.csv" angle_avg, angle_avg_corrected = analyzer.analyze_affine2( training_filename, "dbscan_pursuit", "values", remove_outliers=remove_outliers) # if len(angle_avg) < (5*90*0.3): # raise ValueError('Not enough data') pursuit_spiral_deg_raw.append(np.mean(angle_avg)) pursuit_spiral_deg_cor.append(np.mean(angle_avg_corrected)) except: print("-----------------------------") print("SKIPPING PURSUIT SPIRAL") print("-----------------------------") pursuit_spiral_deg_raw.append(0) pursuit_spiral_deg_cor.append(0) print("") except: print("-----------------------------") print("SKIPPING " + session_folder) print("-----------------------------")