예제 #1
0
        /// <summary>
        /// Recognized single char
        /// </summary>
        /// <param name="cleanLetter">B&W thresholded image with single char as white on black background</param>
        /// <returns>Best match recognition data</returns>
        RecognizedLetter ProcessSingleLetter(Mat cleanLetter)
        {
            // ocr
            int[]    classes;
            double[] confidences;
            ocr.Eval(cleanLetter, out classes, out confidences);

            // process
            if (confidences.Length > 0)
            {
                var unit = new RecognizedLetter();
                unit.Data       = vocabulary[classes[0]].ToString();
                unit.Confidence = confidences[0];
                return(unit);
            }

            return(null);
        }
예제 #2
0
        /// <summary>
        /// Recognizes letter on the image
        /// </summary>
        /// <param name="clean">B&W thresholded image with black background and white letters</param>
        /// <param name="possibilities">ROI as a list of RotatedRect's with letters marked</param>
        /// <returns>Recognized letters</returns>
        IList <RecognizedLetter> RecognizeLetters(Mat clean, IList <RotatedRect> possibilities)
        {
            var result = new List <RecognizedLetter>();

            foreach (RotatedRect potentialLetter in possibilities)
            {
                var corners = Cv2.BoxPoints(potentialLetter);
                var chunk   = clean.UnwrapShape(corners, 64);

                // check aspect as scanner might have issues with some "tall" chars like { I, J, L, etc. } and we can
                // help the detection here: as there are no that much wide chars, we presume all strongly disproportional chars
                // to be tall and reduce rotation options
                Mat[] letters = null;
                var   size    = potentialLetter.Size;
                var   aspect  = Math.Max(size.Width, size.Height) / Math.Min(size.Width, size.Height);
                if (aspect >= 2.0)
                {
                    if (chunk.Cols > chunk.Rows)                     // it lays on "broadside", let's make it tall again
                    {
                        chunk = chunk.Rotate(RotateFlags.Rotate90Clockwise);
                    }

                    letters = new Mat[]
                    {
                        chunk,
                        chunk.Rotate(RotateFlags.Rotate180)
                    };
                }
                else
                {
                    // as we're not sure how exactly is letter rotated, we recognize it 4 times,
                    // with a 90 degrees step, than the best match (best "confidence" from OCR) is
                    // used
                    letters = new Mat[]
                    {
                        chunk,
                        chunk.Rotate(RotateFlags.Rotate90Clockwise),
                        chunk.Rotate(RotateFlags.Rotate180),
                        chunk.Rotate(RotateFlags.Rotate90CounterClockwise)
                    };
                }

                // ocr
                int selectedIndex     = -1;
                RecognizedLetter unit = null;
                var lowerCases        = new List <KeyValuePair <int, RecognizedLetter> >();
                for (int i = 0; i < letters.Length; ++i)
                {
                    var local = ProcessSingleLetter(letters[i]);
                    if (null != local && (null == unit || (null != unit && null != local && local.Confidence > unit.Confidence)))
                    {
                        if (char.IsUpper(local.Data[0]))
                        {
                            unit          = local;
                            selectedIndex = i;
                        }
                        else
                        {
                            lowerCases.Add(new KeyValuePair <int, RecognizedLetter>(i, local));
                        }
                    }

                    //Cv2.ImShow(string.Format("#{0}: {1} - {2:00.0}%", i, local.Data, local.Confidence * 100), letters[i]);
                }

                if (null == unit && lowerCases.Count > 0)
                {
                    lowerCases.Sort((x, y) => x.Value.Confidence.CompareTo(y.Value.Confidence));
                    unit          = lowerCases[0].Value;
                    selectedIndex = lowerCases[0].Key;
                }

                // process
                if (null != unit)
                {
                    // this will show each separated letter in it's own window, un-wrapped and rotated according
                    // to the best found match
                    //Cv2.ImShow(unit.Data, letters[selectedIndex]);

                    unit.Rect  = Array.ConvertAll(corners, p => new Point(Math.Round(p.X), Math.Round(p.Y)));
                    unit.Angle = (potentialLetter.Angle + selectedIndex * 90) % 360;
                    result.Add(unit);
                }
            }

            return(result);
        }