public Rectangle[] FindPunctuation(Rectangle[] boxes) { Rectangle[] points = boxes.Where(box => box.Diameter().InRange(minPunctuationSize, maxCharSize-1)).ToArray(); Rectangle[] chars = FindChars(boxes); var groupBy = chars.Group(); return points // .Where(p => !chars.IntersectsWith(p)) // .Where(p => chars.Any(ch => ch.MaxCoordDistanceTo(p) < ch.Diameter())) // significantly slow down. need optimization (for example with KD-Tree) .Where(p => groupBy.ContainsKey(p.Sector()) && !groupBy.IntersectsWith(p)) .ToArray(); }
// Assumes no rectangles are overlapping beyond their edges public static bool IsSurroundedBy(this Point point, Rectangle[] usedSpace) { // Cannot surround a point with only one edge if (usedSpace.Length < 2) return false; var rectsSharingCorner = usedSpace.Where(r => r.GetCorners().Contains(point)).ToArray(); var rectsSharingEdge = usedSpace.Where(r => r.SharesEdge(point)) .Where(r => !rectsSharingCorner.Contains(r)) .ToArray(); // Four rects sharing a corner = surrounded if (rectsSharingCorner.Length == 4) return true; // Two rects sharing a corner = one rect needs to share an edge to be surrounded if (rectsSharingCorner.Length == 2 && rectsSharingEdge.Length == 1) return true; // No rects sharing a corner = two rects needs to share an edge to be surrounded if (rectsSharingCorner.Length == 0 && rectsSharingEdge.Length == 2) return true; //// One or three rects sharing a corner = at least one diagonal exposed //if (rectsSharingCorner.Length == 3) return false; //if (rectsSharingCorner.Length == 1) return false; return false; }
/// <summary> /// This method tries to order the blobs in rows. /// </summary> private Dictionary<int, List<Rectangle>> ReorderBlobs(Rectangle[] blobs) { Dictionary<int, List<Rectangle>> result = new Dictionary<int, List<Rectangle>>(); if (blobs.Length < 1) return result; // Merge intersecting blobs (we filter some very small blobs first). List<Rectangle> mergedBlobs = MergeIntersectingBlobs(blobs.Where(r => r.Width * r.Height >= txtPreMergeFilter.Value).ToArray()); // Filter for blobs that are larger than 50 "sq pixels" and order by Y. mergedBlobs = new List<Rectangle>( mergedBlobs.Where(r => r.Height * r.Width >= txtPostMergeFilter.Value).OrderBy(r => r.Y)); // Add the first row and blob. int currRowInd = 0; result.Add(currRowInd, new List<Rectangle>()); result[currRowInd].Add(mergedBlobs[0]); // Now we loop thru all the blobs and try to guess where a new line begins. for (int i = 1; i < mergedBlobs.Count; i++) { // Since the blobs are ordered by Y, we consider a NEW line if the current blob's Y // is BELOW the previous blob lower quarter. // The assumption is that blobs on the same row will have more-or-less same Y, so if // the Y is below the previous blob lower quarter it's probably a new line. if (mergedBlobs[i].Y > mergedBlobs[i - 1].Y + 0.75 * mergedBlobs[i - 1].Height) { // Add a new row to the dictionary ++currRowInd; result.Add(currRowInd, new List<Rectangle>()); } // Add blob to the current row. result[currRowInd].Add(mergedBlobs[i]); } return result; }
public Rectangle[] FindChars(Rectangle[] boxes) { return boxes.Where(box => box.Diameter().InRange(minCharSize, maxCharSize)).ToArray(); }
/// <summary> /// This method looks for blobs that intersect and join them into one blob. /// </summary> private List<Rectangle> MergeIntersectingBlobs(Rectangle[] blobs) { // Loop thru all blobs. int i = 0; while (i < blobs.Length) { // Ignore empty blobs. if (blobs[i].IsEmpty) { ++i; continue; } // When we check for intersection we want to inflate the current blob, this is // for special cases where there are very close blobs that do not intersect and we DO want // them to intersect, for example the letters "i" or j" where the dot above the letter is a // different not intersecting blob, so by inflating the current blon we would hopefully // make them intersect. Rectangle tmp = blobs[i]; tmp.Inflate((int)txtWidthMergeSense.Value, (int)txtHeightMergeSense.Value); // Go check the following blobs (it is order by X) and see if they are intersecting with // the current i'th blob. bool merged = false; for (int j = i + 1; j < blobs.Length; ++j) { // Ignore empty blobs. if (blobs[j].IsEmpty) { continue; } // If the j'th blob X is beyond the i'th blob area it means there are no more // potential blobs that will intersect with the i'th blob, hence we can stop (because blobs are sorted on X). if (blobs[j].X > tmp.X + tmp.Width) break; // Check if there is intersection. if (tmp.IntersectsWith(blobs[j])) { // Replace the i'th blob with the union with j // (Note we are using the i'th blob and not the inflated blob (tmp)). blobs[i] = Rectangle.Union(blobs[i], blobs[j]); // Set j'th blob to be empty so we will ignore it from now on. blobs[j] = new Rectangle(); // Stop the current loop. merged = true; break; } } // If we had a merge we don't move to the next Blob as the newly created // joined blob has to be checked for another newly potential intersections. if (!merged) ++i; } // Create the result list with only non-empty rectangles. List<Rectangle> result = new List<Rectangle>(blobs.Where(r => !r.IsEmpty)); return result; }