public void ProcessImageTest() { double[,] diag = Matrix.Magic(5); Bitmap input; new MatrixToImage().Convert(diag, out input); // Create a new Gabor filter KirschEdgeDetector filter = new KirschEdgeDetector(); // Apply the filter Bitmap output = filter.Apply(input); double[,] actual; new ImageToMatrix().Convert(output, out actual); // string str = actual.ToString(Accord.Math.Formats.CSharpMatrixFormatProvider.InvariantCulture); double[,] expected = { { 1, 1, 1, 1, 1 }, { 1, 0.458823529411765, 0.349019607843137, 0.698039215686274, 1 }, { 1, 0.309803921568627, 0.658823529411765, 0.286274509803922, 1 }, { 1, 0.619607843137255, 0.403921568627451, 0.890196078431373, 1 }, { 1, 1, 1, 1, 0.968627450980392 } }; Assert.IsTrue(expected.IsEqual(actual, 1e-6)); }
/// <summary> /// Kirsch's Edge Detector /// <para>Accord.NET internal call.</para> /// </summary> /// <typeparam name="TColor">Color type.</typeparam> /// <param name="img">Input image.</param> /// <returns>Processed image.</returns> public static TColor[,] Kirsch <TColor>(this TColor[,] img) where TColor : struct, IColor { KirschEdgeDetector k = new KirschEdgeDetector(); return(img.ApplyFilter(k)); }
/// <summary> /// Kirsch's Edge Detector /// <para>Accord.NET internal call.</para> /// </summary> /// <typeparam name="TColor">Color type.</typeparam> /// <typeparam name="TDepth">Depth type.</typeparam> /// <param name="img">Input image.</param> /// <returns>Processed image.</returns> public static Image <TColor, TDepth> Kirsch <TColor, TDepth>(this Image <TColor, TDepth> img) where TColor : IColor where TDepth : struct { KirschEdgeDetector k = new KirschEdgeDetector(); return(img.ApplyFilter(k)); }
public void ApplyTest1() { Bitmap image = Accord.Imaging.Image.Clone(Resources.lena512); KirschEdgeDetector kirsch = new KirschEdgeDetector(); Bitmap edges = kirsch.Apply(image); // ImageBox.Show(edges); Assert.IsNotNull(edges); }
public void ApplyTest1() { Bitmap image = Properties.Resources.lena512; KirschEdgeDetector kirsch = new KirschEdgeDetector(); Bitmap edges = kirsch.Apply(image); // ImageBox.Show(edges); Assert.IsNotNull(edges); }
public static (List <Rectangle> rectangles, int cols, int rows) ProcessScreenshot(Bitmap screenshot) { var card = new RECT( Left: 0, Top: 0, Right: (int)(85 / 1280.0 * screenshot.Width), Bottom: (int)(100 / 720.0 * screenshot.Height)); // Filter for relative size of items in inventory, give or take a few pixels using (BlobCounter blobCounter = new BlobCounter { FilterBlobs = true, MinHeight = card.Height - 15, MaxHeight = card.Height + 15, MinWidth = card.Width - 15, MaxWidth = card.Width + 15, }) { // Image pre-processing screenshot = new KirschEdgeDetector().Apply(screenshot); // Algorithm to find edges. Really good but can take ~1s screenshot = new Grayscale(0.2125, 0.7154, 0.0721).Apply(screenshot); screenshot = new Threshold(100).Apply(screenshot); // Convert to black and white only based on pixel intensity blobCounter.ProcessImage(screenshot); // Note: Processing won't always detect all item rectangles on screen. Since the // background isn't a solid color it's a bit trickier to filter out. if (blobCounter.ObjectsCount < 7) { throw new Exception(); } // Don't save overlapping blobs List <Rectangle> rectangles = new List <Rectangle>(); List <Rectangle> blobRects = blobCounter.GetObjectsRectangles().ToList(); int minWidth = blobRects[0].Width; int minHeight = blobRects[0].Height; foreach (var rect in blobRects) { bool add = true; foreach (var item in rectangles) { Rectangle r1 = rect; Rectangle r2 = item; Rectangle intersect = Rectangle.Intersect(r1, r2); if (intersect.Width > r1.Width * .2) { add = false; break; } } if (add) { minWidth = Math.Min(minWidth, rect.Width); minHeight = Math.Min(minHeight, rect.Height); rectangles.Add(rect); } } // Determine X and Y coordinates for columns and rows, respectively var colCoords = new List <int>(); var rowCoords = new List <int>(); foreach (var item in rectangles) { bool addX = true; bool addY = true; foreach (var x in colCoords) { var xC = item.Center().X; if (x - 50 / 1280.0 * screenshot.Width <= xC && xC <= x + 50 / 1280.0 * screenshot.Width) { addX = false; break; } } foreach (var y in rowCoords) { var yC = item.Center().Y; if (y - 50 / 720.0 * screenshot.Height <= yC && yC <= y + 50 / 720.0 * screenshot.Height) { addY = false; break; } } if (addX) { colCoords.Add(item.Center().X); } if (addY) { rowCoords.Add(item.Center().Y); } } // Going to use X,Y coordinate pairings to build rectangles around. Items that might have been missed // This is quite accurate and algorithmically puts rectangles over all items on the screen that were missed. // The center of each of these rectangles should be a good enough spot to click. rectangles.Clear(); colCoords.Sort(); rowCoords.Sort(); colCoords.RemoveAll(col => col > screenshot.Width * 0.65); foreach (var row in rowCoords) { foreach (var col in colCoords) { int x = (int)(col - (minWidth * .5)); int y = (int)(row - (minHeight * .5)); rectangles.Add(new Rectangle(x, y, minWidth, minHeight)); } } // Remove some rectangles that somehow overlap each other. Don't think this happens // but it doesn't hurt to double check. for (int i = 0; i < rectangles.Count - 1; i++) { for (int j = i + 1; j < rectangles.Count; j++) { Rectangle r1 = rectangles[i]; Rectangle r2 = rectangles[j]; Rectangle intersect = Rectangle.Intersect(r1, r2); if (intersect.Width > r1.Width * .2) { rectangles.RemoveAt(j); } } } // Sort by row then by column within each row rectangles = rectangles.OrderBy(r => r.Top).ThenBy(r => r.Left).ToList(); Debug.WriteLine($"{colCoords.Count} columns: "); colCoords.ForEach(c => Debug.Write(c + ", ")); Debug.WriteLine(""); Debug.WriteLine($"{rowCoords.Count} rows: "); rowCoords.ForEach(c => Debug.Write(c + ", ")); Debug.WriteLine(""); Debug.WriteLine($"{rectangles.Count} rectangles"); return(rectangles, colCoords.Count, rowCoords.Count); } }