Пример #1
0
        public bool TryGetAverageColor(Bitmap image, Rectangle bounds, int ColorThreshold, out ColorDouble averageColor)
        {
            averageColor = new ColorDouble();
            var count = 0;

            for (var x = bounds.Left; x < bounds.Right; x++)
            {
                for (var y = bounds.Top; y < bounds.Bottom; y++)
                {
                    var color = image.GetPixel(x, y);
                    if (count > 0 && ColorDiff(averageColor / count, color) > ColorThreshold)
                    {
                        return(false);
                    }
                    averageColor += color;
                    count++;
                }
            }
            averageColor = averageColor / count;
            return(true);
        }
Пример #2
0
        public double GetColorPercentOnCircle(Bitmap image, ColorDouble color, Point center, double radius, int colorThreshold)
        {
            var totalCount = 0;
            var colorCount = 0;

            for (var angle = 0d; angle < 2 * Math.PI; angle += 1 / radius)
            {
                var p = new Point((int)(center.X + Math.Cos(angle) * radius), (int)(center.Y + Math.Sin(angle) * radius));
                if (p.X < 0 || p.Y < 0 || p.X >= image.Width || p.Y >= image.Height)
                {
                    continue;
                }
                var pixel = image.GetPixel(p.X, p.Y);
                if (ColorDiff(color, pixel) < colorThreshold)
                {
                    colorCount++;
                }
                totalCount++;
            }
            return(colorCount * 1.0 / totalCount);
        }
Пример #3
0
        public RecognizerResult Run(Bitmap image)
        {
            var colorThreshold = 25;
            var needDispose    = false;
            var multiplier     = 1;
            var smallImage     = image;

            while (smallImage.Width > 600 || smallImage.Height > 600)
            {
                Log?.Debug("Downsample image to {0} x {1} for faster initial search", smallImage.Width / 2, smallImage.Height / 2);
                var newImage = new Bitmap(smallImage, new Size(smallImage.Width / 2, smallImage.Height / 2));
                multiplier *= 2;
                if (needDispose)
                {
                    smallImage.Dispose();
                }
                smallImage  = newImage;
                needDispose = true;
            }
            try
            {
                var corners = new Rectangle[] {
                    new Rectangle(0, 0, 10, 10),
                    new Rectangle(smallImage.Width - 10, 0, 10, 10),
                    new Rectangle(0, smallImage.Height - 10, 10, 10),
                    new Rectangle(smallImage.Width - 10, smallImage.Height - 10, 10, 10)
                };
                var backColorFound = false;
                var backColor      = new ColorDouble();
                foreach (var corner in corners)
                {
                    Log?.Debug("Selecting background color as average of {0} rectangle", corner);
                    if (Tools.TryGetAverageColor(smallImage, corner, colorThreshold, out backColor))
                    {
                        backColorFound = true;
                        Log?.Info("Treating color {0} as background color", backColor);
                        break;
                    }
                    else
                    {
                        Log?.Debug("Color at {0} are mixed - trying other corner", corner);
                    }
                }
                if (!backColorFound)
                {
                    Log?.Error("Failed to determing background color");
                    return(null);
                }
                var colors = Tools.GetImageColors(smallImage, colorThreshold);
                colors.Sort((x, y) => y.Count - x.Count);
                Log?.Debug("Retrieved all image colors: {0}",
                           colors.Aggregate("", (s, c) => s + (s.Length > 0 ? ", " : "") + c));
                Log?.Debug("Taking the most used color that is not a background");
                var outerCircleColor = colors.First(c => Tools.ColorDiff(backColor, c.Color) >= colorThreshold).Color;
                Log?.Info("Outer circle color = {0}", outerCircleColor);

                Log?.Debug("Scanning for outer circle bounds a for lines, that have more than 5% of outer circle color");
                int outerCircleLeft, outerCircleRight, outerCircleTop, outerCircleBottom;

                if (!Tools.TryLineScan <int>(smallImage, new Rectangle(Point.Empty, smallImage.Size),
                                             LineScanDirection.LeftToRight,
                                             (count, color) => count + (Tools.ColorDiff(outerCircleColor, color) < colorThreshold ? 1 : 0),
                                             (count) => count > smallImage.Height / 20,
                                             out outerCircleLeft))
                {
                    Log?.Error("Failed to find left border of the outer circle");
                    return(null);
                }
                if (!Tools.TryLineScan <int>(smallImage, new Rectangle(Point.Empty, smallImage.Size),
                                             LineScanDirection.RightToLeft,
                                             (count, color) => count + (Tools.ColorDiff(outerCircleColor, color) < colorThreshold ? 1 : 0),
                                             (count) => count > smallImage.Height / 20,
                                             out outerCircleRight))
                {
                    Log?.Error("Failed to find right border of the outer circle");
                    return(null);
                }
                if (!Tools.TryLineScan <int>(smallImage, new Rectangle(Point.Empty, smallImage.Size),
                                             LineScanDirection.TopToBottom,
                                             (count, color) => count + (Tools.ColorDiff(outerCircleColor, color) < colorThreshold ? 1 : 0),
                                             (count) => count > smallImage.Width / 20,
                                             out outerCircleTop))
                {
                    Log?.Error("Failed to find top border of the outer circle");
                    return(null);
                }
                if (!Tools.TryLineScan <int>(smallImage, new Rectangle(Point.Empty, smallImage.Size),
                                             LineScanDirection.BottomToTop,
                                             (count, color) => count + (Tools.ColorDiff(outerCircleColor, color) < colorThreshold ? 1 : 0),
                                             (count) => count > smallImage.Width / 20,
                                             out outerCircleBottom))
                {
                    Log?.Error("Failed to find bottom border of the outer circle");
                    return(null);
                }
                Log?.Info("Outer circle bounds: ({0}, {1}) - ({2}, {3})", outerCircleLeft, outerCircleTop, outerCircleRight, outerCircleBottom);
                var center = new Point((outerCircleLeft + outerCircleRight) / 2 * multiplier + multiplier / 2, (outerCircleTop + outerCircleBottom) / 2 * multiplier + multiplier / 2);
                var radius = (outerCircleRight - outerCircleLeft + outerCircleBottom - outerCircleTop) / 4.0 * multiplier + multiplier / 2;
                Log?.Info("Draftly taking {0} as a center and {1} as radius", center, radius);

                colorThreshold = (int)Tools.ColorDiff(backColor, outerCircleColor) / 2;
                Log?.Debug("Adjusting color threshold to {0} - half difference between back and outer circle color", colorThreshold);

                AdjustCenterAndRadius(image, outerCircleColor, colorThreshold, ref center, ref radius);
                Log?.Info("Adjusted center {0} and radius {1}", center, radius);

                ColorDouble innerCircleColor;
                Tools.TryGetAverageColor(image, new Rectangle(center.X - 5, center.Y - 5, 10, 10), 3 * 255, out innerCircleColor);
                Log?.Info("Taking color {0} from center of outer circle as color of inner circle", innerCircleColor);

                colorThreshold = (int)Math.Max(10, Tools.ColorDiff(outerCircleColor, innerCircleColor) / 2);
                Log?.Info("Taking {0} as color threshold for border of inner circle", colorThreshold);

                int innerCircleLeft   = center.X - (int)radius,
                    innerCircleRight  = center.X + (int)radius,
                    innerCircleTop    = center.Y - (int)radius,
                    innerCircleBottom = center.Y + (int)radius;
                for (var x = center.X; x > center.X - radius; x--)
                {
                    if (Tools.ColorDiff(innerCircleColor, image.GetPixel(x, center.Y)) >= colorThreshold)
                    {
                        innerCircleLeft = x;
                        break;
                    }
                }
                for (var x = center.X; x < center.X + radius; x++)
                {
                    if (Tools.ColorDiff(innerCircleColor, image.GetPixel(x, center.Y)) >= colorThreshold)
                    {
                        innerCircleRight = x;
                        break;
                    }
                }
                for (var y = center.Y; y > center.Y - radius; y--)
                {
                    if (Tools.ColorDiff(innerCircleColor, image.GetPixel(center.X, y)) >= colorThreshold)
                    {
                        innerCircleTop = y;
                        break;
                    }
                }
                for (var y = center.Y; y < center.Y + radius; y++)
                {
                    if (Tools.ColorDiff(innerCircleColor, image.GetPixel(center.X, y)) >= colorThreshold)
                    {
                        innerCircleBottom = y;
                        break;
                    }
                }
                Log?.Info("Inner circle bounds: ({0}, {1}) - ({2}, {3})", innerCircleLeft, innerCircleTop, innerCircleRight, innerCircleBottom);
                var innerCenter = new Point((innerCircleLeft + innerCircleRight) / 2, (innerCircleTop + innerCircleBottom) / 2);
                var innerRadius = (innerCircleRight - innerCircleLeft + innerCircleBottom - innerCircleTop) / 4.0;
                Log?.Info("Draftly taking {0} as a inner circle center and {1} as radius", innerCenter, innerRadius);

                AdjustCenterAndRadius(image, innerCircleColor, colorThreshold, ref innerCenter, ref innerRadius);
                Log?.Info("Adjusted inner circle center {0} and radius {1}", innerCenter, innerRadius);

                return(new RecognizerResult {
                    OuterCircleCenter = center,
                    OuterCircleRadius = radius,
                    InnerCircleCenter = innerCenter,
                    InnerCircleRadius = innerRadius
                });
            }
            finally
            {
                if (needDispose)
                {
                    smallImage.Dispose();
                }
            }
        }
Пример #4
0
 public double ColorDiff(ColorDouble x, ColorDouble y)
 {
     return(Math.Abs(x.R - y.R) + Math.Abs(x.G - y.G) + Math.Abs(x.B - y.B));
 }