/// <inheritdoc/>
        public bool TryFindSymbol(QSymbol currentFragment, out QAnalyzedSymbol analyzedSymbol)
        {
            /*
             * Поиск полного соответствия фрагмента символу базы знаний.
             */
            foreach (var possibleSymbol in _knownSymbols)
            {
                // Если данный символ присутствует в базе знаний
                if (
                    possibleSymbol.Codes.Where(code => code.Height == currentFragment.Monomap.Height)
                    .Any(item => item.EulerCode.GetHashCode() == currentFragment.Euler.GetHashCode()))
                {
                    analyzedSymbol = new QAnalyzedSymbol(
                        currentFragment,
                        new[]
                    {
                        new QChar(possibleSymbol.Chr, QState.Ok)
                    });
                    return(true);
                }
            }

            analyzedSymbol = null;
            return(false);
        }
Example #2
0
        /// <summary>
        /// Распарсить изображение на более меньшие.
        /// </summary>
        /// <param name="sourceImage">Исходное распознаваемое изображение.</param>
        /// <returns>Список найденных фрагментов.</returns>
        public IList <QSymbol> GetFragments(IMonomap sourceImage)
        {
            var result      = new List <QSymbol>();
            var editMonomap = new EditMonomap(sourceImage);

            for (int y = 0; y < editMonomap.Height; y++)
            {
                for (int x = 0; x < editMonomap.Width; x++)
                {
                    if (editMonomap[x, y])
                    {
                        // Заполняем первую точку, что бы внутри метода проверку не делать для заполнения.
                        BitmapPad pad = new BitmapPad();
                        pad.SetPoint(x, y);

                        // Начинаем рекурсивное создание фигуры
                        FillBitmapPad(x, y, editMonomap, pad);

                        var symbol = new QSymbol(pad, pad.TopLeftPoint, EulerCharacteristicComputer.Compute2D(pad));
                        result.Add(symbol);
                    }
                }
            }

            return(result);
        }
        private static bool IsFragmentInsideSquare(QSymbol fragment, Point leftTop, Point rightBottom)
        {
            // Признак того, что фрагмент лежит в прямоугольнике.
            var rectangle1 = new Rectangle(
                fragment.StartPoint.X,
                fragment.StartPoint.Y,
                fragment.Width,
                fragment.Height);
            var rectangle2 = new Rectangle(leftTop, new Size(rightBottom.X - leftTop.X, rightBottom.Y - leftTop.Y));

            if (Rectangle.Intersect(rectangle1, rectangle2) == Rectangle.Empty)
            {
                return(false);
            }

            return(true);
        }
        /// <inheritdoc/>
        public QAnalyzedSymbol AnalyzeFragment(
            QSymbol currentFragment,
            IEnumerable <QSymbol> unknownFragments,
            IProducerConsumerCollection <QAnalyzedSymbol> recognizedSymbols)
        {
            /*
             * Алгоритм работы.
             * P.S. Мы работаем со 100% не известным символом, либо фрагментом символа.
             *
             *
             * Input1: ip
             * Input2: Red Alert
             *  сначала будет R потом A затем l.
             *  e, d будут подмяты затем на e, r будет сплющивание вектора
             *
             * Input3: iiа  результат при анализе ii они сольются
             */

            // TODO Позже к высоте можно привязываться
            const int DefaultSplitStep         = 3;
            var       currentFragmentMinVector = currentFragment.StartPoint.Y + DefaultSplitStep;

            // Распознанные символы, лежащие в диапазоне поиска
            var currentLineRecognizedChars =
                recognizedSymbols.Where(
                    symbol =>
                    symbol.StartPoint.Y <= currentFragmentMinVector &&
                    currentFragmentMinVector <= symbol.StartPoint.Y + symbol.Height).ToArray();

            Point bottomRightPoint;

            if (currentLineRecognizedChars.Any())
            {
                var lineChars = currentLineRecognizedChars.ToDictionary(
                    symbol => symbol,
                    symbol => symbol.StartPoint.Y + symbol.Height);

                var lowestBound  = lineChars.Values.Max();
                var lowestSymbol = lineChars.First(symbol => symbol.Value == lowestBound);

                // Минимальная нижняя точка для текущей линии для распознанных символов
                var minLineY = currentFragment.StartPoint.Y + lowestSymbol.Key.Height;

                bottomRightPoint = new Point(
                    currentFragment.StartPoint.X + currentFragment.Width,
                    minLineY);
            }
            else
            {
                // Нижняя правая точка будет ширина фрагмента.
                bottomRightPoint = new Point(
                    currentFragment.StartPoint.X + currentFragment.Width,
                    currentFragment.StartPoint.Y + currentFragment.Height + _minimalHeight);
            }

            // Мерджим фрагменты которые лежат в прямоугольнике fragment.StartPoint > ! > bottomRightPoint
            QSymbol[] mergedFragments = unknownFragments.Where(
                fragment => IsFragmentInsideSquare(fragment, currentFragment.StartPoint, bottomRightPoint))
                                        .ToArray();

            EulerMonomap2D currentEuler = EulerMonomap2D.Empty;

            currentEuler = mergedFragments.Select(fragment => fragment.Euler)
                           .Aggregate(currentEuler, (current, mergedEuler) => current + mergedEuler);

            QAnalyzedSymbol analyzedSymbol;

            if (TryFindSymbol(currentFragment, out analyzedSymbol))
            {
                recognizedSymbols.TryAdd(analyzedSymbol);

                // TODO Symbol стоит смержить, но после всех манипуляций!! Саму картинку
                currentFragment = currentFragment;

                return(analyzedSymbol);
            }

            // Результат анализа всех букв !!!
            var resultData = new List <QChar>();

            // Идём по всем буквам языка
            foreach (var possibleSymbol in _knownSymbols)
            {
                QChar @char;
                if (TryIntelliRecognition(
                        possibleSymbol,
                        currentEuler,
                        bottomRightPoint.Y - currentFragment.StartPoint.Y,
                        out @char) && @char.Popularity > _comparer.MinPopularity)
                {
                    // Не стоит пропускать проверку всех символов, так как стоит найти 3 и з цифро-буквы, либо аналоги А ру. и а англ.
                    resultData.Add(@char);
                }
            }

            return(new QAnalyzedSymbol(currentFragment, resultData));
        }