/// <summary> /// This method calculates the type of eye movement given a new point /// </summary> /// <param name="newPoint">New point</param> public void CalculateEyeMovement(GTPoint newPoint) { long time = DateTime.UtcNow.Ticks/TimeSpan.TicksPerMillisecond; AddNewPoint(newPoint, time); if (recentPoints.Count > 1) { if (Operations.GetMaxDistanceOnWindow(recentPoints) < Settings.Instance.EyeMovement.MaxDispersion) { CalculateVelocity(); if (velocities[velocities.Count - 1] > Settings.Instance.EyeMovement.MaxAngularSpeed) eyeMovementState = EyeMovementStateEnum.NoFixation; else eyeMovementState = EyeMovementStateEnum.Fixation; } else eyeMovementState = EyeMovementStateEnum.NoFixation; } else eyeMovementState = EyeMovementStateEnum.NoFixation; if (eyeMovementState == EyeMovementStateEnum.NoFixation) { if (TrackDB.Instance.GetLastSample().EyeMovement == EyeMovementStateEnum.Fixation) { recentPoints.Clear(); Settings.Instance.EyeMovement.WindowSize = 2; AddNewPoint(newPoint, time); } } else Settings.Instance.EyeMovement.WindowSize = Math.Min(Settings.Instance.EyeMovement.WindowSize, Settings.Instance.EyeMovement.MaxWindowSize); }
/// <summary> /// Detect two glints in a grayscale image. /// This method will select the two glints closest to the initial location /// </summary> /// <param name="inputImage">Input image in grayscale</param> /// <param name="glintThreshold">Gray level to threshold the image</param> /// <param name="minGlintSize">Minimum glint size allowed (radius in pixels)</param> /// <param name="maxGlintSize">Maximum glint size allowed (radius in pixels)</param> /// <param name="initialLocation">Select the two glints closest this parameter</param> /// <returns>True if glint(s) detected, false if not</returns> public bool DetectTwoGlints(Image<Gray, byte> inputImage, int glintThreshold, int minGlintSize, int maxGlintSize, GTPoint initialLocation) { GlintThreshold = glintThreshold; MinGlintSize = minGlintSize; MaxGlintSize = 3*maxGlintSize; bool foundGlints = false; // We get the blobs in the input image given the threshold (minWidth, maxWidth) blobs = blobDetector.DetectBlobs(inputImage, glintThreshold, MinGlintSize, MaxGlintSize, true); int unfilteredCount = blobs.Count; double unfilteredArea = blobs.TotalArea; // Filter out exterior blobs blobs.EliminateExteriorBlobs(); if (blobDetector.IsFiltering == false) // Not using AForger filtering blobs.FilterByArea(MinGlintSize, MaxGlintSize); if (blobs.Count > 1) { blobs.FilterByDistance(initialLocation, 2); glintData.Glints = new GlintConfiguration(blobs); // store blobcount for autotune glintData.Glints.UnfilteredCount = unfilteredCount; glintData.Glints.UnfilteredTotalArea = unfilteredArea; if (glintData.Glints.Count > 0) foundGlints = true; } return foundGlints; }
public GlintConfiguration(Blob blob) { count = 1; centers = new GTPoint[1]; blobs.BlobDir[0] = blob; centers[0] = new GTPoint(blob.CenterOfGravity.X, blob.CenterOfGravity.Y); }
/// <summary> /// Order any 4 points /// </summary> /// <param name="points">Array of 4 points</param> /// <returns>Ordered array of the 4 points</returns> static public GTPoint[] OrderPoints(GTPoint[] points) { int N = 4; GTPoint[] orderedPoints = new GTPoint[N]; GTPoint center = new GTPoint(); if (points.Length != N) { Console.WriteLine("error ordering 4 glints"); } else { center = Operations.Mean(points); double[] distances = new double[N - 1]; for (int i = 0; i < N; i++) { if (points[i].X <= center.X && points[i].Y <= center.Y) { orderedPoints[0] = points[i]; } else if (points[i].X >= center.X && points[i].Y <= center.Y) { orderedPoints[1] = points[i]; } else if (points[i].X >= center.X && points[i].Y >= center.Y) { orderedPoints[2] = points[i]; } else if (points[i].X <= center.X && points[i].Y >= center.Y) { orderedPoints[3] = points[i]; } } try { for (int i = 0; i < N; i++) { if (orderedPoints[i] == null) { //Console.WriteLine("Incorrect 4 points detected"); orderedPoints = new GTPoint[1]; return(orderedPoints); } } } catch { //Console.WriteLine("Exception ordering points"); orderedPoints = new GTPoint[1]; } } return(orderedPoints); }
/// <summary> /// Converts a Matrix of points into an array of GTPoints /// </summary> /// <param name="pointsMatrix">Nx2 matrix, with first column being X coordinate /// and second column being Y coordinate</param> /// <returns>Array of GTpoints</returns> public static GTPoint[] ConvertToArray(Matrix <double> pointsMatrix) { var pointsArray = new GTPoint[pointsMatrix.Rows]; for (int i = 0; i < pointsMatrix.Rows; i++) { pointsArray[i] = new GTPoint(pointsMatrix[i, 0], pointsMatrix[i, 1]); } return(pointsArray); }
// Copy constructur internal Blob(Blob source) { // copy everything except image id = source.id; rect = source.rect; cog = source.cog; area = source.area; fullness = source.fullness; colorMean = source.colorMean; colorStdDev = source.colorStdDev; }
public GlintConfiguration(int numGlints) { count = numGlints; centers = new GTPoint[numGlints]; blobs = new Blobs(); for (int i = 0; i < numGlints; i++) { centers[i] = new GTPoint(); blobs.BlobDir[i] = new Blob(); } }
public GlintConfiguration(GlintConfiguration src) { count = src.Count; centers = new GTPoint[count]; blobs = new Blobs(); for (int i = 0; i < count; i++) { centers[i] = new GTPoint(src.centers[i]); blobs.BlobDir[i] = new Blob(); blobs.BlobDir[i] = src.blobs.BlobDir.ElementAt(i).Value; } }
/// <summary> /// Mean GTPoint of an array of GTPoints /// </summary> /// <param name="points">Array of GTPoints</param> /// <returns>GTPoint containing the mean</returns> public static GTPoint Mean(GTPoint[] points) { double x = 0; double y = 0; for (int i = 0; i < points.Length; i++) { x = x + points[i].X; y = y + points[i].Y; } return new GTPoint(x/points.Length, y/points.Length); }
/// <summary> /// Smooth method. Call this method when we get a new /// sample and it will return the smoothed coordinates /// </summary> /// <param name="newPoint">New gazed point</param> /// <returns>Smoothed point</returns> public GTPoint Smooth(GTPoint newPoint) { GTPoint smoothedPoint; if (data.Count < numberOfSamples) data.Add(newPoint); else { data.RemoveAt(0); data.Add(newPoint); } smoothedPoint = Operations.Mean(data.ToArray()); return smoothedPoint; }
public static double GetMaxDistanceOnWindow(List <GTPoint> data) { GTPoint centroid = Mean(data.ToArray()); int maxDistance = 150; double maxDist = 0; double dist = 0; for (int i = 0; i < data.Count; i++) { dist = Distance(centroid, data[i]); if (dist > maxDistance) { maxDist = dist; } } return(maxDist); }
public void CalculateAngleDegreesTest() { // Can be used for testing to make sure N-Unit is responding properly Assert.IsTrue( true, "Hello World" ); // Check angle between two simple points GTPoint gtPoint1 = new GTPoint( 1.0D, 1.0D ); GTPoint gtPoint2 = new GTPoint( 2.0D, 2.0D ); Assert.AreEqual( 45.0D, Operations.CalculateAngle( gtPoint1, gtPoint2 ), UnitTestSettings.DOUBLE_COMPARISON_TOLERANCE ); // Now create the same GTPoints via two System.Drawing.Point objects and recheck the angles found System.Drawing.Point drawingPoint1 = new System.Drawing.Point( 1, 1 ); System.Drawing.Point drawingPoint2 = new System.Drawing.Point( 2, 2 ); Assert.AreEqual( 45.0D, Operations.CalculateAngle( drawingPoint1, drawingPoint2 ), UnitTestSettings.DOUBLE_COMPARISON_TOLERANCE ); // Now create the same GTPoints via two System.Windows.Point objects and recheck the angles found System.Windows.Point windowsP1 = new System.Windows.Point( 1, 1 ); System.Windows.Point windowsP2 = new System.Windows.Point( 2, 2 ); Assert.AreEqual( 45.0D, Operations.CalculateAngle( windowsP1, windowsP2 ), UnitTestSettings.DOUBLE_COMPARISON_TOLERANCE ); }
public void CalculateAngleDegreesTest() { // Can be used for testing to make sure N-Unit is responding properly Assert.IsTrue(true, "Hello World"); // Check angle between two simple points GTPoint gtPoint1 = new GTPoint(1.0D, 1.0D); GTPoint gtPoint2 = new GTPoint(2.0D, 2.0D); Assert.AreEqual(45.0D, Operations.CalculateAngle(gtPoint1, gtPoint2), UnitTestSettings.DOUBLE_COMPARISON_TOLERANCE); // Now create the same GTPoints via two System.Drawing.Point objects and recheck the angles found System.Drawing.Point drawingPoint1 = new System.Drawing.Point(1, 1); System.Drawing.Point drawingPoint2 = new System.Drawing.Point(2, 2); Assert.AreEqual(45.0D, Operations.CalculateAngle(drawingPoint1, drawingPoint2), UnitTestSettings.DOUBLE_COMPARISON_TOLERANCE); // Now create the same GTPoints via two System.Windows.Point objects and recheck the angles found System.Windows.Point windowsP1 = new System.Windows.Point(1, 1); System.Windows.Point windowsP2 = new System.Windows.Point(2, 2); Assert.AreEqual(45.0D, Operations.CalculateAngle(windowsP1, windowsP2), UnitTestSettings.DOUBLE_COMPARISON_TOLERANCE); }
/// <summary> /// Detect glints in a grayscale image. /// This method will select the blob closest to coordinates of initialLocation /// that has a lower y coordinate (i.e., corresponds to having the light source /// above the screen) /// </summary> /// <param name="inputImage">Input image in grayscale</param> /// <param name="glintThreshold">Gray level to threshold the image</param> /// <param name="minGlintSize">Minimum glint size allowed (radius in pixels)</param> /// <param name="maxGlintSize">Maximum glint size allowed (radius in pixels)</param> /// <param name="initialLocation">Select the glint closest to this parameter</param> /// <returns>True if glint detected, true otherwise</returns> public bool DetectGlintAbove(Image<Gray, byte> inputImage, int glintThreshold, int minGlintSize, int maxGlintSize, GTPoint initialLocation) { bool foundGlints = false; GlintThreshold = glintThreshold; MinGlintSize = minGlintSize; MaxGlintSize = maxGlintSize; var min = (int) Math.Round(Math.PI*Math.Pow(minGlintSize, 2)); var max = (int) Math.Round(Math.PI*Math.Pow(maxGlintSize, 2)); // We get the blobs in the input image given the threshold blobs = blobDetector.DetectBlobs(inputImage, glintThreshold, min, max, true); // store blobcount for autotune glintData.Glints.UnfilteredCount = blobs.Count; glintData.Glints.UnfilteredTotalArea = blobs.TotalArea; // Filter out exterior blobs if (blobs.Count > 1) blobs.EliminateExteriorBlobs(); if (blobDetector.IsFiltering == false) // Not using AForger filtering blobs.FilterByArea(min, max); // Eliminate blobs below initialLocation (pupil center) blobs.FilterByLocation(initialLocation, 1, 1); if (blobs.Count > 1) blobs.FilterByDistance(initialLocation); if (blobs.Count > 0) { glintData.Glints = new GlintConfiguration(blobs); foundGlints = true; } return foundGlints; }
/// <summary> /// This method calculates the average of the estimated gazed coordinates /// (once calibration is finished) /// </summary> public void CalculateAverageCoords() { var avgLeft = new GTPoint(); var avgRight = new GTPoint(); var varianceLeft = new GTPoint(); var varianceRight = new GTPoint(); // Left eye if (estimatedGazeCoordinatesLeft.Count > 0) { avgLeft = Operations.Mean(estimatedGazeCoordinatesLeft.ToArray()); meanGazeCoordinatesLeft.X = (int) avgLeft.X; meanGazeCoordinatesLeft.Y = (int) avgLeft.Y; varianceLeft = Operations.Variance(estimatedGazeCoordinatesLeft.ToArray()); stdDeviationGazeCoordinatesLeft = Math.Sqrt(varianceLeft.X + varianceLeft.Y); } else { meanGazeCoordinatesLeft.X = 0; meanGazeCoordinatesLeft.Y = 0; stdDeviationGazeCoordinatesLeft = 0; } // Right eye if (estimatedGazeCoordinatesRight.Count > 0) { avgRight = Operations.Mean(estimatedGazeCoordinatesRight.ToArray()); meanGazeCoordinatesRight.X = (int) avgRight.X; meanGazeCoordinatesRight.Y = (int) avgRight.Y; varianceRight = Operations.Variance(estimatedGazeCoordinatesRight.ToArray()); stdDeviationGazeCoordinatesRight = Math.Sqrt(varianceRight.X + varianceRight.Y); } else { meanGazeCoordinatesRight.X = 0; meanGazeCoordinatesRight.Y = 0; stdDeviationGazeCoordinatesRight = 0; } }
/// <summary> /// Calculate the angle between 2 GTPoints /// </summary> /// <param name="newPoint"></param> /// <param name="oldPoint"></param> /// <returns></returns> public static double CalculateAngle(GTPoint newPoint, GTPoint oldPoint) { double angle; if (newPoint.X - oldPoint.X == 0) { if (newPoint.Y - oldPoint.Y > 0) { angle = 90; } else { angle = -90; } } else { angle = Math.Atan((newPoint.Y - oldPoint.Y) / (newPoint.X - oldPoint.X)); angle = angle * 180 / Math.PI; } return(angle); }
/// <summary> /// /// </summary> /// <param name="points"></param> /// <param name="numPoints"></param> /// <returns></returns> public static GTPoint[] GetRandomPermutation(GTPoint[] points, int numPoints) { var randPoints = new GTPoint[numPoints]; var randomGenerator = new Random(); var mask = new int[points.Length]; int randomNumber; for (int i = 0; i < mask.Length; i++) { mask[i] = 0; } while (Sum(mask) < numPoints) { randomNumber = randomGenerator.Next(points.Length); if (mask[randomNumber] == 0) { mask[randomNumber] = 1; } } int counter = 0; for (int k = 0; k < mask.Length; k++) { if (mask[k] == 1) { randPoints[counter] = new GTPoint(points[k]); counter++; } } return(randPoints); }
public GlintConfiguration(Blobs blobs) { count = blobs.Count; centers = new GTPoint[blobs.Count]; int i = 0; foreach (Blob b in blobs.BlobList) { centers[i] = new GTPoint(b.CenterOfGravity.X, b.CenterOfGravity.Y); i++; } //OrderGlints(); this.blobs = blobs; }
/// <summary> /// Calculates the optimal valid configuration and eliminates the rest of the blobs. /// It uses the number of light sources. /// </summary> public GlintConfiguration GetValidConfiguration(Blobs blobs, GTPoint initialLocation) { var validConfig = new GlintConfiguration(4); var candidateGlintCenters = new Matrix<double>(blobs.Count, blobs.Count); Matrix<int> distMatrixThr; var combinations = new List<Point>(); var validConfigurations = new List<GlintConfiguration>(); var indicesValidConfigs = new List<int>(); distMatrixThr = GetDistanceMatrix(blobs, MinDistBetweenGlints, MaxDistBetweenGlints); for (int i = 0; i < distMatrixThr.Rows; i++) { combinations.AddRange(GetCombinations(distMatrixThr.GetRow(i).Clone(), i)); } if (combinations.Count > 0) validConfig = FilterConfigsByDistance(blobs, combinations, initialLocation); else validConfig = new GlintConfiguration(1); return validConfig; }
private GlintConfiguration FilterConfigsBySize(Blobs blobs, List<Point> combinations, GTPoint initialLocation) { int N = combinations.Count; double maxSize = 0; double combinationSize; int correctConfigIndex = 0; for (int i = 0; i < N; i++) { combinationSize = blobs.BlobList[(int) combinations[i].X].Area + blobs.BlobList[(int) combinations[i].Y].Area; if (combinationSize > maxSize) { correctConfigIndex = i; maxSize = combinationSize; } } return new GlintConfiguration(blobs.BlobList[(int) combinations[correctConfigIndex].X], blobs.BlobList[(int) combinations[correctConfigIndex].Y]); }
private GlintConfiguration FilterConfigsByDistance(Blobs blobs, List<Point> combinations, GTPoint initialLocation) { int N = combinations.Count; double minDistance = 100000000; double avgDist = 0; int correctConfigIndex = 0; for (int i = 0; i < N; i++) { double dist1 = Operations.Distance(blobs.BlobList[(int) combinations[i].X].CenterOfGravity, initialLocation); double dist2 = Operations.Distance(blobs.BlobList[(int) combinations[i].Y].CenterOfGravity, initialLocation); avgDist = (dist1 + dist2)/2; if (avgDist < minDistance) { correctConfigIndex = i; minDistance = avgDist; } } return new GlintConfiguration(blobs.BlobList[(int) combinations[correctConfigIndex].X], blobs.BlobList[(int) combinations[correctConfigIndex].Y]); }
public GTPoint Smooth(GTPoint newPoint) { return newPoint; }
public void FilterByDistance(GTPoint initialLocation, int N) { if(N > numBlobs) return; BlobObject[] finalBlobs = new BlobObject[N]; double[] distances = new double[numBlobs]; int[] keys = new int[numBlobs]; //Matrix<double> distances = new Matrix<double>(numBlobs, 1); GTPoint center; for (int i = 0; i < numBlobs; i++) { center = new GTPoint(detectedBlobs[i].CentroidX, detectedBlobs[i].CentroidY); distances[i] = Operations.Distance(center, new GTPoint(initialLocation)); keys[i] = i; } Array.Sort(distances, keys); for (int i = 0; i < numBlobs; i++) { if (i < N) finalBlobs[i] = detectedBlobs[keys[i]]; else detectedBlobs[keys[i]].Clear(); } detectedBlobs = finalBlobs; numBlobs = N; }
/// <summary> /// Calculate angular velocity /// </summary> private void CalculateVelocity() { var newPoint = new GTPoint(recentPoints[recentPoints.Count - 1]); var oldPoint = new GTPoint(recentPoints[recentPoints.Count - 2]); distPixels = Operations.Distance(newPoint, oldPoint); distMm = ConvertPixToMm(distPixels); distDegrees = Math.Atan(distMm/10/Settings.Instance.EyeMovement.DistanceUserToScreen); distDegrees = distDegrees*180/Math.PI; angularVelocity = distDegrees/timeElapsed; AddNewVelocity(angularVelocity); }
private void AddNewPoint(GTPoint newPoint, long time) { if (recentPoints.Count >= Settings.Instance.EyeMovement.WindowSize) recentPoints.RemoveAt(0); recentPoints.Add(newPoint); timeElapsed = time - previousTime; timeElapsed = timeElapsed/1000; previousTime = time; }
public GTPoint(GTPoint point) { X = point.X; Y = point.Y; }
public bool DetectPupil(Image<Gray, byte> inputImage, TrackData trackData) { foundPupil = false; var initialLocation = new GTPoint(inputImage.Width/2, inputImage.Height/2); if (eye == EyeEnum.Left) PupilGrayLevel = Settings.Instance.Processing.PupilThresholdLeft; else PupilGrayLevel = Settings.Instance.Processing.PupilThresholdRight; MinPupilSize = Settings.Instance.Processing.PupilSizeMinimum; MaxPupilSize = Settings.Instance.Processing.PupilSizeMaximum; var min = (int) Math.Round(Math.PI*Math.Pow(MinPupilSize, 2)); var max = (int) Math.Round(Math.PI*Math.Pow(MaxPupilSize, 2)); Blobs blobs = blobDetector.DetectBlobs(inputImage, PupilGrayLevel, min, max, false); #region Autotuning data store if (eye == EyeEnum.Left) { trackData.UnfilteredBlobCountLeft = blobs.Count; trackData.UnfilteredTotalBlobAreaLeft = blobs.TotalArea; } else { trackData.UnfilteredBlobCountRight = blobs.Count; trackData.UnfilteredTotalBlobAreaRight = blobs.TotalArea; } #endregion //if (blobDetector.IsFiltering == false) // blobs.FilterByArea(10, (int)blobs.TotalArea); //Console.WriteLine("Average fullness: {0}", blobs.AverageFullness); blobs.EliminateExteriorBlobs(); if (blobDetector.IsFiltering == false) blobs.FilterByArea(min, max); if (blobs.Count > 1) blobs.FilterByDistance(initialLocation); // New, filter by fullness //blobs.FilterByFullness(0.40); if (blobs.Count > 0) { //blobDetector.blobCounter.ExtractBlobsImage(inputImage.ToBitmap(), blobs.BlobDir.ElementAt(0).Value, false); pupilData.Blob = blobs.BlobDir.ElementAt(0).Value; if (pupilData.Blob != null) { foundPupil = true; pupilData.Center = new GTPoint(pupilData.Blob.CenterOfGravity.X, pupilData.Blob.CenterOfGravity.Y); // We save the values of the gray level in the corners of rectangle around the pupil blob (which are on the iris) // Javier, the array on EmguGray is [y,x] not [x,y] int x = pupilData.Blob.Rectangle.X; int y = pupilData.Blob.Rectangle.Y; int w = pupilData.Blob.Rectangle.Width; int h = pupilData.Blob.Rectangle.Height; pupilData.GrayCorners[0] = (int) inputImage[y, x].Intensity; pupilData.GrayCorners[1] = (int) inputImage[y, x + w - 1].Intensity; pupilData.GrayCorners[2] = (int) inputImage[y + h - 1, x].Intensity; pupilData.GrayCorners[3] = (int) inputImage[y + h - 1, x + w - 1].Intensity; } } else foundPupil = false; return foundPupil; }
public static double Distance(GTPoint p1, Point p2) { return(Math.Sqrt(Math.Pow(p1.X - p2.X, 2) + Math.Pow(p1.Y - p2.Y, 2))); }
/// <summary> /// Detect glint(s) main method (moved from ImageProcessing) /// </summary> /// <returns>True if glints detected, false otherwise</returns> public bool DetectGlints(Image<Gray, byte> gray, GTPoint pupilCenter) { bool glintsDetected = false; int threshold = Settings.Instance.Processing.GlintThreshold; // default for both eyes // Treshold to apply, seperate for each eye. if (eye == EyeEnum.Left) threshold = Settings.Instance.Processing.GlintThresholdLeft; else threshold = Settings.Instance.Processing.GlintThresholdRight; MinDistBetweenGlints = (int) Math.Floor(0.03*gray.Width); MaxDistBetweenGlints = (int) Math.Ceiling(0.5*gray.Width); switch (Settings.Instance.Processing.IRPlacement) { case IRPlacementEnum.Above: if (Settings.Instance.Processing.NumberOfGlints == 1) { glintsDetected = DetectGlintAbove( gray, threshold, Settings.Instance.Processing.GlintSizeMinimum, Settings.Instance.Processing.GlintSizeMaximum, pupilCenter); } else { glintsDetected = DetectTwoGlintsAbove( gray, threshold, Settings.Instance.Processing.GlintSizeMinimum, Settings.Instance.Processing.GlintSizeMaximum, pupilCenter); } break; case IRPlacementEnum.Below: if (Settings.Instance.Processing.NumberOfGlints == 1) { glintsDetected = DetectGlintBelow( gray, threshold, Settings.Instance.Processing.GlintSizeMinimum, Settings.Instance.Processing.GlintSizeMaximum, pupilCenter); } else { glintsDetected = DetectTwoGlintsBelow( gray, threshold, Settings.Instance.Processing.GlintSizeMinimum, Settings.Instance.Processing.GlintSizeMaximum, pupilCenter); } break; case IRPlacementEnum.None: if (Settings.Instance.Processing.NumberOfGlints == 1) { glintsDetected = DetectGlint( gray, threshold, Settings.Instance.Processing.GlintSizeMinimum, Settings.Instance.Processing.GlintSizeMaximum, pupilCenter); } else if (Settings.Instance.Processing.NumberOfGlints == 2) { glintsDetected = DetectTwoGlints( gray, threshold, Settings.Instance.Processing.GlintSizeMinimum, Settings.Instance.Processing.GlintSizeMaximum, pupilCenter); } break; case IRPlacementEnum.BelowAndAbove: if (Settings.Instance.Processing.NumberOfGlints == 2) { glintsDetected = DetectTwoGlints( gray, threshold, Settings.Instance.Processing.GlintSizeMinimum, Settings.Instance.Processing.GlintSizeMaximum, pupilCenter); } break; } //Performance.Now.Stamp("Glint detected"); return glintsDetected; }
public GlintConfiguration(Blob blob0, Blob blob1) { count = 2; centers = new GTPoint[2]; blobs = new Blobs(); blobs.BlobDir[0] = blob0; blobs.BlobDir[1] = blob1; centers[0] = new GTPoint(blob0.CenterOfGravity.X, blob0.CenterOfGravity.Y); centers[1] = new GTPoint(blob1.CenterOfGravity.X, blob1.CenterOfGravity.Y); }
/// <summary> /// Select the blob closest to the initial location /// </summary> /// <param name="initialLocation">GTPoint</param> /// <returns>Blob</returns> public BlobObject FilterByDistance(GTPoint initialLocation) { double[] distances = new double[numBlobs]; int[] keys = new int[numBlobs]; GTPoint center; for (int i = 0; i < numBlobs; i++) { center = new GTPoint(detectedBlobs[i].CentroidX, detectedBlobs[i].CentroidY); distances[i] = Operations.Distance(center, new GTPoint(initialLocation)); keys[i] = i; } Array.Sort(distances, keys); return GetBlob(keys[0]); }
private void tcpipServer_OnCalibrationFeedbackPoint(long time, int packagenumber, int targetX, int targetY, int gazeX, int gazeY, float distance, int acquisitionTime) { CalibrationWindow.Instance.Dispatcher.Invoke ( DispatcherPriority.ApplicationIdle, new Action ( delegate { //pass info from the dedicated interface to the tracker class var target = new System.Drawing.Point(targetX, targetY); var gaze = new GTPoint(gazeX, gazeY); //tracker.SaveRecalibInfo(time, packagenumber, target, gaze); /* outputting the data in a local class */ string del = " "; string msg = DateTime.Now.Ticks + del + time + del + packagenumber + del + targetX + del + targetX + del + gazeX + del + gazeY + del + distance + del + acquisitionTime; Output.Instance.appendToFile(msg); } ) ); }
/// <summary> /// Smooth method. Call this method when we get a new /// sample and it will return the smoothed coordinates /// </summary> /// <param name="newPoint">New gazed point</param> /// <returns>Smoothed point</returns> /// public GTPoint Smooth(GTPoint newPoint) { GTPoint smoothedPoint; stddev = (int) Math.Ceiling(Settings.Instance.EyeMovement.SmoothLevel/5.0); if (data.Count < numberOfSamples) data.Add(newPoint); else { data.RemoveAt(0); data.Add(newPoint); } //Javier: this has been incorporated in the eye movement detection, where it belongs //if (GetMaxDistanceOnWindow() > maxDistance) // smoothedPoint = newPoint; //else //{ var sum = new GTPoint(0, 0); double sumWeights = 0; double weight; for (int i = 0; i < data.Count; i++) { weight = GetGaussWeight(data.Count - i - 1, mean, stddev); sum.X += data[i].X*weight; sum.Y += data[i].Y*weight; sumWeights += weight; } smoothedPoint = new GTPoint(sum.X/sumWeights, sum.Y/sumWeights); //} return smoothedPoint; }
/// <summary> /// Standard deviation of an array of GTPoints /// </summary> /// <param name="num"></param> /// <returns>GTPoint</returns> public static GTPoint StandardDeviation(GTPoint[] num) { GTPoint variance = Variance(num); return(new GTPoint(Math.Sqrt(variance.X), Math.Sqrt(variance.Y))); }
private void CalculateGazeCoordinates(TrackData td) { GTPoint gazedCoordinatesLeft; GTPoint gazedCoordinatesRight = new GTPoint(); GTPoint smoothedCoordinates; #region Monocular/Left eye calibration.PupilCenterLeft = trackData.PupilDataLeft.Center; if (Settings.Instance.Processing.TrackingGlints) calibration.GlintConfigLeft = td.GlintDataLeft.Glints; gazedCoordinatesLeft = calibration.GetGazeCoordinates(td, EyeEnum.Left); #endregion #region Binocular/Right eye if (Settings.Instance.Processing.TrackingMode == TrackingModeEnum.Binocular) { calibration.PupilCenterRight = td.PupilDataRight.Center; if (Settings.Instance.Processing.TrackingGlints) calibration.GlintConfigRight = td.GlintDataRight.Glints; gazedCoordinatesRight = calibration.GetGazeCoordinates(td, EyeEnum.Right); } #endregion #region Smoothing/Eye movement state if (Settings.Instance.Processing.EyeMouseSmooth) { var p = new GTPoint(gazedCoordinatesLeft.X, gazedCoordinatesLeft.Y); if (Settings.Instance.Processing.TrackingMode == TrackingModeEnum.Binocular) { if (gazedCoordinatesRight.Y != 0 && gazedCoordinatesRight.X != 0) { p.X += gazedCoordinatesRight.X; p.Y += gazedCoordinatesRight.Y; p.X = p.X / 2; p.Y = p.Y / 2; } } this.eyeMovement.CalculateEyeMovement(p); smoothedCoordinates = exponentialSmoother.Smooth(p); //if (this.eyeMovement.EyeMovementState == Classifier.EyeMovementStateEnum.Fixation) // smoothedCoordinates = exponentialSmoother.Smooth(p); //else //{ // smoothedCoordinates = p; // this.exponentialSmoother.Stop(); //} trackData.EyeMovement = this.eyeMovement.EyeMovementState; gazeDataSmoothed.Set(smoothedCoordinates.X, smoothedCoordinates.Y, smoothedCoordinates.X, smoothedCoordinates.Y); } #endregion #region Set values, raise events // trigger OnGazeData events this.gazeDataRaw.Set( gazedCoordinatesLeft.X, gazedCoordinatesLeft.Y, gazedCoordinatesRight.X, gazedCoordinatesRight.Y); this.trackData.GazeDataRaw = this.gazeDataRaw; this.trackData.GazeDataSmoothed = this.gazeDataSmoothed; // Trigger OnExtendedGazeData events this.gazeDazaExtended.Set( this.trackData.TimeStamp, this.gazeDataRaw.GazePositionX, this.gazeDataRaw.GazePositionY, this.trackData.PupilDataLeft.Diameter, this.trackData.PupilDataRight.Diameter); #endregion }
/// <summary> /// Set the ROI of an image around a central point given the radius, which would /// correspond to the radius of the inscribed circle (e.g a pupil). The method /// checks whether the ROI is actually within the limits of the image. If it's /// not, the ROI will not be set and the method return false /// </summary> /// <param name="image">Input image</param> /// <param name="center">Central point</param> /// <param name="radius">The radius of the roi.</param> /// <returns>True if succesfull, otherwise false.</returns> /// private static Rectangle SetROI(Size imageSize, GTPoint center, double diameter) { var ROI = new Rectangle(); double aspectRatio = imageSize.Width/(double) imageSize.Height; double r = 2.5*diameter; var roiSize = new Size((int) (aspectRatio*r), (int) (aspectRatio*r)); if (center.X - roiSize.Width > 0 && center.Y - roiSize.Height > 0 && center.X + roiSize.Width < imageSize.Width && center.Y + roiSize.Height < imageSize.Height) { ROI = new Rectangle( (int) Math.Round(center.X) - roiSize.Width/2, (int) Math.Round(center.Y) - roiSize.Height/2, roiSize.Width, roiSize.Height); } else ROI = new Rectangle(new Point(0, 0), roiSize); return ROI; }
public void RecalibrateOffset(GTPoint gazeCoords, Point targetCoords) { double distanceX = gazeCoords.X - targetCoords.X; double distanceY = gazeCoords.Y - targetCoords.Y; calibration.CalibMethod.CalibrationDataLeft.CoeffsX[0, 0] -= distanceX/2; calibration.CalibMethod.CalibrationDataLeft.CoeffsY[0, 0] -= distanceY/2; if (GTSettings.Settings.Instance.Processing.TrackingMode == TrackingModeEnum.Binocular) { calibration.CalibMethod.CalibrationDataRight.CoeffsX[0, 0] += distanceX/2; calibration.CalibMethod.CalibrationDataRight.CoeffsY[0, 0] += distanceY/2; } OnRecalibrationAvailable(); }
/// <summary> /// Detect two pupils /// </summary> /// <param name="inputImage">Input image in grayscale</param> /// <returns></returns> public bool DetectTwoPupils(Image<Gray, byte> inputImage, TrackData trackData) { foundPupil = false; var initialLocation = new GTPoint(inputImage.Width/2, inputImage.Height/2); PupilGrayLevel = Settings.Instance.Processing.PupilThreshold; MinPupilSize = Settings.Instance.Processing.PupilSizeMinimum; MaxPupilSize = Settings.Instance.Processing.PupilSizeMaximum; double min = Math.PI*Math.Pow(MinPupilSize, 2); double max = Math.PI*Math.Pow(MaxPupilSize, 2); Blobs blobs = blobDetector.DetectBlobs(inputImage, PupilGrayLevel, (int) min, (int) max, false); blobs.EliminateExteriorBlobs(); if (blobDetector.IsFiltering == false) blobs.FilterByArea((int) min, (int) max); // We have 2 or more candidates if (blobs.Count > 1) { pupilData.Blob = blobs.FilterByDistance(initialLocation); if (pupilData.Blob != null) { foundPupil = true; pupilData.Center = new GTPoint(pupilData.Blob.CenterOfGravity.X, pupilData.Blob.CenterOfGravity.Y); } } else foundPupil = false; return foundPupil; }