def get_fixations(df): df = df[df["Type"] == "SMP"] df["Time"] = df["Time"] // 1000 fixations = detectors.fixation_detection( df["L POR X [px]"].to_numpy(), df["L POR Y [px]"].to_numpy(), df["Time"].to_numpy(), maxdist=45, mindur=50, ) entries = [ create_dataframe_entry(*fixation, df) for fixation in fixations[1] ] return pd.DataFrame(entries)
def read_eyetribe(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } starttime = 0 started = False trialend = False # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n', '').replace('\r', '').split('\t') # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[0] == 'MSG' and stop in line[3]) or i == len(raw) - 1: started = False trialend = True # check for new start otherwise else: if start in line or i == len(raw) - 1: started = True trialend = True # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data), len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events'][ 'Eblk'] = blink_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Sfix'], trial['events'][ 'Efix'] = fixation_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) trial['events']['Ssac'], trial['events'][ 'Esac'] = saccade_detection(trial['x'], trial['y'], trial['trackertime'], missing=missing) # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } trialend = False # check if the current line contains start message else: if line[0] == "MSG": if start in line[3]: message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(line[2]) # # # # # # parse line if started: # message lines will start with MSG, followed by a tab, then a # timestamp, a tab, the time, a tab and the message, e.g.: # "MSG\t2014-07-01 17:02:33.770\t853589802\tsomething of importance here" if line[0] == "MSG": t = int(line[2]) # time m = line[3] # message events['msg'].append([t, m]) # regular lines will contain tab separated values, beginning with # a timestamp, follwed by the values that were asked to be stored # in the data file. Usually, this comes down to # timestamp, time, fix, state, rawx, rawy, avgx, avgy, psize, # Lrawx, Lrawy, Lavgx, Lavgy, Lpsize, Lpupilx, Lpupily, # Rrawx, Rrawy, Ravgx, Ravgy, Rpsize, Rpupilx, Rpupily # e.g.: # '2014-07-01 17:02:33.770, 853589802, False, 7, 512.5897, 510.8104, 614.6975, 614.3327, 16.8657, # 523.3592, 475.2756, 511.1529, 492.7412, 16.9398, 0.4037, 0.5209, # 501.8202, 546.3453, 609.3405, 623.2287, 16.7916, 0.5539, 0.5209' else: # see if current line contains relevant data try: # extract data x.append(float(line[6])) y.append(float(line[7])) size.append(float(line[8])) time.append(int(line[1]) - starttime) trackertime.append(int(line[1])) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data
# # # # # # IMAGES if DOIMAGES: # READ DATA imagedata = read_data[trackertype](DATAFILE, "image_on", stop="image_off", missing=0.0, debug=False) # CUSTOM FIXATION DETECTION # calculate maximal inter-sampel distance maxdist = ang2cm(FIXTHRESH, SCREENDIST) * PIXPERCM # overwrite fixations for i in range(len(imagedata)): imagedata[i]['events']['Sfix'], imagedata[i]['events']['Efix'] = \ fixation_detection(imagedata[i]['x'], imagedata[i]['y'], imagedata[i]['trackertime'], missing=0.0, maxdist=maxdist, mindur=FIXMINDUR) # PLOT DATA for i in range(len(imagedata)): # image name imgname = os.path.splitext(os.path.basename(IMAGES[i]))[0] # pickle fixation data fixfile = open(os.path.join(outputdir, "fixations_%s.dat" % imgname), 'w') pickle.dump(imagedata[i]['events']['Efix'], fixfile) fixfile.close() # plot raw data fig = gazeplotter.draw_raw(imagedata[i]['x'], imagedata[i]['y'], DISPSIZE, imagefile=IMAGES[i], savefilename=os.path.join(outputdir, "image_%s_raw.png" % imgname)) pyplot.close(fig) # plot fixations fig = gazeplotter.draw_fixations(imagedata[i]['events']['Efix'], DISPSIZE, imagefile=IMAGES[i], durationsize=True, durationcolour=False, alpha=0.5, savefilename=os.path.join(outputdir, "image_%s_fixations.png" % imgname)) pyplot.close(fig)
def read_tobii(filename, reduced, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions time - numpy array of timestamps events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - list of lists, each containing [starttime] Sblk - EMPTY! list of lists, each containing [starttime] Efix - list of lists, each containing \ [starttime, endtime, duration, endx, endy] Esac - list of lists, each containing \ [starttime, endtime, dur, startx, starty, endx, endy] Eblk - EMPTY! list of lists, each containing [starttime, endtime, dur] msg - list of lists, each containing [time, message] Args: filename - path to the file that has to be read Kwargs: missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) Returns data - a list with a dict for every trial (see above) """ # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # variables data = [] time = [] x = [] y = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } if reduced: limit = 5000 else: limit = len(raw) # loop through all lines for i in range(limit): # string to list line = [float(s) for s in raw[i].replace('\n', '').split(',')] line[0] = line[0] * 1000 # line[1] = line[1] - 1920 # Correcting for display to the left # see if current line contains relevant data try: # extract data time.append(line[0]) x.append(line[1]) y.append(line[2]) except IndexError: message("line '%s' could not be parsed" % line) continue # skip this line message("%d samples found" % (len(raw))) message("plotting %d samples" % (limit)) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['time'] = numpy.array(time) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events']['Eblk'] = blink_detection( trial['x'], trial['y'], trial['time'], missing=missing) trial['events']['Sfix'], trial['events']['Efix'] = fixation_detection( trial['x'], trial['y'], trial['time'], missing=missing) trial['events']['Ssac'], trial['events']['Esac'] = saccade_detection( trial['x'], trial['y'], trial['time'], missing=missing) # add trial to data data.append(trial) return data
def heatMap(startTime, endTime, totalTime): #(in seconds) #start time of video segment you want to extract #end time of video segment you want to extract #total time of video #saveLocation: location where output heatmap is to be saved #gazeFilePath: location of gaze csv #videoLocation: location of video #imageWidth and IimageHeight: dimension of a frame in a video saveLocation = '/Users/jeffhe/Desktop/commitments/urap/resources/heatmap_processing/0308_1630_text_02/heatmap.png' gazeFilePath = "/Users/jeffhe/Desktop/commitments/urap/resources/heatmap_processing/0308_1630_text_02/gaze_positions.csv" videoLocation = "/Users/jeffhe/Desktop/commitments/urap/resources/heatmap_processing/0308_1630_text_02/world.mp4" imageWidth = 1280 imageHeight = 720 def StartTimeSeconds(): with open(gazeFilePath) as f: reader = csv.reader(f) reader = list(reader) startTimeSeconds = float(reader[1][0]) return startTimeSeconds startTimeSeconds = StartTimeSeconds() + startTime endTimeSeconds = StartTimeSeconds() + endTime vidcap = cv2.VideoCapture(videoLocation) frames = [] success, image = vidcap.read() frames += [image] while success: success, image = vidcap.read() frames += [image] startFrame = (startTime / totalTime) * len(frames) endFrame = (endTime / totalTime) * len(frames) image = frames[int((startFrame + endFrame) / 2)] with open(gazeFilePath) as f: reader = csv.reader(f) line_num = 0 norm_pos_x = [] norm_pos_y = [] timeStamps = [] for row in reader: if (line_num != 0): if not (float(row[2]) < 0.5 or float(row[3]) > 1 or float(row[3]) < 0 or float(row[4]) > 1 or float(row[4]) < 0): if (float(row[0]) > startTimeSeconds and float(row[0]) < endTimeSeconds): norm_pos_x += [int(float(row[3]) * 1280)] norm_pos_y += [imageHeight - int(float(row[4]) * 720)] timeStamps += [float(row[0])] line_num += 1 count = 0 while (count < len(timeStamps)): timeStamps[count] *= 1000 count += 1 Sfix, Efix = fixation_detection(norm_pos_x, norm_pos_y, timeStamps) draw_heatmap(Efix, (imageWidth, imageHeight), image, savefilename=saveLocation) #the above function call isn't necessary in Shaantam's case. The fixation data is stored in Efix #in the form of [[start time, end time, duration, x-coordinates, y-coordinates][][]...] #here, the y-coordinate is calculated from top (meaning that top pixel is 0, bottom pixel is 720) return Efix
def read_idf(filename, start, stop=None, missing=0.0, debug=False): """Returns a list with dicts for every trial. A trial dict contains the following keys: x - numpy array of x positions y - numpy array of y positions size - numpy array of pupil size time - numpy array of timestamps, t=0 at trialstart trackertime- numpy array of timestamps, according to the tracker events - dict with the following keys: Sfix - list of lists, each containing [starttime] Ssac - EMPTY! list of lists, each containing [starttime] Sblk - list of lists, each containing [starttime] Efix - list of lists, each containing [starttime, endtime, duration, endx, endy] Esac - EMPTY! list of lists, each containing [starttime, endtime, duration, startx, starty, endx, endy] Eblk - list of lists, each containing [starttime, endtime, duration] msg - list of lists, each containing [time, message] NOTE: timing is in EyeTribe time! arguments filename - path to the file that has to be read start - trial start string keyword arguments stop - trial ending string (default = None) missing - value to be used for missing data (default = 0.0) debug - Boolean indicating if DEBUG mode should be on or off; if DEBUG mode is on, information on what the script currently is doing will be printed to the console (default = False) returns data - a list with a dict for every trial (see above) """ # # # # # # debug mode if debug: def message(msg): print(msg) else: def message(msg): pass # # # # # # file handling # check if the file exists if os.path.isfile(filename): # open file message("opening file '%s'" % filename) f = open(filename, 'r') # raise exception if the file does not exist else: raise Exception("Error in read_eyetribe: file '%s' does not exist" % filename) # read file contents message("reading file '%s'" % filename) raw = f.readlines() # close file message("closing file '%s'" % filename) f.close() # # # # # # parse lines # variables data = [] x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } starttime = 0 started = False trialend = False filestarted = False # loop through all lines for i in range(len(raw)): # string to list line = raw[i].replace('\n', '').replace('\r', '').split('\t') # check if the line starts with '##' (denoting header) if '##' in line[0]: # skip processing continue elif '##' not in line[0] and not filestarted: # check the indexes for several key things we want to extract # (we need to do this, because ASCII outputs of the IDF reader # are different, based on whatever the user wanted to extract) timei = line.index("Time") typei = line.index("Type") msgi = -1 xi = {'L': None, 'R': None} yi = {'L': None, 'R': None} sizei = {'L': None, 'R': None} if "L POR X [px]" in line: xi['L'] = line.index("L POR X [px]") if "R POR X [px]" in line: xi['R'] = line.index("R POR X [px]") if "L POR Y [px]" in line: yi['L'] = line.index("L POR Y [px]") if "R POR Y [px]" in line: yi['R'] = line.index("R POR Y [px]") if "L Dia X [px]" in line: sizei['L'] = line.index("L Dia X [px]") if "R Dia X [px]" in line: sizei['R'] = line.index("R Dia X [px]") # set filestarted to True, so we don't attempt to extract # this info on all consecutive lines filestarted = True # check if trial has already started if started: # only check for stop if there is one if stop != None: if (line[typei] == 'MSG' and stop in line[msgi]) or i == len(raw) - 1: started = False trialend = True # check for new start otherwise else: if start in line or i == len(raw) - 1: started = True trialend = True # # # # # # trial ending if trialend: message("trialend %d; %d samples found" % (len(data), len(x))) # trial dict trial = {} trial['x'] = numpy.array(x) trial['y'] = numpy.array(y) trial['size'] = numpy.array(size) trial['time'] = numpy.array(time) trial['trackertime'] = numpy.array(trackertime) trial['events'] = copy.deepcopy(events) # events trial['events']['Sblk'], trial['events'][ 'Eblk'] = blink_detection( trial['x'], trial['y'], trial['trackertime'], missing=missing, minlen=5) # TEJADA: decreased from 10 to 5 trial['events']['Sfix'], trial['events'][ 'Efix'] = fixation_detection( trial['x'], trial['y'], trial['trackertime'], missing=missing, maxdist=80, mindur=80) # Parametros ajustados para BeGaze trial['events']['Ssac'], trial['events'][ 'Esac'] = saccade_detection( trial['x'], trial['y'], trial['trackertime'], missing=missing, minlen=1, maxvel=60, maxacc=450 ) #TEJADA: still trying to obtain the best adjust # add trial to data data.append(trial) # reset stuff x = [] y = [] size = [] time = [] trackertime = [] events = { 'Sfix': [], 'Ssac': [], 'Sblk': [], 'Efix': [], 'Esac': [], 'Eblk': [], 'msg': [] } trialend = False # check if the current line contains start message else: if line[typei] == "MSG": if start in line[msgi]: message("trialstart %d" % len(data)) # set started to True started = True # find starting time starttime = int(line[timei]) # # # # # # parse line if started: # message lines will usually start with a timestamp, followed # by 'MSG', the trial number and the actual message, e.g.: # "7818328012 MSG 1 # Message: 3" if line[typei] == "MSG": t = int(line[timei]) # time m = line[msgi] # message events['msg'].append([t, m]) # regular lines will contain tab separated values, beginning with # a timestamp, follwed by the values that were chosen to be # extracted by the IDF converter else: # see if current line contains relevant data try: # extract data on POR and pupil size for var in ['x', 'y', 'size']: exec("vi = %si" % var) exec("v = %s" % var) # nothing if vi['L'] == None and vi['R'] == None: val = 'not in IDF' # only left eye elif vi['L'] != None and vi['R'] == None: val = float(line[vi['L']]) # only right eye elif vi['L'] == None and vi['R'] != None: val = float(line[vi['R']]) # average the two eyes, but only if they both # contain valid data elif vi['L'] != None and vi['R'] != None: if float(line[vi['L']]) == 0: val = float(line[vi['R']]) elif float(line[vi['R']]) == 0: val = float(line[vi['L']]) else: val = (float(line[vi['L']]) + float(line[vi['R']])) / 2.0 v.append(val) # extract time data time.append((int(line[timei]) - starttime)) # TEJADA: tracker time was divided by 1000 to adjust timestamp of SMI trackertime.append((int(line[timei]) - starttime) / 1000) except: message("line '%s' could not be parsed" % line) continue # skip this line # # # # # # return return data