public Dictionary<Card, Point> LocateCards(Image<Bgr, Byte> table, Settings settings) { #region process image //Convert the image to grayscale and filter out the noise Image<Gray, Byte> gray = table.Convert<Gray, Byte>(); Gray cannyThreshold = new Gray(180); Gray cannyThresholdLinking = new Gray(120); Gray circleAccumulatorThreshold = new Gray(120); Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking); StructuringElementEx el = new StructuringElementEx(3, 3, 1, 1, CV_ELEMENT_SHAPE.CV_SHAPE_RECT); cannyEdges = cannyEdges.MorphologyEx(el, CV_MORPH_OP.CV_MOP_CLOSE, 1); #endregion Contour<Point> contours = cannyEdges.FindContours( CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, //was CV_CHAIN_APPROX_SIMPLE RETR_TYPE.CV_RETR_TREE); ContourNode tree = new ContourNode(contours); Dictionary<Card, Point> cardlocs = new Dictionary<Card, Point>(); foreach (KeyValuePair<Card, CardContour> pair in GiveCards(tree)) { ContourNode node = pair.Value.Node; Card card = pair.Key; PointF fcenter = node.Contour.GetMinAreaRect().center; Point center = new Point((int)fcenter.X, (int)fcenter.Y); cardlocs.Add(card, center); } #region draw #if DEBUG TreeViz.VizualizeTree(tree); ContourAnalyzer.DrawContours(tree, table); //ImageViewer.Show(table); #endif #endregion return cardlocs; }
private Image<Bgr, Byte> Run(string filename) { Stopwatch watch = new Stopwatch(); watch.Start(); ContourAnalyzer ca = new ContourAnalyzer(); Image<Bgr, Byte> table = new Image<Bgr, byte>(filename); table = table.PyrDown().PyrDown(); int debuglevel = cmbDebuglevel.SelectedIndex; Settings settings = new Settings(debuglevel); Dictionary<Card, System.Drawing.Point> cards = ca.LocateCards(table, settings); Logic logic = new Logic(); HashSet<List<Card>> sets = logic.FindSets(new List<Card>(cards.Keys)); Random rnd = new Random(); foreach (List<Card> set in sets) { DrawSet(table, cards, rnd, set); } watch.Stop(); this.Title = String.Format("Done. Elapsed time: {0}", watch.Elapsed.ToString()); ImageSource bitmap = TreeViz.ToBitmapSource(table); Shower.Source = bitmap; return table; }
public Dictionary<SetVision.Gamelogic.Card, Point> LocateCards(Image<Bgr, byte> table, Settings settings) { throw new NotImplementedException(); }
private static CardColor RecognizeColor(ContourNode node, Settings settings) { Image<Bgr, Byte> image = node.Image; image.ROI = node.Contour.BoundingRectangle; Image<Bgr, Byte> debugBest = null; Point bestpos = FindBestColoredPixel(image, out debugBest); Bgr bgr = image[bestpos]; #region classification CardColor classification = classifier.Classify(bgr); CardColor verdict = classification; if (verdict == CardColor.Other) { if (!isGray(bgr, 10)) { verdict = ClassifyBgr2(bgr); } else { verdict = CardColor.White; } } #endregion #if DEBUG //save for training: writer.Write((int)bgr.Blue, (int)bgr.Green, (int)bgr.Red); #endif #region debug if (settings.debuglevel >= 4) { ImageViewer.Show(debugBest, verdict.ToString()); } else if (settings.debuglevel >= 2 && verdict == CardColor.Other) { ImageViewer.Show(debugBest, verdict.ToString()); } #endregion return verdict; }
private static void AssignColors(ContourNode tree, Image<Bgr, Byte> image, Settings settings) { AssignColor(tree, image, settings); foreach (ContourNode child in tree.Children) { //AssignColor(child, image, settings); AssignColors(child, image, settings); } }
private static void AssignColor(ContourNode node, Image<Bgr, Byte> image, Settings settings) { if (node.Contour.Area > 100 && ((node.Shape == Shape.Squiggle) || (node.Shape == Shape.Diamond) || (node.Shape == Shape.Oval))) { //CardColor color = RecognizeColor(image, node); //CardColor color = RecognizeColor(node); CardColor color = RecognizeColor(node, settings); node.Color = color; AssignAverageColors(node, settings); } else if (node.Shape == Shape.Card) { AssignAverageColors(node, settings); } }
private static void AssignAverageColors(ContourNode node, Settings settings) { //Then get the average color of the card (should be white or gray) Bgr avgBgr = new Bgr(); MCvScalar scr1 = new MCvScalar(); node.Image.AvgSdv(out avgBgr, out scr1, node.AttentionMask); node.averageBgr = avgBgr; Hsv avgHsv = new Hsv(); MCvScalar scr2 = new MCvScalar(); node.Image.Convert<Hsv, Byte>().AvgSdv(out avgHsv, out scr2, node.AttentionMask); node.averageBgr = avgBgr; node.averageHsv = avgHsv; }
/// <summary> /// LocateCards works by analyzing the contours in the image. /// For instance, the Diamond in Set is a polygon with exactly 4 vertices. /// The Oval has no such features yet. /// The Squiggle is not convex, but concave and has edges in a 'right bend', instead of only 'left bends' /// /// All these shapes are inside the contour of a (white) card, which is a rounded square. /// Cards may also be the (only) exterior boundaries /// </summary> /// <param name="table">An image displaying the table with the Set cards</param> /// <returns>A dict locating which cards are present where in the image</returns> public Dictionary<Card, Point> LocateCards(Image<Bgr, Byte> table, Settings settings) { classifier = new BgrHsvClassifier(); classifier.Train(); #region process image //Convert the image to grayscale and filter out the noise Image<Gray, Byte> gray = table.Convert<Gray, Byte>(); Gray cannyThreshold = new Gray(50); //180 Gray cannyThresholdLinking = new Gray(30); //120 Gray circleAccumulatorThreshold = new Gray(100); //120 #region old Image<Gray, Byte> cannyEdges = gray.Canny(cannyThreshold, cannyThresholdLinking); if (settings.debuglevel >= 3) { ImageViewer.Show(cannyEdges, "cannyEdges before Closing"); } #endregion //#region new //Image<Gray, Byte> thresholded = new Image<Gray, byte>(gray.Size); //CvInvoke.cvAdaptiveThreshold(gray.Ptr, thresholded.Ptr, // 255, // ADAPTIVE_THRESHOLD_TYPE.CV_ADAPTIVE_THRESH_GAUSSIAN_C, // THRESH.CV_THRESH_BINARY_INV, 9, 5); //StructuringElementEx el1 = new StructuringElementEx(3, 3, 1, 1, CV_ELEMENT_SHAPE.CV_SHAPE_RECT); //thresholded = thresholded.Erode(1);//thresholded.MorphologyEx(el1, CV_MORPH_OP.CV_MOP_CLOSE, 1);// //Image<Gray, Byte> cannyEdges = thresholded;//.Canny(new Gray(1), new Gray(10)); //#endregion //StructuringElementEx el = new StructuringElementEx(5, 5, 2, 2, CV_ELEMENT_SHAPE.CV_SHAPE_RECT); StructuringElementEx el = new StructuringElementEx(3, 3, 1, 1, CV_ELEMENT_SHAPE.CV_SHAPE_RECT); cannyEdges = cannyEdges.MorphologyEx(el, CV_MORPH_OP.CV_MOP_CLOSE, 1); if (settings.debuglevel >= 3) { ImageViewer.Show(cannyEdges, "cannyEdges after Closing"); } #endregion Contour<Point> contours = cannyEdges.FindContours( CHAIN_APPROX_METHOD.CV_CHAIN_APPROX_SIMPLE, //was CV_CHAIN_APPROX_SIMPLE RETR_TYPE.CV_RETR_TREE); ContourNode tree = new ContourNode(contours); FilterTree(tree); #region debug if (settings.debuglevel >= 3) { var debug = table.Clone(); DrawContours(tree, debug); ImageViewer.Show(debug, "Contours after filtering"); } #endregion AssignShapes(tree); AssignImages(tree, table, true); #region debug if (settings.debuglevel >= 3) { var debug1 = table.Clone(); DrawContours(tree, debug1); ImageViewer.Show(debug1); } #endregion FilterTree(tree); #region debug if (settings.debuglevel >= 3) { var debug2 = table.Clone(); DrawContours(tree, debug2); ImageViewer.Show(debug2); } #endregion AssignColors(tree, table, settings); #region debug if (settings.debuglevel >= 3) { TreeViz.VizualizeTree(tree); } #endregion AssignFills(tree); Dictionary<Card, Point> cardlocs = new Dictionary<Card, Point>(); foreach (KeyValuePair<Card, ContourNode> pair in GiveCards(tree)) { ContourNode node = pair.Value; Card card = pair.Key; PointF fcenter = node.Contour.GetMinAreaRect().center; Point center = new Point((int)fcenter.X, (int)fcenter.Y); cardlocs.Add(card, center); } #region debug if (settings.debuglevel >= 1) { TreeViz.VizualizeTree(tree); } if (settings.debuglevel >= 2) { DrawContours(tree, table); ImageViewer.Show(table); } #endregion return cardlocs; }