private Bitmap Compute(Bitmap inputImage) { // Define output array int[,] output; // Get the grayscale image from src int[,] grayscale = Grayscale.FromBitmap(inputImage); int width = grayscale.GetLength(0); int height = grayscale.GetLength(1); // Detect edges using sobel int[,] edges = Sobel.Compute(grayscale); bool[,] strucElem = { { false, true, false }, { true, true, true }, { false, true, false } }; // Calculate white top-hat (WTH) with plus-shaped structuring element int[,] wth = Defaults.Combine(edges, Morphologicals.Opening(edges, strucElem), (a, b) => a - b); // Create thresholds from the WTH int[,] wth60 = Threshold.Compute(wth, 60); int[,] wth30 = Threshold.Compute(wth, 30); // Calculate Hough transform const double STEP_SIZE = 0.25; int[,] hough = Hough.Compute(wth60, STEP_SIZE); int[,] houghWindow = Window.Compute(hough, 20000, int.MaxValue); // Find and filter lines from hough transform SortedSet <Line> lines = Lines.FindLines(houghWindow, STEP_SIZE); lines = Lines.FilterLines(lines); strucElem = new bool[, ] { { false, false, true, false, false }, { false, true, true, true, false }, { true, true, true, true, true }, { false, true, true, true, false }, { false, false, true, false, false } }; // Find all rectangles that somewhat resemble a card shape IList <Card> cards = Lines.FindCardShapedRectangles(lines, width, height); // Filter all card shaped rectangles with enough line support int[,] dilation = Morphologicals.Dilation(wth60, strucElem); IList <Card> filteredCards = Lines.FilterCardShapedRectangles(dilation, cards); // Set the output image, convert it to a bitmap and create a graphics object so we can draw on it switch (outputSelector.SelectedIndex) { default: case 0: output = grayscale; break; case 1: output = edges; break; case 2: output = wth; break; case 3: output = wth60; break; case 4: output = wth30; break; case 5: output = dilation; break; case 6: output = hough; break; } Bitmap outputImage = Grayscale.ToBitmap(Defaults.Normalize(output)); if (output == hough) { return(outputImage); } Graphics g = Graphics.FromImage(outputImage); // Draw the filtered lines if (drawFilteredLinesCheckbox.Checked) { DrawLines(lines, g, outputImage.Width, outputImage.Height); } // Draw the potential cards (card-shaped rectangles) if (drawFoundRectanglesCheckbox.Checked) { foreach (Card card in cards) { card.Draw(g, Pens.Yellow); } } if (drawFilteredRectanglesCheckbox.Checked) { foreach (Card card in filteredCards) { card.Draw(g, Pens.Red); } } // Classify and draw all filtered cards foreach (Card card in filteredCards) { List <ShapeInfo> shapes = Shapes.Find(wth30, card); if (shapes.Count > 10) { continue; } Suit suit = Shapes.ClassifyShapes(shapes); if (suit != Suit.Unknown) { // Draw the bboxes of the shapes if (drawBBCheckbox.Checked) { DrawShapes(shapes, g); } // Draw the card outline if (drawFoundCardsCheckbox.Checked) { card.Draw(g); } // Format the card name and print it on the card string cardName = String.Format("{0} of {1}", shapes.Count == 1 ? "Ace" : shapes.Count.ToString(), suit); g.DrawString(cardName, new Font("Arial", 14), Brushes.Orange, new PointF(card.bottomLeft.X, card.bottomLeft.Y + 4)); Console.WriteLine(cardName); } } return(outputImage); }