/// <summary> /// Converts a paper color to a string representation. /// </summary> /// <param name="paperColor">PaperColor to convert to string.</param> /// <returns></returns> public static string PaperColorToString(PaperColor paperColor) { switch(paperColor) { case PaperColor.UNKNOWN: return "Unknown"; case PaperColor.YELLOW: return "Yellow"; case PaperColor.GREEN: return "Green"; default: return "Invalid Enum Value"; } }
/// <summary> /// Adds paper colors from a contour into the grid. /// </summary> /// <param name="contourImage">Source image.</param> /// <param name="papers">Grid to add paper colors to.</param> /// <param name="paperContours">Contours to add to grid.</param> /// <param name="paperColor">Color of paper to add to grid.</param> private void detectColumns(Image<Bgr, byte> contourImage, Paper[,] papers, List<Contour<Point>> paperContours, PaperColor paperColor) { foreach (Contour<Point> paperContour in paperContours) { int x; int xMidPoint = paperContour.BoundingRectangle.X + paperContour.BoundingRectangle.Width / 2; if (xMidPoint < contourImage.Width * LEFT_WIDTH_THRESHOLD) { x = 0; } else if (xMidPoint > contourImage.Width * RIGHT_WIDTH_THRESHOLD) { x = 2; } else { x = 1; } int y; int yMidPoint = paperContour.BoundingRectangle.Y + paperContour.BoundingRectangle.Height / 2; if (yMidPoint < contourImage.Height * TOP_HEIGHT_THRESHOLD) { y = 0; } else if(yMidPoint > contourImage.Height * BOTTOM_HEIGHT_THRESHOLD) { y = 2; } else { y = 1; } Paper currentPaper = papers[y, x]; currentPaper.Color = paperColor; currentPaper.XMidPoint = xMidPoint; currentPaper.YMidPoint = yMidPoint; currentPaper.ParentImageWidth = contourImage.Width; currentPaper.ParentImageHeight = contourImage.Height; } }
/// <summary> /// Display the detected digit and coloumns of paper colors on the UI. /// </summary> /// <param name="digitDetected">Detected Digit</param> /// <param name="paperColors">All Paper Colors Detected</param> public void DigitDetected(int digitDetected, PaperColor[] paperColors) { if (this.InvokeRequired) { DigitDetectionCallbackSetDigit callback = new DigitDetectionCallbackSetDigit(DigitDetected); try { this.Invoke(callback, new object[] { digitDetected, paperColors }); } catch (ObjectDisposedException) { // No Op } } else { this.detectedDigitLbl.Text = digitDetected.ToString(); this.cell0Txt.Text = PaperColorUtils.PaperColorToString(paperColors[0]); this.cell1Txt.Text = PaperColorUtils.PaperColorToString(paperColors[1]); this.cell2Txt.Text = PaperColorUtils.PaperColorToString(paperColors[2]); this.cell3Txt.Text = PaperColorUtils.PaperColorToString(paperColors[3]); this.cell4Txt.Text = PaperColorUtils.PaperColorToString(paperColors[4]); this.cell5Txt.Text = PaperColorUtils.PaperColorToString(paperColors[5]); this.cell6Txt.Text = PaperColorUtils.PaperColorToString(paperColors[6]); this.cell7Txt.Text = PaperColorUtils.PaperColorToString(paperColors[7]); this.cell8Txt.Text = PaperColorUtils.PaperColorToString(paperColors[8]); this.cell9Txt.Text = PaperColorUtils.PaperColorToString(paperColors[9]); this.cell10Txt.Text = PaperColorUtils.PaperColorToString(paperColors[10]); this.cell11Txt.Text = PaperColorUtils.PaperColorToString(paperColors[11]); this.cell12Txt.Text = PaperColorUtils.PaperColorToString(paperColors[12]); this.cell13Txt.Text = PaperColorUtils.PaperColorToString(paperColors[13]); this.cell14Txt.Text = PaperColorUtils.PaperColorToString(paperColors[14]); } }
/// <summary> /// Detects and stores the center columns in the current paper grid. /// See <see cref="State.COLUMN_DETECTION"/>. /// </summary> /// <param name="papers">Current Paper Grid</param> /// <returns><see cref="State.STEER_TO_MOVE"/> if there are more /// columns. <see cref="State.CALCULATE_DIGIT"/> if all columns /// have now been checked.</returns> private State columnDetection(Paper[,] papers) { PaperColor[] paperColorColumn = new PaperColor[3]; // Top Column paperColorColumn[0] = papers[0, 1].Color; // Middle Column paperColorColumn[1] = papers[1, 1].Color; // Bottom Column paperColorColumn[2] = papers[2, 1].Color; this.paperColumns.Add(paperColorColumn); if (this.paperColumns.Count < COLUMN_COUNT) { return State.STEER_TO_MOVE; } else { return State.CALCULATE_DIGIT; } }
/// <summary> /// Calculates the digit represented by all of the /// paper color columns. The detected digit is sent /// to the UI using /// <see cref="IDigitDetectionCallback.DigitDetected(int, PaperColor[])"/>. /// </summary> /// <param name="papers">Current Paper Grid</param> /// <returns><see cref="State.STEER_720_DEGREES"/></returns> private State calculateDigit(Paper[,] papers) { // The columns are read top to bottom; however, the digit needs to // be bottom to top, which translate into left to right when the // digit is compared. for (int i = 0; i < this.paperColumns.Count; i++) { PaperColor temp = this.paperColumns[i][0]; this.paperColumns[i][0] = this.paperColumns[i][2]; this.paperColumns[i][2] = temp; } if (this.direction == Direction.LEFT) { this.paperColumns.Reverse(); } // Convert paper color columns to an array PaperColor[] paperColors = new PaperColor[this.paperColumns.Count * 3]; for (int i = 0; i < paperColumns.Count; i++) { for(int j = 0; j < 3; j++) { paperColors[i * papers.GetLength(0) + j] = this.paperColumns[i][j]; } } int matchNumber = 0; int matchCount = 0; // Find the digit that is the closest match. The idea behind // this algorithm is that the closest match is the digit with // the most papers in common with the digit represented by // the paper viewed by the robot. In the event that the robot // is unable to read a sheet of paper, this algorithm assumes // that it would have been a match. for(int i = 0; i < this.digitsToMatch.GetLength(0); i++) { int currentMatchCount = 0; for(int j = 0; j < this.digitsToMatch.GetLength(1); j++) { if(paperColors[j] == PaperColor.UNKNOWN) { currentMatchCount++; } else if(paperColors[j] == this.digitsToMatch[i, j]) { currentMatchCount++; } } if(currentMatchCount > matchCount) { matchNumber = i; matchCount = currentMatchCount; } } this.callback.DigitDetected(matchNumber, paperColors); return State.STEER_720_DEGREES; }