/// <summary>
        /// This function checks all sentences if there are components which have an angle
        /// of 90 degrees, if so they will be merged
        /// </summary>
        public static void MergeComponentsInSentences(PageImage Image)
        {
            int           index;
            double        Angle;
            PageComponent Left, Right;

            foreach (Sentence Sentence in Image.Sentences)
            {
                for (index = 0; index < Sentence.Count - 1; index++)
                {
                    Left  = Sentence.Components[index];
                    Right = Sentence.Components[index + 1];

                    if (Left.Type == ePageComponentType.eCharacter &&
                        Right.Type == ePageComponentType.eCharacter)
                    {
                        Angle = PageComponent.AngleBetweenComponents(Left, Right);

                        if (Angle > 88 && Angle < 92)
                        {
                            Left.Merge(Right);
                            Sentence.Delete(index + 1);
                        }
                    }
                }
            }
        }
Пример #2
0
        private static void GenerateBitmap(PageImage Image, PageComponent Component, List <Point> Pixels)
        {
            //Generate a bitmap of the connected component. The bitmap contains only
            //pixels of the connected component and no other ones. The bitmaps has the
            //size of the bounding rectangle of the connected component

            int Size;

            Size = Component.Stride * Component.Height;

            Component.Bytes       = new Byte[Component.Width, Component.Height];
            Component.BinaryBytes = new Byte[Component.Width, Component.Height];

            for (int x = 0; x < Component.Width; x++)
            {
                for (int y = 0; y < Component.Height; y++)
                {
                    Component.Bytes[x, y]       = 0xFF;
                    Component.BinaryBytes[x, y] = 0xFF;
                }
            }

            foreach (Point Pixel in Pixels)
            {
                Component.Bytes[Pixel.X - Component.Area.X, Pixel.Y - Component.Area.Y]       = Image.Bytes[Pixel.X, Pixel.Y];
                Component.BinaryBytes[Pixel.X - Component.Area.X, Pixel.Y - Component.Area.Y] = 0x00;
            }

            Pixels.Clear();


            //int Source;
            //int Destination;
            //    int y = Component.Area.Height;
            //    int x = Component.Area.Width;

            //    while (y > 0)
            //    {
            //        y--;

            //        Source = (Component.Area.X + x) + (Component.Area.Y + y) * Image.Stride;
            //        Destination = x + y * Component.Stride;

            //        while (x > 0)
            //        {
            //            x--;
            //            Destination--;
            //            Source--;

            //            if (Image.ImageBytes[Source] != 0xFF)
            //            {
            //                Component.ComponentBytes[Destination] = 0x00;
            //            }
            //            else
            //            {
            //                Component.ComponentBytes[Destination] = 0xFF;
            //            }
            //        }
            //    }
        }
        /// <summary>
        /// This function creates/calculates the input for a neural network
        /// </summary>
        /// <param name="Component"></param>
        /// <returns></returns>
        public static sNeuralInput CalculateNetworkInput(PageComponent Component)
        {
            sNeuralInput Input;

            Input = new sNeuralInput();

            //Initialize input
            for (int index = 0; index < 48; index++)
            {
                Input.fInputs.Add(0);
            }

            //Add stroke direction
            for (int i = 0; i < 8; i++)
            {
                for (int j = 0; j < 4; j++)
                {
                    Input.fInputs[i + 0] += Component.lStrokeDirectionX[i * 4 + j];
                    Input.fInputs[i + 8] += Component.lStrokeDirectionY[i * 4 + j];
                }
            }

            for (int i = 0; i < 2; i++)
            {
                for (int j = 0; j < 2; j++)
                {
                    Input.fInputs[16 + i + j * 2] = Component.lStrokeMatrixNW[i, j];
                    Input.fInputs[20 + i + j * 2] = Component.lStrokeMatrixSW[i, j];
                }
            }

            int Pointer;

            //Add endpoints and junctions
            for (int x = 0; x < 3; x++)
            {
                for (int y = 0; y < 3; y++)
                {
                    Pointer = 24 + x + y * 3;
                    Input.fInputs[Pointer] = Component.PixelTypeProjectionEndpoint[x, y];

                    Pointer = 33 + x + y * 3;
                    Input.fInputs[Pointer] = Component.PixelTypeProjectionJunction[x, y];
                }
            }

            //Add width/height ratio
            Input.fInputs[42] = Component.AspectRatio;

            //Add position
            Input.fInputs[43] = Component.Position.Ascent  ? 1.0 : 0.0;
            Input.fInputs[44] = Component.Position.Height  ? 1.0 : 0.0;
            Input.fInputs[45] = Component.Position.Center  ? 1.0 : 0.0;
            Input.fInputs[46] = Component.Position.Base    ? 1.0 : 0.0;
            Input.fInputs[47] = Component.Position.Descent ? 1.0 : 0.0;

            return(Input);
        }
        /// <summary>
        ///This function takes a to be deleted component and sees whether it could
        ///be a part of another component in the outer sentence. It could be a
        ///dot for example. If so, it will merged.
        /// </summary>
        /// <param name="InnerSentence"></param>
        /// <param name="OuterSentence"></param>
        public static void MergeRectangles(Sentence InnerSentence, Sentence OuterSentence)
        {
            int    MinDistance = 1000;
            int    Distance;
            double BestAngle = 90;
            double Angle;
            double AverageAngle;

            PageComponent InnerComponent;
            PageComponent MergeComponent = null;

            InnerComponent = InnerSentence.Components[0];

            if (InnerComponent.Type != ePageComponentType.eCharacter)
            {
                return;
            }

            AverageAngle = OuterSentence.AverageAngle();

            //we merge two rectangles if:
            //1. the distance between them is the minimum in comparing to other pairs in the sentence
            //2. if the angle between them is the best 90 degress angle in comparision to the average angle

            foreach (PageComponent OuterComponent in OuterSentence.Components)
            {
                Distance = PageComponent.DistanceBetweenComponents(OuterComponent, InnerComponent);

                if (Distance < MinDistance && OuterComponent.Type == ePageComponentType.eCharacter)
                {
                    Angle = PageComponent.AngleBetweenComponents(OuterComponent, InnerComponent);
                    Angle = (Angle % 180) - 90 + AverageAngle;

                    if (Math.Abs(Angle) <= 10)
                    {
                        if (Math.Abs(Angle) <= BestAngle)
                        {
                            //Check if the distance isn't to great, but if the angle is exact 90 degrees always
                            //do a merge.
                            if (Distance <= 3 * Math.Max(OuterComponent.Width, OuterComponent.Height) ||
                                Angle == 0)
                            {
                                BestAngle      = Math.Abs(Angle);
                                MergeComponent = OuterComponent;
                                MinDistance    = Distance;
                            }
                        }
                    }
                }
            }

            if (MergeComponent != null)
            {
                //we found a rectangle with which we can merge
                MergeComponent.Merge(InnerComponent);
            }
        }
        /// <summary>
        /// This functions 'recognises' the given compontent by running its features through
        /// a neural network.
        /// </summary>
        /// <param name="Component"></param>
        public static void RecogniseWithoutConnectedRepair(ShapeNet ShapeNet, PageComponent Component)
        {
            sNeuralOutput Result = new sNeuralOutput();

            ShapeNet.NeuralNetwork.ComputeOutput(RecogniseComponent.CalculateNetworkInput(Component), Result);

            for (int i = 0; i < Result.fOutputs.Count; i++)
            {
                if (Result.fOutputs[i] >= 0.01)
                {
                    Component.AddRecognitionResult(Result.fOutputs[i], ShapeNet.ShapeList[i].Shape);
                }
            }
        }
Пример #6
0
        /// <summary>
        /// This function calculates the angle between two component.
        /// </summary>
        /// <param name="From"></param>
        /// <param name="To"></param>
        /// <returns></returns>
        public static double AngleBetweenComponents(PageComponent From, PageComponent To)
        {
            double dx, dy, dInput, dAngle;
            int    xTo, xFrom, yTo, yFrom;

            xTo   = To.Area.X;
            xFrom = From.Area.X;
            yTo   = To.Area.Y;
            yFrom = From.Area.Y;

            if (xTo <= xFrom && (xTo + To.Area.Width) > xFrom)
            {
                xTo = xFrom;
            }
            if (xFrom <= xTo && (xFrom + From.Area.Width) > xTo)
            {
                xFrom = xTo;
            }
            if (yTo <= yFrom && (yTo + To.Area.Height) > yFrom)
            {
                yTo = yFrom;
            }
            if (yFrom <= yTo && (yFrom + From.Area.Height) > yTo)
            {
                yFrom = yTo;
            }


            dx = System.Math.Abs(xTo - xFrom);
            dy = System.Math.Abs(yTo - yFrom);

            if (dx != 0)
            {
                dInput = dy / dx;

                dAngle = ((System.Math.Atan(dInput) * 360) / (2 * System.Math.PI));
            }
            else
            {
                if (yTo != yFrom)
                {
                    dAngle = 90;
                }
                else
                {
                    dAngle = 0;
                }
            }
            return(dAngle);
        }
        /// <summary>
        ///this function add spaces to sentences. Space are added between two
        ///characters when the space between the two is larger than
        ///60 percent of the average width of all the characters in the sentence
        /// </summary>
        /// <param name="Image"></param>

        public static void AddSpacesToSentences(PageImage Image)
        {
            int           Pointer;
            int           AverageWidthCharacters;
            int           WidthBetweenCharacters;
            int           nSpaces;
            PageComponent newSpace;
            Rectangle     newArea;
            Point         Component1, Component2;


            foreach (Sentence Sentence in Image.Sentences)
            {
                Pointer = Sentence.Count - 1;
                AverageWidthCharacters = (int)(Sentence.AverageWidth() * 0.60);

                if (Sentence.Components.Count > 1)
                {
                    while (Pointer > 0)
                    {
                        WidthBetweenCharacters = (int)PageComponent.DistanceBetweenComponents(Sentence.Components[Pointer], Sentence.Components[Pointer - 1]);
                        if (WidthBetweenCharacters >= AverageWidthCharacters && AverageWidthCharacters > 0)
                        {
                            nSpaces    = WidthBetweenCharacters / AverageWidthCharacters;
                            Component1 = Sentence.Components[Pointer - 1].CenterPoint;
                            Component2 = Sentence.Components[Pointer].CenterPoint;

                            for (int j = 0; j < nSpaces; j++)
                            {
                                //to do: the area part is mostly for visualising the space. Doesn't really needs to
                                //be there. This is an option to speed it up.
                                newSpace      = new PageComponent();
                                newSpace.Type = ePageComponentType.eSpace;


                                newArea = new Rectangle((Component2.X - Component1.X) / nSpaces + Component1.X,
                                                        (Component2.Y - Component1.Y) / nSpaces + Component1.Y,
                                                        2,
                                                        2);
                                newSpace.Area = newArea;

                                Sentence.Insert(Pointer, newSpace);
                            }
                        }
                        Pointer--;
                    }
                }
            }
        }
Пример #8
0
        /// <summary>
        /// Returns the average angle between the components in the sentence
        /// </summary>
        /// <returns></returns>
        public double AverageAngle()
        {
            if (m_AverageAngle == -1)
            {
                if (Components.Count > 0)
                {
                    m_AverageAngle = PageComponent.AngleBetweenComponents(Components.First(), Components.Last());
                }
            }

            //int PointerFrom, PointerTo, ComponentCount;

            //if (m_AverageAngle == -1) {

            //    ComponentCount = 0;
            //    m_AverageAngle = 0;

            //    PointerFrom = 0;
            //    PointerTo = 0;

            //    do
            //    {
            //        while (Components[PointerTo].Type == eRectangleType.eSpace && PointerTo < Components.Count)
            //        {
            //            PointerTo++;
            //        }

            //        if (PointerTo < Components.Count)
            //        {
            //            m_AverageAngle += PageComponent.AngleBetweenComponents(Components[PointerFrom], Components[PointerTo]);
            //            ComponentCount++;
            //        }

            //        PointerFrom = PointerTo;
            //        PointerTo++;

            //    } while (PointerTo < Components.Count);

            //    if (ComponentCount > 0)
            //    {
            //        m_AverageAngle = m_AverageAngle / ComponentCount;
            //    }
            //}

            return(m_AverageAngle);
        }
Пример #9
0
        /// <summary>
        /// This function calculates the distance between the center points of two components
        /// </summary>
        /// <param name="From"></param>
        /// <param name="To"></param>
        /// <returns></returns>
        public static long Distance(PageComponent From, PageComponent To)
        {
            long  lRetValue;
            Point Pos1;
            Point Pos2;

            double root1, root2;

            Pos1 = From.CenterPoint;
            Pos2 = To.CenterPoint;

            root1     = System.Math.Pow(System.Math.Abs(Pos1.X - Pos2.X), 2);
            root2     = System.Math.Pow(System.Math.Abs(Pos1.Y - Pos2.Y), 2);
            lRetValue = (long)System.Math.Sqrt(root1 + root2);

            return(lRetValue);
        }
Пример #10
0
        private static void CreateTrainingData(OCR.ShapeNet ShapeNet, List <Example> Examples)
        {
            NeuralNetwork.LearningData oLearningData;
            OCR.PageComponent          PageComponent;
            sNeuralInput newInput;

            foreach (Example Example in Examples)
            {
                PageComponent = new OCR.PageComponent();
                PageComponent.LoadBitmap(Example.Filename);

                ExtractFeatures.ExecuteExtractFeatures(PageComponent, true);

                PageComponent.Position.Ascent  = ShapeNet.ShapeList[Example.ShapeId].Position.Ascent;
                PageComponent.Position.Height  = ShapeNet.ShapeList[Example.ShapeId].Position.Height;
                PageComponent.Position.Center  = ShapeNet.ShapeList[Example.ShapeId].Position.Center;
                PageComponent.Position.Base    = ShapeNet.ShapeList[Example.ShapeId].Position.Base;
                PageComponent.Position.Descent = ShapeNet.ShapeList[Example.ShapeId].Position.Descent;

                //Fill the
                oLearningData = new NeuralNetwork.LearningData();

                oLearningData.oInput.fInputs.Clear();
                oLearningData.oOutput.fOutputs.Clear();

                newInput             = RecogniseComponent.CalculateNetworkInput(PageComponent);
                oLearningData.oInput = newInput;

                for (long lIndex2 = 0; lIndex2 < ShapeNet.ShapeList.Count; lIndex2++)
                {
                    if (Example.ShapeId == lIndex2)
                    {
                        oLearningData.oOutput.fOutputs.Add(1);
                    }
                    else
                    {
                        oLearningData.oOutput.fOutputs.Add(0);
                    }
                }

                ShapeNet.NeuralNetwork.AddSituation(oLearningData);
            }

            ShapeNet.NeuralNetwork.ComputeInputRatios();
        }
Пример #11
0
        /// <summary>
        /// This function merges this Component with another component.
        /// </summary>
        /// <param name="MergeWith"></param>
        public PageComponent PartialCopy(Rectangle newArea)
        {
            //Create the new component
            PageComponent newComponent;

            newComponent             = new PageComponent();
            newComponent.Area        = newArea;
            newComponent.Bytes       = new Byte[newComponent.Width, newComponent.Height];
            newComponent.BinaryBytes = new Byte[newComponent.Width, newComponent.Height];
            newComponent.Type        = ePageComponentType.eSplitCharacter;

            //Clear the memory block
            for (int x = 0; x < newComponent.Width; x++)
            {
                for (int y = 0; y < newComponent.Height; y++)
                {
                    newComponent.Bytes[x, y]       = 0xFF;
                    newComponent.BinaryBytes[x, y] = 0xFF;
                }
            }

            //Copy the memory block of this component in the new one
            for (int y = newArea.Top; y < newArea.Bottom; y++)
            {
                for (int x = 0; x < newArea.Width; x++)
                {
                    newComponent.Bytes[x, y - newArea.Top]       = Bytes[newArea.X + x, y];
                    newComponent.BinaryBytes[x, y - newArea.Top] = BinaryBytes[newArea.X + x, y];
                    if (BinaryBytes[newArea.X + x, y] != 0xFF)
                    {
                        newComponent.PixelCount++;
                    }
                }
            }

            return(newComponent);
        }
Пример #12
0
        /// <summary>
        ///This function searches the distance matrix for the closest component
        ///to the given rectangle. The closest component must comply to
        ///the following rules:
        /// * Different from the given component
        /// * Component must not be a part of another sentence
        /// * Must be on the left side of given rectangle (if bLeft is true)
        /// * Must be on the right side of given rectangle (if bLeft is false)
        /// * Angle between rectangle and given rectangle must be less than 5 degrees
        /// </summary>
        /// <param name="Sentence"></param>
        /// <param name="CurrentComponent"></param>
        /// <param name="m_Areas"></param>
        /// <param name="Angle"></param>
        /// <param name="Left"></param>
        /// <returns></returns>

        public static PageComponent FindNearestComponent(Sentence Sentence, PageComponent CurrentComponent, List <DetectionArea> m_Areas, float Angle, bool Left)
        {
            int MinDistance;
            int Distance;

            MinDistance = 2000;

            PageComponent BestCandidate = null;

            int           CurrentAreaIndex;
            DetectionArea Area;


            double AverageAngle       = Sentence.AverageAngle();
            int    MaxAllowedDistance = (int)(Sentence.AverageHeight() * 1.5);
            int    AreaIndex          = CurrentComponent.DetectionAreaIndex;

            for (int Index = 0; Index < 6; Index++)
            {
                //the Index is converted to an area number according to the
                //matrix below. The start point is the center area (lIndex = 2).
                //lIndex 3 is on the left when bleft = true or on the right when bleft = false

                //  *************
                //  * 1 * 0 * 1 *
                //  *************
                //  * 3 * 2 * 3 *
                //  *************
                //  * 5 * 4 * 5 *
                //  *************

                CurrentAreaIndex = AreaIndex;

                //translate the lIndex to the x axis of the areas
                if ((Index & 1) != 0)
                {
                    if (Left)
                    {
                        CurrentAreaIndex--;
                    }
                    else
                    {
                        CurrentAreaIndex++;
                    }
                }

                //translate the Index to the y axis of the areas
                CurrentAreaIndex += ((Index / 2) - 1) * NumberAreasX;

                //the current area number must ly within boundaries (0, number areas)
                //no throw here if it is outside the boundaries because when the area
                //lies on the edge of the image this algorithm will try to go further
                if (CurrentAreaIndex >= 0 && CurrentAreaIndex < m_Areas.Count)
                {
                    Area = m_Areas[CurrentAreaIndex];

                    //loop through all the rectangles in the area
                    foreach (PageComponent Candidate in Area.Components)
                    {
                        if (Candidate.Type == ePageComponentType.eCharacter)
                        {
                            //Candidate neighbour must be on left/right side
                            if ((Left && Candidate.Area.X < CurrentComponent.Area.X) ||
                                (!Left && Candidate.Area.X > CurrentComponent.Area.X))
                            {
                                Distance = PageComponent.DistanceBetweenComponents(CurrentComponent, Candidate);

                                //Distance must be between current minimum and Maximum allowed
                                if (MinDistance > Distance && MaxAllowedDistance > Distance)
                                {
                                    //Angle between rectangle and sentence must be less than 5 degrees
                                    if (PageComponent.AngleBetweenComponents(CurrentComponent, Candidate) < 5 ||
                                        (Sentence.Area.Bottom > Candidate.Area.Top && Sentence.Area.Top < Candidate.Area.Top) ||
                                        (Sentence.Area.Bottom > Candidate.Area.Bottom && Sentence.Area.Top > Candidate.Area.Bottom))
                                    {
                                        BestCandidate = Candidate;
                                        MinDistance   = Distance;
                                    }
                                }
                            }
                        }
                    }
                }
            }

            if (BestCandidate != null)
            {
                m_Areas[BestCandidate.DetectionAreaIndex].Components.Remove(BestCandidate);
            }


            return(BestCandidate);
        }
Пример #13
0
        private void RunThinning_Click(object sender, RoutedEventArgs e)
        {
            OCRStubControls.CharacterGrid[] CharacterGrids = new OCRStubControls.CharacterGrid[7];

            OCR.PageImage     PageImage;
            OCR.PageComponent PageComponent;

            //Initialize charactergrids
            CharacterGrids[0] = ThinningStep1;
            CharacterGrids[1] = ThinningStep2;
            CharacterGrids[2] = ThinningStep3;
            CharacterGrids[3] = ThinningStep4;
            CharacterGrids[4] = ThinningStep5;
            CharacterGrids[5] = ThinningStep6;
            CharacterGrids[6] = ThinningStep7;

            PageImage = new OCR.PageImage();

            PageComponent = new OCR.PageComponent();
            PageComponent.LoadBitmap(txtThinningSample.Text);

            for (int x = 0; x < PageComponent.Width; x++)
            {
                for (int y = 0; y < PageComponent.Height; y++)
                {
                    PageComponent.BinaryBytes[x, y] = PageComponent.Bytes[x, y];
                }
            }

            ExtractFeatures.CreateCompareMatrixWithoutPruning(PageComponent);

            for (int x = 0; x < PageComponent.Width; x++)
            {
                for (int y = 0; y < PageComponent.Height; y++)
                {
                    PageComponent.BinaryBytes[x, y] = (PageComponent.Bytes[x, y] == 0xFF ? (Byte)0xFF : (Byte)0x00);
                }
            }

            CharacterGrids[0].Bytes = new byte[32, 32];
            for (int x = 0; x < 32; x++)
            {
                for (int y = 0; y < 32; y++)
                {
                    CharacterGrids[0].Bytes[x, y] = PageComponent.CompareMatrix[x, y];
                }
            }

            CharacterGrids[0].InvalidateVisual();

            for (int i = 0; i < 6; i++)
            {
                CharacterGrids[i + 1].Bytes = new byte[32, 32];

                for (int x = 0; x < 32; x++)
                {
                    for (int y = 0; y < 32; y++)
                    {
                        CharacterGrids[i + 1].Bytes[x, y] = PageComponent.CompareMatrix[x, y];
                    }
                }

                switch (ThinningAlgorithm.SelectedIndex)
                {
                case 0:     //Standard

                    ExtractFeatures.Thinning(CharacterGrids[i + 1].Bytes, 0, 0xFF, i + 1);
                    break;

                case 1:     //Erode

                    ExtractFeatures.ErodeThinning(CharacterGrids[i + 1].Bytes, 0, 0xFF, i + 1);
                    break;

                case 2:     //Middle

                    ExtractFeatures.MiddleThinning(CharacterGrids[i + 1].Bytes, 0, 0xFF);
                    break;

                case 3:     //Condensed

                    PageComponent = new OCR.PageComponent();
                    PageComponent.LoadBitmap(txtThinningSample.Text);
                    ExtractFeatures.CondensedThinning(PageImage, PageComponent, 0, 0xFF, i + 1);
                    for (int x = 0; x < 32; x++)
                    {
                        for (int y = 0; y < 32; y++)
                        {
                            CharacterGrids[i + 1].Bytes[x, y] = PageComponent.CompareMatrix[x, y];
                        }
                    }
                    break;

                case 4:     //Pruning

                    PageComponent = new OCR.PageComponent();
                    PageComponent.LoadBitmap(txtThinningSample.Text);

                    for (int x = 0; x < PageComponent.Width; x++)
                    {
                        for (int y = 0; y < PageComponent.Height; y++)
                        {
                            PageComponent.BinaryBytes[x, y] = PageComponent.Bytes[x, y];
                        }
                    }

                    ExtractFeatures.ThinningPruningOnOriginalImage(PageComponent, PageComponent, 0, i + 1);

                    ExtractFeatures.CreateCompareMatrixWithoutPruning(PageComponent);

                    for (int x = 0; x < 32; x++)
                    {
                        for (int y = 0; y < 32; y++)
                        {
                            CharacterGrids[i + 1].Bytes[x, y] = PageComponent.CompareMatrix[x, y];
                        }
                    }

                    break;

                case 5:     //Pruning  original

                    PageComponent = new OCR.PageComponent();
                    PageComponent.LoadBitmap(txtThinningSample.Text);
                    ExtractFeatures.ThinningPruningOnOriginalImage(PageImage, PageComponent, 2, i + 1);
                    ExtractFeatures.CreateCompareMatrixWithoutPruning(PageComponent);
                    for (int x = 0; x < 32; x++)
                    {
                        for (int y = 0; y < 32; y++)
                        {
                            CharacterGrids[i + 1].Bytes[x, y] = PageComponent.CompareMatrix[x, y];
                        }
                    }
                    break;
                }

                CharacterGrids[i + 1].InvalidateVisual();
            }
        }
Пример #14
0
        private void btnTest_Click(object sender, RoutedEventArgs e)
        {
            OCR.ShapeNet      SelectedShapeNet;
            OCR.PageComponent PageComponent;

            SelectedShapeNet = (OCR.ShapeNet)lstNeuralNetworks.SelectedItem;

            PageComponent.newID = 0;
            PageComponent       = new OCR.PageComponent();
            PageComponent.LoadBitmap(txtSample.Text);

            ExtractFeatures.ExecuteExtractFeatures(PageComponent, PageComponent, true);
            RecogniseComponent.Recognise(SelectedShapeNet, PageComponent);

            //Recognise the component
            lstResults.Items.Clear();
            String ResultText = "";

            foreach (RecognitionResult Result in PageComponent.RecognitionResults)
            {
                ResultText = Result.Content + " (" + Result.Probability + ")";
                lstResults.Items.Add(ResultText);
            }

            //Build the original image
            PageComponent Original = new PageComponent();

            Original.LoadBitmap(txtSample.Text);

            ExtractFeatures.CreateCompareMatrixWithoutPruning(Original, Original.Bytes);

            imgSample.Bytes = Original.CompareMatrix;
            for (int index = 0; index < 256; index++)
            {
                imgSample.GridBrushes[index] = new SolidColorBrush(System.Windows.Media.Color.FromRgb((byte)index, (byte)index, (byte)index));
            }
            imgSample.InvalidateVisual();

            ExtractFeatures.CreateCompareMatrixWithoutPruning(PageComponent);

            //Build the thinned and stroked image
            for (int x = 0; x < 32; x++)
            {
                for (int y = 0; y < 32; y++)
                {
                    if (PageComponent.StrokeMatrix[x, y] == 0xFF && PageComponent.CompareMatrix[x, y] != 0xFF)
                    {
                        PageComponent.StrokeMatrix[x, y] = 0x04;
                    }
                    if (PageComponent.PixelTypeMatrix[x, y] == ePixelType.End)
                    {
                        PageComponent.StrokeMatrix[x, y] = 0xFE;
                    }
                    if (PageComponent.PixelTypeMatrix[x, y] == ePixelType.Junction)
                    {
                        PageComponent.StrokeMatrix[x, y] = 0xFD;
                    }
                }
            }

            imgProjection.Bytes            = PageComponent.StrokeMatrix;
            imgProjection.GridBrushes[0]   = new SolidColorBrush(Colors.Black);
            imgProjection.GridBrushes[4]   = new SolidColorBrush(Colors.LightGray);
            imgProjection.GridBrushes[11]  = new SolidColorBrush(Colors.Brown);
            imgProjection.GridBrushes[12]  = new SolidColorBrush(Colors.Maroon);
            imgProjection.GridBrushes[13]  = new SolidColorBrush(Colors.Magenta);
            imgProjection.GridBrushes[14]  = new SolidColorBrush(Colors.Lime);
            imgProjection.GridBrushes[15]  = new SolidColorBrush(Colors.LightCyan);
            imgProjection.GridBrushes[16]  = new SolidColorBrush(Colors.Purple);
            imgProjection.GridBrushes[32]  = new SolidColorBrush(Colors.Blue);
            imgProjection.GridBrushes[48]  = new SolidColorBrush(Colors.Green);
            imgProjection.GridBrushes[64]  = new SolidColorBrush(Colors.Yellow);
            imgProjection.GridBrushes[253] = new SolidColorBrush(Colors.Red);
            imgProjection.GridBrushes[254] = new SolidColorBrush(Colors.Red);
            imgProjection.InvalidateVisual();

            lblStrokes.Content = "#Strokes: " + Convert.ToString(PageComponent.Strokes);

            //Bitmap StrokeMatrixBitmap = OCR.DebugTrace.DebugTrace.CreateBitmapFromByteArray(PageComponent.StrokeMatrix, new System.Drawing.Size(32, 32));
            //StrokeMatrixBitmap.Save("d:\\ocr\\temp.bmp");
            //imgProjection.Source = new BitmapImage(new Uri("d:\\ocr\\temp.bmp"));

            pbHorizontal.Clear();

            int ProjectionValue;

            for (int x = 0; x < 3; x++)
            {
                ProjectionValue = 0;
                for (int y = 0; y < 3; y++)
                {
                    ProjectionValue += PageComponent.PixelTypeProjectionJunction[x, y];
                    ProjectionValue += PageComponent.PixelTypeProjectionEndpoint[x, y];
                }
                pbHorizontal.AddValue(ProjectionValue);
            }

            pbVertical.Clear();
            for (int y = 0; y < 3; y++)
            {
                ProjectionValue = 0;
                for (int x = 0; x < 3; x++)
                {
                    ProjectionValue += PageComponent.PixelTypeProjectionJunction[x, y];
                    ProjectionValue += PageComponent.PixelTypeProjectionEndpoint[x, y];
                }
                pbVertical.AddValue(ProjectionValue);
            }

            pbStrokeHorizontal.Clear();
            foreach (int Value in PageComponent.lStrokeDirectionX)
            {
                pbStrokeHorizontal.AddValue(Value);
            }

            pbStrokeVertical.Clear();
            foreach (int Value in PageComponent.lStrokeDirectionY)
            {
                pbStrokeVertical.AddValue(Value);
            }
        }
Пример #15
0
 public Boolean Add(PageComponent Child)
 {
     Components.Add(Child);
     return(true);
 }
Пример #16
0
        /// <summary>
        /// Adds a component to the sentence
        /// </summary>
        /// <param name="Component"></param>
        public void Add(PageComponent Component)
        {
            ClearCache();

            Components.Add(Component);
        }
Пример #17
0
        /// <summary>
        /// Updates/replaces the given position in the sentence with a new component
        /// </summary>
        /// <param name="Position"></param>
        /// <param name="Component"></param>
        public void Update(int Position, PageComponent Component)
        {
            ClearCache();

            Components[Position] = Component;
        }
        /// <summary>
        /// This functions 'recognises' the given compontent by running its features through
        /// a neural network.
        /// </summary>
        /// <param name="Component"></param>
        public static void Recognise(ShapeNet ShapeNet, PageComponent Component)
        {
            RecogniseWithoutConnectedRepair(ShapeNet, Component);

            Component.CheckAndRepairConnected(ShapeNet);
        }
Пример #19
0
        public static void ExecuteActivity(object Parameter)
        {
            WorkPackage   WorkPackage;
            Rectangle     Assignment;
            PageComponent newComponent;

            WorkPackage = (WorkPackage)Parameter;
            Assignment  = (Rectangle)WorkPackage.Assignment;

            int          y = Assignment.Top;
            int          x = Assignment.Left;
            int          pointer;
            List <Point> Pixels = new List <Point>(0);

            while (y < Assignment.Bottom)
            {
                x = Assignment.Left + ((y & 2) / 2);

                // we are using a mesh, therefor
                // we use y&1 to differentiate the starting point of each row.
                // the mesh looks like:
                // +-+-+-+-+
                // ---------
                // -+-+-+-+-
                // ---------
                // +-+-+-+-+
                // ---------
                // -+-+-+-+-
                // we check every other pixel, that way we can check half of the image
                // and still find all the component we want to find, except for lines
                // at exactly 45 degrees and 1 pixel wide. But at this point we find
                // those irrelevant;

                pointer = x + y * WorkPackage.Image.Stride;

                while (x < Assignment.Right)
                {
                    if (WorkPackage.Image.BinaryBytes[x, y] == 0)
                    {
                        //We found a new pixel with the
                        lock (WorkPackage.Image)
                        {
                            newComponent = new PageComponent();
                        }
                        newComponent.Area = new Rectangle(x, y, 1, 1);

                        Pixels.Clear();

                        if (GenerateConnectedComponent(WorkPackage, newComponent, Pixels))
                        {
                            if (newComponent.Area.Height < WorkPackage.Image.Height * 0.9 &&
                                newComponent.Area.Width < WorkPackage.Image.Width * 0.9)
                            {
                                newComponent.PixelCount = Pixels.Count;

                                GenerateBitmap(WorkPackage.Image, newComponent, Pixels);

                                lock (WorkPackage.Image)
                                {
                                    WorkPackage.Image.Components.Add(newComponent);
                                }
                            }
                        }
                    }

                    x       += 2;
                    pointer += 2;
                }

                y += 2;
            }
            SignalWorkDone();
        }
Пример #20
0
        public static void AnalyseComponentType(PageComponent Component)
        {
            //see 'A word extraction algorithm for machine-printed documents using
            //     a 3D neighborhood graph model' by H.Park, S.Ok, Y. Yu and H.CHo, 2001
            //     International Journal on Document Analysis and Recognition

            Component.Type = ePageComponentType.eCharacter;

            if ((Component.AreaSize) > (ComponentAverageArea * 25))
            {
                Component.Type = ePageComponentType.eImageRect;
            }

            return;

            //const double cL0 = 0.8;
            //const double cD0 = 0.7;
            //const double cC1 = -1.09;
            //const double cC2 = 2.8;

            ////step 1, compare the area of the rectangle
            // //with the average rectangle size
            // if ((Component.AreaSize()) <= ComponentAverageArea)
            // {
            //    Component.Type = eRectangleType.eCharacter;
            // }
            // else
            // {
            //    //we have a rather large rectangle, proceed to step 2
            //    //checking of elongation.
            //     double Elong = (double)System.Math.Min(Component.Width, Component.Height) / (double)System.Math.Max(Component.Width, Component.Height);

            //    if (Elong <= cL0) {
            //        //Step 3, compare density. Pictures normally have larger
            //        //density than characters.
            //        if (Component.Density >= cD0)
            //        {
            //            Component.Type = eRectangleType.eImageRect;
            //        }
            //        else
            //        {
            //            if (cC1 * CalculateRowVariance(Component) + cC2 <= CalculateColumnVariance(Component))
            //            {
            //                Component.Type = eRectangleType.eInvertedCharacter;
            //            }
            //            else
            //            {
            //                Component.Type = eRectangleType.eImageRect;
            //            }
            //        }
            //    }
            //    else
            //    {
            //        if (cC1 * CalculateRowVariance(Component) + cC2 <= CalculateColumnVariance(Component))
            //        {
            //            Component.Type = eRectangleType.eCharacter;
            //        }
            //        else
            //        {
            //            Component.Type = eRectangleType.eImageRect;
            //        }
            //    }
            //}
        }
Пример #21
0
        private static bool GenerateConnectedComponent(WorkPackage WorkPackage, PageComponent newComponent, List <Point> Pixels)
        {
            //this functies growes the newComponent in such manner that it
            //surrounds connected pixels.

            //the function returns true if there are more than 8 connected pixels present.
            //The number of 8 comes from the article bu L.A.Fletcher and R.Kasturi,
            // 'A Robust Algorithm for Text String Separation from Mixed Text/Graphics Images'

            //in 'A word extraction algorithm for machine-printed documents using a
            //    3D neighborhood graph algorithm' a number of 6 pixels was mentioned
            //but for now the number of 8 seems to work allright.

            int       pointer = 0;
            int       Index   = 0;
            Rectangle newArea;
            Point     Pixel       = newComponent.Area.Location;
            Point     TopLeft     = new Point(Pixel.X, Pixel.Y);
            Point     BottomRight = new Point(Pixel.X, Pixel.Y);

            try
            {
                Pixels.Add(TopLeft);

                do
                {
                    //get pixel from the queue
                    Pixel = Pixels[Index];

                    //determine if we need to increase the area of the component.
                    if (Pixel.X < TopLeft.X)
                    {
                        TopLeft.X = Pixel.X;
                    }
                    if (Pixel.Y < TopLeft.Y)
                    {
                        TopLeft.Y = Pixel.Y;
                    }
                    if (Pixel.X >= BottomRight.X)
                    {
                        BottomRight.X = Pixel.X + 1;
                    }
                    if (Pixel.Y >= BottomRight.Y)
                    {
                        BottomRight.Y = Pixel.Y + 1;
                    }

                    //calculate pointer and change color of pixel to make sure
                    //it will not be detected for other connected components
                    pointer = Pixel.X + WorkPackage.Image.Stride * Pixel.Y;

                    lock (ImageWriteLocker)
                    {
                        if (WorkPackage.Image.BinaryBytes[Pixel.X, Pixel.Y] == (Byte)WorkPackage.Parameter ||
                            WorkPackage.Image.BinaryBytes[Pixel.X, Pixel.Y] == 0)
                        {
                            WorkPackage.Image.BinaryBytes[Pixel.X, Pixel.Y] = 64; //pixel is set
                        }
                        else
                        {
                            //detected a conflict with another thread, roll back!
                            while (Index > 0)
                            {
                                Index--;
                                Pixel   = Pixels[Index];
                                pointer = Pixel.X + WorkPackage.Image.Stride * Pixel.Y;
                                WorkPackage.Image.BinaryBytes[Pixel.X, Pixel.Y] = 0x00;
                            }

                            //throw an exception, leave this as quick as possible
                            throw new ApplicationException("Conflict with another thread");
                        }
                    }

                    //look around and add interesting pixels to queue
                    GCC_CheckNeighbour(WorkPackage, Pixel, -1, 0, Pixels);
                    GCC_CheckNeighbour(WorkPackage, Pixel, 0, -1, Pixels);
                    GCC_CheckNeighbour(WorkPackage, Pixel, 1, 0, Pixels);
                    GCC_CheckNeighbour(WorkPackage, Pixel, 0, 1, Pixels);
                    GCC_CheckNeighbour(WorkPackage, Pixel, -1, 1, Pixels);
                    GCC_CheckNeighbour(WorkPackage, Pixel, 1, -1, Pixels);
                    GCC_CheckNeighbour(WorkPackage, Pixel, -1, -1, Pixels);
                    GCC_CheckNeighbour(WorkPackage, Pixel, 1, 1, Pixels);

                    Index++;
                } while (Index < Pixels.Count);

                //Set the area of the component
                newArea           = new Rectangle(TopLeft.X, TopLeft.Y, BottomRight.X - TopLeft.X, BottomRight.Y - TopLeft.Y);
                newComponent.Area = newArea;
            }
            catch (ApplicationException exp)
            {
                Console.WriteLine("Exception caught: " + exp.Message);
                Console.WriteLine("   in: " + exp.StackTrace);
                return(false);
            }

            //return true if there are more than 8 connected pixels
            return(Pixels.Count >= 2);  // was 8
        }
Пример #22
0
        /// <summary>
        /// This function merges this Component with another component.
        /// </summary>
        /// <param name="MergeWith"></param>
        public void Merge(PageComponent MergeWith)
        {
            Rectangle newArea;

            Byte[,] newComponentBytes;
            Byte[,] newComponentBinaryBytes;
            int newStride;

            try
            {
                //Calculate the new area of the merged component
                newArea = new Rectangle();

                newArea.X      = Math.Min(Area.X, MergeWith.Area.X);
                newArea.Y      = Math.Min(Area.Y, MergeWith.Area.Y);
                newArea.Width  = Math.Max(Area.Right, MergeWith.Area.Right) - newArea.X;
                newArea.Height = Math.Max(Area.Bottom, MergeWith.Area.Bottom) - newArea.Y;

                //Calculate the size of the memory block which contains the pixels
                newStride = CalculateStride(newArea.Width);

                //Allocate the memory block
                newComponentBytes       = new Byte[newArea.Width, newArea.Height];
                newComponentBinaryBytes = new Byte[newArea.Width, newArea.Height];

                //Clear the memory block
                int index = newComponentBytes.Length;

                for (int x = 0; x < newArea.Width; x++)
                {
                    for (int y = 0; y < newArea.Height; y++)
                    {
                        newComponentBytes[x, y]       = 0xFF;
                        newComponentBinaryBytes[x, y] = 0xFF;
                    }
                }

                //Copy the memory block of this component in the new one
                int PointerFrom;
                int PointerTo;

                for (int y = 0; y < Area.Height; y++)
                {
                    PointerFrom = y * m_Stride;
                    PointerTo   = (Area.X - newArea.X) + (y + Area.Y - newArea.Y) * newStride;

                    for (int x = 0; x < Area.Width; x++)
                    {
                        newComponentBytes[(x + Area.X - newArea.X), (y + Area.Y - newArea.Y)]       = Bytes[x, y];
                        newComponentBinaryBytes[(x + Area.X - newArea.X), (y + Area.Y - newArea.Y)] = BinaryBytes[x, y];
                    }
                }

                //Copy the memory block of the merge component in the new one
                for (int y = 0; y < MergeWith.Area.Height; y++)
                {
                    for (int x = 0; x < MergeWith.Area.Width; x++)
                    {
                        newComponentBytes[x + MergeWith.Area.X - newArea.X, y + MergeWith.Area.Y - newArea.Y]       = MergeWith.Bytes[x, y];
                        newComponentBinaryBytes[x + MergeWith.Area.X - newArea.X, y + MergeWith.Area.Y - newArea.Y] = MergeWith.BinaryBytes[x, y];
                    }
                }

                //Update the properties of this component;
                Area        = newArea;
                BinaryBytes = newComponentBinaryBytes;
                Bytes       = newComponentBytes;

                PixelCount += MergeWith.PixelCount;
            }
            catch (Exception e)
            {
                Console.WriteLine("Exception caught: " + e.Message);
                Console.WriteLine("  In: " + e.StackTrace);
            }
        }
Пример #23
0
        /// <summary>
        /// This function calculates the distance between the bounding boxes of two components
        /// </summary>
        /// <param name="ChildFrom"></param>
        /// <param name="ChildTo"></param>
        /// <returns></returns>
        public static int DistanceBetweenComponents(PageComponent From, PageComponent To)
        {
            int lRetValue;

            int    xDelta, yDelta;
            int    xMoved, yMoved;
            double Direction;
            Point  PointFrom, PointTo, Position, Origin;

            lRetValue = 0;
            Direction = 0;

            PointFrom = From.CenterPoint;
            PointTo   = To.CenterPoint;
            Origin    = PointFrom;

            lRetValue = (int)Distance(From, To) + 1;

            if (System.Math.Abs(PointTo.X - PointFrom.X) > System.Math.Abs(PointTo.Y - PointFrom.Y))
            {
                if (PointTo.X != PointFrom.X)
                { //just to be sure we don't get a division by zero
                    Direction = (double)(PointTo.Y - PointFrom.Y) / (double)(PointTo.X - PointFrom.X);
                }

                Position = PointFrom;

                if (PointFrom.X > PointTo.X)
                {
                    xDelta = -1;
                }
                else
                {
                    xDelta = 1;
                }
                xMoved = 0;

                while (From.CoordinateInMe(Position))
                {
                    lRetValue--;

                    xMoved     += xDelta;
                    Position.X += xDelta;
                    Position.Y  = (Origin.Y + (int)(xMoved * Direction));
                }

                Position = PointTo;
                xMoved   = 0;
                xDelta   = xDelta * -1; //we walk to the different side

                while (To.CoordinateInMe(Position))
                {
                    lRetValue--;

                    xMoved     += xDelta;
                    Position.X += xDelta;
                    Position.Y  = (Origin.Y + (int)(xMoved * Direction));
                }
            }
            else
            {
                if (PointTo.Y != PointFrom.Y)   //just to be sure we don't get a division by zero
                {
                    Direction = (double)(PointTo.X - PointFrom.X) / (double)(PointTo.Y - PointFrom.Y);
                }

                Position = PointFrom;
                yDelta   = (PointFrom.Y > PointTo.Y) ? -1 : 1;
                yMoved   = 0;

                while (From.CoordinateInMe(Position))
                {
                    lRetValue--;

                    yMoved     += yDelta;
                    Position.Y += yDelta;
                    Position.X  = Origin.X + (int)(yMoved * Direction);
                }

                Position = PointTo;
                yMoved   = 0;
                yDelta   = yDelta * -1; //we walk to the different side

                while (To.CoordinateInMe(Position))
                {
                    lRetValue--;

                    yMoved     += yDelta;
                    Position.Y += yDelta;
                    Position.X  = Origin.X + (int)(yMoved * Direction);
                }
            }

            return(lRetValue);
        }
Пример #24
0
        private static double CalculateColumnVariance(PageComponent Component)
        {
            List <int> RunsPerRow = new List <int>();
            int        Runs;
            int        Pointer;
            Byte       CurrentRun;
            double     Average;
            double     Variance;

            //Count number of pixels per column
            int y = 0;
            int x = Component.Width;

            while (x > 0)
            {
                x--;

                Runs       = 1;
                y          = Component.Height;
                Pointer    = x + y * Component.Stride;
                CurrentRun = Component.BinaryBytes[x, y - 1];

                while (y > 0)
                {
                    y--;
                    Pointer -= Component.Stride;

                    if (CurrentRun != Component.BinaryBytes[x, y])
                    {
                        Runs++;
                        CurrentRun = Component.BinaryBytes[x, y];
                    }
                }

                RunsPerRow.Add(Runs);
            }

            //calculate average runs
            Average = 0;
            int i;

            i = RunsPerRow.Count - 1;
            while (i > 0)
            {
                i--;

                Average += System.Math.Abs(RunsPerRow[i + 1] - RunsPerRow[i]);
            }
            Average = Average / (RunsPerRow.Count - 1);

            //calculate variance;
            Variance = 0;
            i        = RunsPerRow.Count - 1;
            while (i > 0)
            {
                i--;

                Variance += System.Math.Pow((System.Math.Abs(RunsPerRow[i + 1] - RunsPerRow[i]) - Average), 2);
            }
            Variance = Variance / (RunsPerRow.Count - 1);

            return(Variance);
        }
Пример #25
0
        /// <summary>
        /// Inserts a component at the given position
        /// </summary>
        /// <param name="Position"></param>
        /// <param name="Component"></param>
        public void Insert(int Position, PageComponent Component)
        {
            ClearCache();

            Components.Insert(Position, Component);
        }