public List <DetectedCard> Detect(Bitmap bitmap, out Bitmap detectionImage) { var imageTools = new ImageTools(); var detectedCards = new List <DetectedCard>(); // Greyscale var greyscaleImage = imageTools.GreyscaleEdgeDetectionImage(bitmap); var bitmapData = greyscaleImage.LockBits( new Rectangle(0, 0, greyscaleImage.Width, greyscaleImage.Height), ImageLockMode.ReadWrite, greyscaleImage.PixelFormat); var blobCounter = new BlobCounter { FilterBlobs = true, MinHeight = Convert.ToInt32(BlobHeight * scaleFactor), MinWidth = Convert.ToInt32(BlobWidth * scaleFactor) }; blobCounter.ProcessImage(bitmapData); var blobs = blobCounter.GetObjectsInformation(); greyscaleImage.UnlockBits(bitmapData); var shapeChecker = new SimpleShapeChecker(); var cardPositions = new List <IntPoint>(); // Loop through detected shapes for (var i = 0; i < blobs.Length; i++) { var edgePoints = blobCounter.GetBlobsEdgePoints(blobs[i]); // is triangle or quadrilateral if (!shapeChecker.IsConvexPolygon(edgePoints, out var corners)) { continue; } var subType = shapeChecker.CheckPolygonSubType(corners); // Only return 4 corner rectanges if (subType != PolygonSubType.Parallelogram && subType != PolygonSubType.Rectangle || corners.Count != 4) { continue; } corners = RotateCard(corners); // Prevent it from detecting the same card twice if (cardPositions.Any(point => corners[0].DistanceTo(point) < Convert.ToInt32(40 * scaleFactor))) { continue; } // Hack to prevent it from detecting smaller sections of the card instead of the whole card if (GetArea(corners) < Convert.ToInt32(DetectionThreshold * scaleFactor)) { continue; } cardPositions.Add(corners[0]); var cardBitmap = imageTools.GetDetectedCardImage(corners, bitmap, scaleFactor); var card = new DetectedCard { Corners = corners, CardBitmap = cardBitmap }; detectedCards.Add(card); } detectionImage = greyscaleImage; return(detectedCards); }
public IdentifiedCard(DetectedCard detectedCard, Card bestMatch) { Card = bestMatch; Corners = detectedCard.Corners; }