/// <summary> /// /// </summary> /// <param name="image"></param> /// <param name="start"></param> /// <param name="maxEyeRadius">Should be 2-3 percent of max(width/height)</param> /// <param name="maxPointSearchDistance">In source pixels, the max distance from 'start' from which to look for the starting point. Good default: roughly 24 display pixels.</param> public static void MarkEye(UnmanagedImage image, Point start, int maxEyeRadius, float maxPointSearchDistance = 0) { int maxRadius = maxEyeRadius * 2 + (int)Math.Ceiling(maxPointSearchDistance); //Find subset Rectangle subset = new Rectangle(start.X - maxRadius, start.Y - maxRadius, maxRadius * 2, maxRadius * 2); if (subset.X < 0) { subset.Width += subset.X; subset.X = 0; } if (subset.Y < 0) { subset.Height += subset.Y; subset.Y = 0; } if (subset.Right >= image.Width) { subset.Width -= (subset.Right - image.Width + 1); } if (subset.Bottom >= image.Height) { subset.Height -= (subset.Bottom - image.Height + 1); } start.X -= subset.X; start.Y -= subset.Y; //Skip processing if we're slightly out of bounds if (subset.X < 0 || subset.Y < 0 || subset.Width < 0 || subset.Height < 0 || subset.Right >= image.Width || subset.Bottom >= image.Height) { return; } UnmanagedImage red = null; try{ Point startAt = start; using (UnmanagedImage c = new Crop(subset).Apply(image)) { red = new RedEyeFilter(2).Apply(c); if (maxPointSearchDistance > 0) { startAt = new ManualSearcher().FindMaxPixel(c, start, maxPointSearchDistance); } } var fill = new AdaptiveCircleFill(red, startAt, start, maxEyeRadius * 2); fill.FirstPass(); fill.SecondPass(); fill.CorrectRedEye(image, subset.X, subset.Y); //fill.MarkFilledPixels(image, subset.X, subset.Y, new byte[] { 0, 255, 0, 0 }); //fill.SetPixel(image, startAt.X + subset.X, startAt.Y + subset.Y, new byte[] { 255, 255, 0, 0 }); }finally{ if (red != null) { red.Dispose(); } } }