private HashSet <LineShape> FilterHorizontalLines(Image hlines, BoundedObjectGrid <CheckboxShape> checkboxGrid) { HashSet <LineShape> lines = new HashSet <LineShape>(); int minThickLineWidth = LineDetector.MinThickLineWidth.MulDiv(hlines.VerticalResolution, 200); int minThickLineLength = LineDetector.MinThickLineLength.MulDiv(hlines.HorizontalResolution, 200); int maxBoxSize = this.MaxBoxSize.MulDiv(hlines.HorizontalResolution, 200); // find connected components and do preliminary filtering foreach (ConnectedComponent component in hlines.FindConnectedComponents(8)) { Rectangle bounds = component.Bounds; int maxWidth = component.MaxHeight(); bool isBad = false; if (bounds.Width.Between(minThickLineWidth, minThickLineLength - 1) && bounds.Height.Between(minThickLineWidth, minThickLineLength - 1) && maxWidth > minThickLineLength) { // too thick for the length isBad = true; } if (!isBad && bounds.Width <= maxBoxSize && checkboxGrid != null && checkboxGrid.EnumObjects(bounds).Any()) { // is part of the check box isBad = true; } if (isBad) { hlines.SetWhite(bounds); } else { LineShape newline = new LineShape(bounds, maxWidth, LineTypes.Horizontal); lines.Add(newline); } } // find line vectors AlignedObjectGrid <LineShape> grid = new AlignedObjectGrid <LineShape>(hlines.Bounds, 10, 20, RectangleLTRBComparer.Default); grid.AddRange(lines, true, true); int minLineLength = (this.MinHorizontalLineLength * hlines.HorizontalResolution).Round(); int maxGap = LineDetector.MaxLineGap.MulDiv(hlines.HorizontalResolution, 200); int tolerance = 3.MulDiv(hlines.VerticalResolution, 200); HashSet <LineShape> newlines = new HashSet <LineShape>(); foreach (LineShape line in lines) { if (line.VerticalAlignment == VerticalAlignment.None) { IList <LineShape> alignedLines = grid.FindVerticalAlignment( line, VerticalAlignment.Center, maxGap, tolerance, (result, bounds) => bounds.Width >= minLineLength && (result.Count >= 2 || result.Any(o => o.Bounds.Width >= minLineLength))); if (alignedLines.Count > 0) { LineShape newline = new LineShape( Rectangle.Union(alignedLines.Select(x => x.Bounds)), alignedLines[0].Begin, alignedLines[alignedLines.Count - 1].End, alignedLines.Max(x => x.Width), LineTypes.Horizontal); newlines.Add(newline); } } } // remove merged and short lines lines.RemoveWhere(x => { // remove merged lines bool remove = x.VerticalAlignment != VerticalAlignment.None; // remove small not merged lines // also delete them from the image if (x.VerticalAlignment == VerticalAlignment.None && x.Bounds.Width < minLineLength) { hlines.SetWhite(x.Bounds); remove = true; } return(remove); }); lines.UnionWith(newlines); return(lines); }
private HashSet <LineShape> FilterVerticalLines(Image vlines, Image hlines, BoundedObjectGrid <CheckboxShape> checkboxGrid) { HashSet <LineShape> lines = new HashSet <LineShape>(); int minThickLineWidth = LineDetector.MinThickLineWidth.MulDiv(vlines.HorizontalResolution, 200); int minThickLineLength = LineDetector.MinThickLineLength.MulDiv(vlines.VerticalResolution, 200); int maxBoxSize = this.MaxBoxSize.MulDiv(vlines.VerticalResolution, 200); // find connected components and do preliminary filtering foreach (ConnectedComponent component in vlines.FindConnectedComponents(8)) { Rectangle bounds = component.Bounds; int maxWidth = component.MaxWidth(); bool isBad = false; if (bounds.Width.Between(minThickLineWidth, minThickLineLength - 1) && bounds.Height.Between(minThickLineWidth, minThickLineLength - 1) && maxWidth > minThickLineLength) { // too thick for the length isBad = true; } if (!isBad && bounds.Height <= maxBoxSize && checkboxGrid != null && checkboxGrid.EnumObjects(bounds).Any()) { // is part of the check box isBad = true; } if (isBad) { vlines.SetWhite(bounds); } else { Point begin = new Point(component.GetLine(bounds.Y).Center, bounds.Y); Point end = new Point(component.GetLine(bounds.Bottom - 1).Center, bounds.Bottom - 1); LineShape line = new LineShape(bounds, begin, end, maxWidth, LineTypes.Vertical); lines.Add(line); } } // find line vectors AlignedObjectGrid <LineShape> grid = new AlignedObjectGrid <LineShape>(vlines.Bounds, 10, 20, RectangleTBLRComparer.Default); grid.AddRange(lines, true, true); int minLineLength = (this.MinVerticalLineLength * vlines.VerticalResolution).Round(); int maxGap = LineDetector.MaxLineGap.MulDiv(vlines.VerticalResolution, 200); int tolerance = 6.MulDiv(vlines.HorizontalResolution, 200); HashSet <LineShape> newlines = new HashSet <LineShape>(); foreach (LineShape line in lines) { if (line.HorizontalAlignment == HorizontalAlignment.None) { IList <LineShape> alignedLines = grid.FindHorizontalAlignment( line, HorizontalAlignment.Center, Math.Min(maxGap, line.Bounds.Height), tolerance, (result, bounds) => (bounds.Height >= minLineLength && (result.Count >= 3 || result.Any(o => o.Bounds.Height >= minLineLength))) || LineHasIntersectionsOnBothEnds(bounds)); if (alignedLines.Count > 0) { LineShape newline = new LineShape( Rectangle.Union(alignedLines.Select(x => x.Bounds)), alignedLines[0].Begin, alignedLines[alignedLines.Count - 1].End, alignedLines.Max(x => x.Width), LineTypes.Vertical); newlines.Add(newline); } } } // remove merged and short lines lines.RemoveWhere(x => { // remove merged lines bool remove = x.HorizontalAlignment != HorizontalAlignment.None; // remove small not merged lines // also delete them from the image if (x.HorizontalAlignment == HorizontalAlignment.None && x.Bounds.Height < minLineLength && !LineHasIntersectionsOnBothEnds(x.Bounds)) { vlines.SetWhite(x.Bounds); remove = true; } return(remove); }); lines.UnionWith(newlines); bool LineHasIntersectionsOnBothEnds(Rectangle bounds) { if (hlines != null) { int boxheight = Math.Min(bounds.Width, bounds.Height); Rectangle top = new Rectangle(bounds.X, bounds.Y, bounds.Width, boxheight); top.Inflate(0, 2 * boxheight); top.Intersect(hlines.Bounds); Rectangle bottom = new Rectangle(bounds.X, bounds.Bottom - boxheight, bounds.Width, boxheight); bottom.Inflate(0, 2 * boxheight); bottom.Intersect(hlines.Bounds); return(!hlines.IsAllWhite(top) && !hlines.IsAllWhite(bottom)); } else { return(false); } } return(lines); }