public List <Saccade> GenerateSaccades(List <Fixation> fixations)
        {
            List <Saccade> saccades = new List <Saccade>();

            for (int i = 0; i < fixations.Count - 1; i++)
            {
                Fixation from = fixations[i];
                Fixation to   = fixations[i + 1];

                Saccade s = new Saccade(new Point(from.x, from.y), new Point(to.x, to.y));
                saccades.Add(s);
            }

            return(saccades);
        }
        // Converts raw gaze input into fixations.
        public List <Fixation> CalculateFixations(int windowSize, float peakThreshold, float radius, int clipAmount)
        {
            ClipRawPoints(clipAmount);

            if (rawPoints == null || rawPoints.Count == 0)
            {
                Console.WriteLine("RawPoints is null or contains no points. Unable to calculate fixations.");
                return(new List <Fixation>());
            }

            Console.WriteLine("Calculating fixations...");
            List <Point> allPoints = ConvertGazePointsToPoints(rawPoints);

            // Create the array to store the differences in the windows for each point.
            float[] differences = new float[rawPoints.Count];
            for (int i = 0; i < rawPoints.Count; i++)
            {
                differences[i] = 0;
            }

            // 1: find the mean of the sliding window before and after sample i
            for (int i = windowSize; i <= (rawPoints.Count - windowSize) - 1; i++)
            {
                List <Point> leftWindow  = allPoints.GetRange(i - windowSize, windowSize);
                List <Point> rightWindow = allPoints.GetRange(i + 1, windowSize);

                Point meanBefore = GeometricMean(leftWindow);
                Point meanAfter  = GeometricMean(rightWindow);

                // 2: create vector "d", with distances between before and after windows
                float axbxSquared = (meanBefore.x - meanAfter.x) * (meanBefore.x - meanAfter.x);
                float aybySquared = (meanBefore.y - meanAfter.y) * (meanBefore.y - meanAfter.y);
                float difference  = (float)Math.Sqrt(axbxSquared + aybySquared);

                differences[i] = difference;
            }

            // Testing

            /*
             * Console.WriteLine("Differences:");
             * int count = 0;
             * foreach(float difference in differences) {
             *  Console.Write(count++ + ":" + difference + ", ");
             * }
             * Console.Write("\n");
             */
            // End Testing

            // 3: create peak vector and find peaks (that is, find the large(est) differences in means of the sliding windows)
            // Create the array to store the differences in the windows for each point.
            float[] peaks = new float[rawPoints.Count];
            for (int i = 0; i < rawPoints.Count; i++)
            {
                peaks[i] = 0;
            }

            for (int i = 1; i < rawPoints.Count - 1; i++)
            {
                // if this is a peak
                if (differences[i] > differences[i - 1] && differences[i] > differences[i + 1])
                {
                    peaks[i] = differences[i];
                }
            }

            // Testing

            /*
             * Console.WriteLine("Peaks:");
             * count = 0;
             * foreach(float peak in peaks) {
             *  Console.Write(count++ + ":" + peak + ", ");
             * }
             * Console.Write("\n");
             */
            // End Testing

            // 4: remove peaks that are too close to each other (only want the largest difference per sliding window)
            for (int i = windowSize; i <= (rawPoints.Count - windowSize) - 1; i++)
            {
                if (peaks[i] != 0)
                {
                    // check left side
                    for (int j = i - windowSize; j < i; j++)
                    {
                        if (peaks[j] < peaks[i])
                        {
                            peaks[j] = 0;
                        }
                    }
                    // check right side
                    for (int j = i + 1; j <= i + windowSize; j++)
                    {
                        if (peaks[j] < peaks[i])
                        {
                            peaks[j] = 0;
                        }
                    }
                }
            }

            // Testing

            /*
             * Console.WriteLine("Peaks after removing nearby peaks:");
             * count = 0;
             * foreach(float peak in peaks) {
             *  Console.Write(count++ + ":" + peak + ", ");
             * }
             * Console.Write("\n");
             */
            // End Testing

            // 5: create list with the indices of the peaks in the peak vector
            //      only add the peaks greater than some threshold, this works the same as a naieve algorithm, we only consider it a saccade if the distance is over a vertain threshold.

            List <int> peakIndices = new List <int>();

            for (int i = 0; i < rawPoints.Count; i++)
            {
                if (peaks[i] > peakThreshold)
                {
                    peakIndices.Add(i);
                }
            }

            // Testing

            /*
             * Console.WriteLine("Peak Indices");
             * count = 0;
             * foreach(float index in peakIndices) {
             *  Console.Write(count++ + ":" + index + ", ");
             * }
             * Console.Write("\n");
             */
            // End Testing

            // 6a: estimate the spacial position of all the fixations between candidate saccades (peaks)
            //      use the geometric median of all the raw points

            // 6b: fixations that are closer together than a specified range are merged together.

            // float shortestDistance = 0; // used in 6b
            List <Fixation> fixations = new List <Fixation>();

            //while(shortestDistance < radius) { // used in 6b

            fixations.Clear();

            // 6a
            for (int i = 1; i <= peakIndices.Count - 1; i++)
            {
                int rawFromIndex = peakIndices[i - 1];
                int rawToIndex   = peakIndices[i];

                List <GazePoint> points = new List <GazePoint>();
                for (int rawIndex = rawFromIndex; rawIndex <= rawToIndex; rawIndex++)
                {
                    points.Add(rawPoints[rawIndex]);
                }

                VSLocation majorityLocation = MajorityVSLocation(points.ToArray());
                Point      median           = GeometricMedian(ConvertGazePointsToPoints(points));
                int        startTime        = points[0].timestamp;
                int        endTime          = points[points.Count - 1].timestamp;
                Fixation   fixation         = new Fixation(median.x, median.y, startTime, endTime, majorityLocation);
                fixations.Add(fixation);
            }


            // 6b

            /*
             * shortestDistance = float.MaxValue;
             *
             * for(int i = 1; i <= fixations.Count - 1; i++) {
             *
             *  int index = 0;
             *  Point a = new Point(fixations[i - 1].x, fixations[i - 1].y);
             *  Point b = new Point(fixations[i].x, fixations[i].y);
             *
             *  float distance = EuclideanDistance(a, b);
             *
             *  if(distance < shortestDistance) {
             *      shortestDistance = distance;
             *      index = i;
             *  }
             *
             *  if (shortestDistance < radius) {
             *      try {
             *          peakIndices.RemoveAt(index); // BUG: When removing peakIndices, all indices move down a slot, can remove at index and expect all other indices to stay the same...
             *      }
             *      catch(Exception e) {
             *          Console.WriteLine(e.Message);
             *          Console.WriteLine("index:" + index);
             *          Console.WriteLine(peakIndices.Count);
             *      }
             *  }
             * }
             * } */

            // Testing

            /*
             * Console.WriteLine("Fixations:");
             * count = 0;
             * foreach(Fixation fixation in fixations) {
             *  Console.Write(count++ + ":" + fixation.x + "," + fixation.y + ", ");
             * }
             * Console.Write("\n");
             */
            // End Testing

            return(fixations);
        }
Example #3
0
 private Token TokenForFixation(Fixation fixation)
 {
     return((fixation.endTime - fixation.startTime) < 500 ? Token.Brief : Token.Hold);
 }