예제 #1
0
        /// <summary>
        /// I-VT algorithm from "Identifying fixations and saccades in eye-tracking protocols", Salvucci, 2000
        /// </summary>
        /// <param name="maxSpeedFixation">If the speed is inferior to maxSpeedFixation, it is considered as a fixation</param>
        public void fixationVelocity(int maxSpeedFixation = 40)
        {
            //With Tobii EyeX, the distance and velocity are similar because the data is recorded at a regular time - every x ms)
            //Compute the velocity
            for (int i = 1; i < gazes.Count; i++)
            {
                gazes[i].squaredVelocity = (gazes[i - 1].gazeX - gazes[i].gazeX) * (gazes[i - 1].gazeX - gazes[i].gazeX) + (gazes[i - 1].gazeY - gazes[i].gazeY) * (gazes[i - 1].gazeY - gazes[i].gazeY);
            }
            List <Gaze> fixations = new List <Gaze>();

            for (int i = 0; i < gazes.Count; i++)
            {
                List <Gaze> microFixations = new List <Gaze>();
                int         j = 0;
                while (i + j < gazes.Count && gazes[i + j].squaredVelocity < maxSpeedFixation * maxSpeedFixation)
                {
                    microFixations.Add(gazes[i + j]);
                    j++;
                }
                if (microFixations.Count > 1)
                {
                    //Compute the centroid
                    Gaze centre = centroid(microFixations);
                    fixations.Add(centre);
                    i += j - 1;
                }
                if (microFixations.Count == 1)
                {
                    fixations.Add(microFixations.First());
                }
            }
            gazes = fixations;
        }
예제 #2
0
        private IEnumerable <Gaze> readTobiiCsvNew(List <string> linesTxt, char split = ';')
        {
            List <Gaze> gazes = new List <Gaze>();

            if (linesTxt.Count < 2)
            {
                return(gazes);
            }
            //Remove the header
            linesTxt.RemoveAt(0);
            //Convert decimal marker in numbers if the format it is a dot or a comma 00.000 (USA / Japan) or 00,000 (Europe)
            double timeZero = double.Parse(linesTxt[0].Split(split)[1].Replace(',', '.'), new CultureInfo("en-US"));

            foreach (string line in linesTxt)
            {
                string[] cols = line.Split(split);
                Gaze     g    = new Gaze();
                g.windowTime    = DateTime.ParseExact(cols[0], "MM/dd/yyyy HH:mm:ss.FFF", null);
                g.timestamp     = (float)(double.Parse(cols[1].Replace(',', '.'), new CultureInfo("en-US")) - timeZero);
                g.gazeX         = float.Parse(cols[2].Replace(',', '.'), new CultureInfo("en-US"));
                g.gazeY         = float.Parse(cols[3].Replace(',', '.'), new CultureInfo("en-US"));
                g.pupilDiameter = float.Parse(cols[4].Replace(',', '.'), new CultureInfo("en-US"));
                gazes.Add(g);
            }
            return(gazes);
        }
예제 #3
0
        private void readSMiRaw(List <string> linesTxt)
        {
            //Remove the non-data lines
            string curentLine = linesTxt[0];
            int    indexGazeX = 0;
            int    indexGazeY = 0;

            while (curentLine.StartsWith("##") || curentLine.StartsWith("Time"))
            {
                //Save the saze of the screen
                if (curentLine.StartsWith("## Calibration Area:	"))
                {
                    width  = int.Parse(curentLine.Split('\t')[1].Replace(',', '.'), new CultureInfo("en-US"));
                    height = int.Parse(curentLine.Split('\t')[2].Replace(',', '.'), new CultureInfo("en-US"));
                }
                //Save the index of the collomn that contain the position of the gaze, because it change depending on the files!
                else if (curentLine.StartsWith("Time"))
                {
                    string[] cols = curentLine.Split('\t');
                    for (int i = 0; i < cols.Length; i++)
                    {
                        if (cols[i] == "R POR X [px]")
                        {
                            indexGazeX = i;
                        }
                        else if (cols[i] == "R POR Y [px]")
                        {
                            indexGazeY = i;
                        }
                    }
                }
                linesTxt.RemoveAt(0);
                curentLine = linesTxt[0];
            }

            double timeZero = double.Parse(linesTxt[0].Split('\t')[0].Replace(',', '.'), new CultureInfo("en-US"));

            foreach (var line in linesTxt)
            {
                string[] cols = line.Split('\t');
                if (indexGazeX < cols.Length && indexGazeY < cols.Length)
                {
                    Gaze g = new Gaze();
                    g.timestamp = (float)(double.Parse(cols[0].Replace(',', '.'), new CultureInfo("en-US")) - timeZero);
                    g.gazeX     = float.Parse(cols[indexGazeX].Replace(',', '.'), new CultureInfo("en-US"));
                    g.gazeY     = float.Parse(cols[indexGazeY].Replace(',', '.'), new CultureInfo("en-US"));
                    gazes.Add(g);
                }
            }
        }
예제 #4
0
        public static Gaze centroid(List <Gaze> gazes)
        {
            Gaze g = gazes.First();

            g.duration = gazes.Last().timestamp - g.timestamp;
            for (int i = 1; i < gazes.Count; i++)
            {
                g.gazeX += gazes[i].gazeX;
                g.gazeY += gazes[i].gazeY;
            }
            g.gazeX /= gazes.Count;
            g.gazeY /= gazes.Count;
            return(g);
        }
예제 #5
0
        public static List <Gaze> readTobiiCsv(List <string> linesTxt, char split = ';')
        {
            List <Gaze> gazes = new List <Gaze>();

            if (linesTxt.Count < 2)
            {
                return(gazes);
            }
            //Remove the header
            linesTxt.RemoveAt(0);
            //Convert decimal marker in numbers if the format it is a dot or a comma 00.000 (USA / Japan) or 00,000 (Europe)
            double timeZero = double.Parse(linesTxt[0].Split(split)[0].Replace(',', '.'), new CultureInfo("en-US"));

            foreach (string line in linesTxt)
            {
                string[] cols = line.Split(split);
                Gaze     g    = new Gaze();
                g.timestamp = (float)(double.Parse(cols[0].Replace(',', '.'), new CultureInfo("en-US")) - timeZero);
                g.gazeX     = float.Parse(cols[1].Replace(',', '.'), new CultureInfo("en-US"));
                g.gazeY     = float.Parse(cols[2].Replace(',', '.'), new CultureInfo("en-US"));
                gazes.Add(g);
            }
            return(gazes);
        }
예제 #6
0
        private void initialize(string nameWithoutExtention)
        {
            paramFilename  = nameWithoutExtention + "_param.txt";
            filename       = nameWithoutExtention + ".csv";
            aviOriginal    = nameWithoutExtention + ".avi";
            pngOriginal    = nameWithoutExtention + "_gaze.png";
            pngFixations   = nameWithoutExtention + "_fixations.png";
            aviFixations   = nameWithoutExtention + "_fixations.avi";
            pngLineBreak   = nameWithoutExtention + "_line.png";
            aviLineBreak   = nameWithoutExtention + "_line.avi";
            pngMedian      = nameWithoutExtention + "_median.png";
            backgroundPath = nameWithoutExtention + "_back.png";
            csvFixations   = nameWithoutExtention + "_fix.csv";

            //Read the data
            if (!File.Exists(filename))
            {
                //Second possibility because of SMi files
                filename = filename.Replace(".csv", ".txt");
                if (!File.Exists(filename))
                {
                    throw new Exception("Error, the file " + filename + " cannot be found. Press a key to exit the program...");
                }
            }

            List <string> linesTxt = File.ReadAllLines(filename).ToList();

            //Inspect the first line, if "Timestamp;GazeX;GazeY;LeftEye;RightEye" it is a Tobii raw data
            if (linesTxt[0] == "Timestamp;GazeX;GazeY;LeftEye;RightEye" || linesTxt[0] == "TimeStamp;GazeX;GazeY" || linesTxt[0] == "TimeStamp;GazeX;GazeY;TimeStampWindows")
            {
                readTobii(linesTxt);
            }

            else if (linesTxt[0] == "WindowsTime;Timestamp;GazeX;GazeY;PupilDiameter")
            {
                readTobiiNew(linesTxt);
            }

            //Else if it is "## [BeGaze]" it is SMi
            else if (linesTxt[0] == "## [BeGaze]")
            {
                readSMiRaw(linesTxt);
            }

            //Else if the last line is "finish", it is a Fixation file made by the student from SMi
            else if (linesTxt[linesTxt.Count - 1] == "finish")
            {
                int    i        = 0;
                double timeZero = double.Parse(linesTxt[0].Split('\t')[0].Replace(',', '.'), new CultureInfo("en-US"));
                while (linesTxt[i] != "blink")
                {
                    string[] cols = linesTxt[i].Split('\t');
                    Gaze     g    = new Gaze();
                    g.timestamp = (float)(double.Parse(cols[0].Replace(',', '.'), new CultureInfo("en-US")) - timeZero);
                    g.gazeX     = float.Parse(cols[2].Replace(',', '.'), new CultureInfo("en-US"));
                    g.gazeY     = float.Parse(cols[3].Replace(',', '.'), new CultureInfo("en-US"));
                    gazes.Add(g);
                    i++;
                }
            }

            //a Tobii raw data made by Shoya
            else if (linesTxt[0] == "# timestamp,x,y")
            {
                gazes = readTobiiCsv(linesTxt, ',');
            }

            //Else exeption
            else
            {
                throw new Exception("Unknown type of input");
            }
        }