/// <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 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--; } } } }
/// <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); }