public AForge.Point NormalEnd { get; set; } // (needed in drawing, avoid calculating twice) public Component(AForge.Point centr, double alignmnt, List<IntPoint> outln, LineSegment lngst, AForge.Point Nstart, AForge.Point Nend) { Center = centr; Alignment = alignmnt; Outline = outln; Longest = lngst; NormalStart = Nstart; NormalEnd = Nend; }
// ========================================================================================================== // Components: // ========================================================================================================== private List<Shapes.Component> FindComponentsFunct(Bitmap bitmap) { // Locating objects BlobCounter blobCounter = new BlobCounter(); blobCounter.FilterBlobs = true; blobCounter.MinHeight = 8; blobCounter.MinWidth = 8; blobCounter.ProcessImage(bitmap); Blob[] blobs = blobCounter.GetObjectsInformation(); // create convex hull searching algorithm GrahamConvexHull hullFinder = new GrahamConvexHull(); ClosePointsMergingOptimizer optimizer1 = new ClosePointsMergingOptimizer(); FlatAnglesOptimizer optimizer2 = new FlatAnglesOptimizer(); List<Shapes.Component> Components = new List<Shapes.Component>(); // process each blob foreach (Blob blob in blobs) { List<IntPoint> leftPoints, rightPoints, edgePoints = new List<IntPoint>(); if ((blob.Rectangle.Height > 400) && (blob.Rectangle.Width > 600)) { break; // The whole image could be a blob, discard that } // get blob's edge points blobCounter.GetBlobsLeftAndRightEdges(blob, out leftPoints, out rightPoints); edgePoints.AddRange(leftPoints); edgePoints.AddRange(rightPoints); // blob's convex hull List<IntPoint> Outline = hullFinder.FindHull(edgePoints); optimizer1.MaxDistanceToMerge = 4; optimizer2.MaxAngleToKeep = 170F; Outline = optimizer2.OptimizeShape(Outline); Outline = optimizer1.OptimizeShape(Outline); // find Longest line segment float dist = 0; LineSegment Longest = new LineSegment(Outline[0], Outline[1]); LineSegment line; dist = Longest.Length; int LongestInd = 0; for (int i = 1; i < Outline.Count; i++) { if (i != Outline.Count - 1) { line = new LineSegment(Outline[i], Outline[i + 1]); } else { // last iteration if (Outline[i] == Outline[0]) { break; } line = new LineSegment(Outline[i], Outline[0]); } if (line.Length > dist) { Longest = line; dist = line.Length; LongestInd = i; } } // Get the center point of it AForge.Point LongestCenter = new AForge.Point(); LongestCenter.X = (float)Math.Round((Longest.End.X - Longest.Start.X) / 2.0 + Longest.Start.X); LongestCenter.Y = (float)Math.Round((Longest.End.Y - Longest.Start.Y) / 2.0 + Longest.Start.Y); AForge.Point NormalStart = new AForge.Point(); AForge.Point NormalEnd = new AForge.Point(); // Find normal: // start= longest.start rotated +90deg relative to center // end= longest.end rotated -90deg and relative to center // If you rotate point (px, py) around point (ox, oy) by angle theta you'll get: // p'x = cos(theta) * (px-ox) - sin(theta) * (py-oy) + ox // p'y = sin(theta) * (px-ox) + cos(theta) * (py-oy) + oy // cos90 = 0, sin90= 1 => // p'x= -(py-oy) + ox= oy-py+ox, p'y= (px-ox)+ oy NormalStart.X = LongestCenter.Y - Longest.Start.Y + LongestCenter.X; NormalStart.Y = (Longest.Start.X - LongestCenter.X) + LongestCenter.Y; // cos-90=0, sin-90= -1 => // p'x= (py-oy) + ox // p'y= -(px-ox)+oy= ox-px+oy NormalEnd.X = (Longest.Start.Y - LongestCenter.Y) + LongestCenter.X; NormalEnd.Y = LongestCenter.X - Longest.Start.X + LongestCenter.Y; // Make line out of the points Line Normal = Line.FromPoints(NormalStart, NormalEnd); // Find the furthest intersection to the normal (skip the Longest) AForge.Point InterSection = new AForge.Point(); AForge.Point Furthest = new AForge.Point(); bool FurhtestAssinged = false; LineSegment seg; dist = 0; for (int i = 0; i < Outline.Count; i++) { if (i == LongestInd) { continue; } if (i != Outline.Count - 1) { seg = new LineSegment(Outline[i], Outline[i + 1]); } else { // last iteration if (Outline[i] == Outline[0]) { break; } seg = new LineSegment(Outline[i], Outline[0]); } if (seg.GetIntersectionWith(Normal) == null) { continue; } InterSection = (AForge.Point)seg.GetIntersectionWith(Normal); if (InterSection.DistanceTo(LongestCenter) > dist) { Furthest = InterSection; FurhtestAssinged = true; dist = InterSection.DistanceTo(LongestCenter); } } // Check, if there is a edge point that is close to the normal even further AForge.Point fPoint = new AForge.Point(); for (int i = 0; i < Outline.Count; i++) { fPoint.X = Outline[i].X; fPoint.Y = Outline[i].Y; if (Normal.DistanceToPoint(fPoint) < 1.5) { if (fPoint.DistanceTo(LongestCenter) > dist) { Furthest = fPoint; FurhtestAssinged = true; dist = fPoint.DistanceTo(LongestCenter); } } } AForge.Point ComponentCenter = new AForge.Point(); if (FurhtestAssinged) { // Find the midpoint of LongestCenter and Furthest: This is the centerpoint of component ComponentCenter.X = (float)Math.Round((LongestCenter.X - Furthest.X) / 2.0 + Furthest.X); ComponentCenter.Y = (float)Math.Round((LongestCenter.Y - Furthest.Y) / 2.0 + Furthest.Y); // Alignment is the angle of longest double Alignment; if (Math.Abs(Longest.End.X - Longest.Start.X) < 0.001) { Alignment = 0; } else { Alignment = Math.Atan((Longest.End.Y - Longest.Start.Y) / (Longest.End.X - Longest.Start.X)); Alignment = Alignment * 180.0 / Math.PI; // in deg. } Components.Add(new Shapes.Component(ComponentCenter, Alignment, Outline, Longest, NormalStart, NormalEnd)); } } return Components; }
/// <summary> /// Finds, provided it exists, the intersection point with the specified <see cref="LineSegment"/>. /// </summary> /// /// <param name="other"><see cref="LineSegment"/> to find intersection with.</param> /// /// <returns>Returns intersection point with the specified <see cref="LineSegment"/>, or <see langword="null"/>, /// if this line does not intersect with the segment.</returns> /// /// <remarks><para>If the line and segment do not intersect, the method returns <see langword="null"/>. /// If the line and segment share multiple points, the method throws an <see cref="InvalidOperationException"/>. /// </para></remarks> /// /// <exception cref="InvalidOperationException">Thrown if <paramref name="other"/> is a portion /// of this line.</exception> /// public Point? GetIntersectionWith( LineSegment other ) { return other.GetIntersectionWith( this ); }
/// <summary> /// Process the filter on the specified image. /// </summary> /// /// <param name="image">Source image data.</param> /// protected override unsafe void ProcessFilter(UnmanagedImage image) { // get border point which is still in the line IntPoint a = new IntPoint(0, 0); IntPoint b = new IntPoint(0, image.Height); IntPoint c = new IntPoint(image.Width, 0); IntPoint d = new IntPoint(image.Width, image.Height); LineSegment top = new LineSegment(a, c); LineSegment left = new LineSegment(a, b); LineSegment right = new LineSegment(c, d); LineSegment bottom = new LineSegment(b, d); AForge.Point?[] points = new AForge.Point?[4]; points[0] = line.GetIntersectionWith(bottom); points[1] = line.GetIntersectionWith(left); points[2] = line.GetIntersectionWith(right); points[3] = line.GetIntersectionWith(top); IntPoint? p1 = null; IntPoint? p2 = null; foreach (var p in points) { if (p == null) continue; if (p1 == null) { p1 = p.Value.Round(); continue; } p2 = p.Value.Round(); break; } IntPoint start = new IntPoint(image.Width - p1.Value.X, p1.Value.Y); IntPoint end = new IntPoint(image.Width - p2.Value.X, p2.Value.Y); Drawing.Line(image, start, end, markerColor); }
/// <summary> /// Finds, provided it exists, the intersection point with the specified <see cref="LineSegment"/>. /// </summary> /// /// <param name="other"><see cref="LineSegment"/> to find intersection with.</param> /// /// <returns>Returns intersection point with the specified <see cref="LineSegment"/>, or <see langword="null"/>, if /// the two segments do not intersect.</returns> /// /// <remarks><para>If the two segments do not intersect, the method returns <see langword="null"/>. If the two /// segments share multiple points, this throws an <see cref="InvalidOperationException"/>. /// </para></remarks> /// /// <exception cref="InvalidOperationException">Thrown if the segments overlap - if they have /// multiple points in common.</exception> /// public DoublePoint? GetIntersectionWith( LineSegment other ) { DoublePoint? result = null; if ( ( line.Slope == other.line.Slope ) || ( line.IsVertical && other.line.IsVertical ) ) { if ( line.Intercept == other.line.Intercept ) { // Collinear segments. Inspect and handle. // Consider this segment AB and other as CD. (start/end in both cases) // There are three cases: // 0 shared points: C and D both project onto the same ray of AB // 1 shared point: One of A or B equals one of C or D, and the other of C/D // projects on the correct ray. // Many shared points. ProjectionLocation projC = LocateProjection( other.start ), projD = LocateProjection( other.end ); if ( ( projC != ProjectionLocation.SegmentAB ) && ( projC == projD ) ) { // no shared points result = null; } else if ( ( ( start == other.start ) && ( projD == ProjectionLocation.RayA ) ) || ( ( start == other.end ) && ( projC == ProjectionLocation.RayA ) ) ) { // shared start point result = start; } else if ( ( ( end == other.start ) && ( projD == ProjectionLocation.RayB ) ) || ( ( end == other.end ) && ( projC == ProjectionLocation.RayB ) ) ) { // shared end point result = end; } else { // overlapping throw new InvalidOperationException( "Overlapping segments do not have a single intersection point." ); } } } else { result = GetIntersectionWith( other.line ); if ( ( result.HasValue ) && ( other.LocateProjection( result.Value ) != ProjectionLocation.SegmentAB ) ) { // the intersection is on the extended line of this segment result = null; } } return result; }
/// <summary> /// Finds, provided it exists, the intersection point with the specified <see cref="LineSegment"/>. /// </summary> /// /// <param name="other"><see cref="LineSegment"/> to find intersection with.</param> /// /// <returns>Returns intersection point with the specified <see cref="LineSegment"/>, or <see langword="null"/>, /// if this line does not intersect with the segment.</returns> /// /// <remarks><para>If the line and segment do not intersect, the method returns <see langword="null"/>. /// If the line and segment share multiple points, the method throws an <see cref="InvalidOperationException"/>. /// </para></remarks> /// /// <exception cref="InvalidOperationException">Thrown if <paramref name="other"/> is a portion /// of this line.</exception> /// public Point?GetIntersectionWith(LineSegment other) { return(other.GetIntersectionWith(this)); }
public Component(Point centr, double alignmnt, List<IntPoint> outln, LineSegment lngst, Point Nstart, Point Nend) : base(centr.X, centr.Y) { Alignment = alignmnt; Outline = outln; Longest = lngst; NormalStart = Nstart; NormalEnd = Nend; }