예제 #1
0
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)
예제 #2
0
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
예제 #3
0
	# # # # #
	# 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)
예제 #4
0
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
예제 #6
0
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