AForge.Math.Geometry.PointsCloud.FindQuadrilateralCorners C# (CSharp) Method

FindQuadrilateralCorners() public static method

Find corners of quadrilateral or triangular area, which contains the specified collection of points.

The method makes an assumption that the specified collection of points form some sort of quadrilateral/triangular area. With this assumption it tries to find corners of the area.

The method does not search for bounding quadrilateral/triangular area, where all specified points are inside of the found quadrilateral/triangle. Some of the specified points potentially may be outside of the found quadrilateral/triangle, since the method takes corners only from the specified collection of points, but does not calculate such to form true bounding quadrilateral/triangle.

See QuadrilateralRelativeDistortionLimit property for additional information.

public static FindQuadrilateralCorners ( IEnumerable cloud ) : List
cloud IEnumerable Collection of points to search quadrilateral for.
return List
        public static List<IntPoint> FindQuadrilateralCorners( IEnumerable<IntPoint> cloud )
        {
            // quadrilateral's corners
            List<IntPoint> corners = new List<IntPoint>( );

            // get bounding rectangle of the points list
            IntPoint minXY, maxXY;
            PointsCloud.GetBoundingRectangle( cloud, out minXY, out maxXY );
            // get cloud's size
            IntPoint cloudSize = maxXY - minXY;
            // calculate center point
            IntPoint center = minXY + cloudSize / 2;
            // acceptable deviation limit
            double distortionLimit = quadrilateralRelativeDistortionLimit * ( cloudSize.X + cloudSize.Y ) / 2;

            // get the furthest point from (0,0)
            IntPoint point1 = PointsCloud.GetFurthestPoint( cloud, center );
            // get the furthest point from the first point
            IntPoint point2 = PointsCloud.GetFurthestPoint( cloud, point1 );

            corners.Add( point1 );
            corners.Add( point2 );

            // get two furthest points from line
            IntPoint point3, point4;
            double distance3, distance4;

            PointsCloud.GetFurthestPointsFromLine( cloud, point1, point2,
                out point3, out distance3, out point4, out distance4 );

            // ideally points 1 and 2 form a diagonal of the
            // quadrilateral area, and points 3 and 4 form another diagonal

            // but if one of the points (3 or 4) is very close to the line
            // connecting points 1 and 2, then it is one the same line ...
            // which means corner was not found.
            // in this case we deal with a trapezoid or triangle, where
            // (1-2) line is one of it sides.

            // another interesting case is when both points (3) and (4) are
            // very close the (1-2) line. in this case we may have just a flat
            // quadrilateral.

            if (
                 ( ( distance3 >= distortionLimit ) && ( distance4 >= distortionLimit ) ) ||

                 ( ( distance3 < distortionLimit ) && ( distance3 != 0 ) &&
                   ( distance4 < distortionLimit ) && ( distance4 != 0 ) ) )
            {
                corners.Add( point3 );
                corners.Add( point4 );
            }
            else
            {
                // it seems that we deal with kind of trapezoid,
                // where point 1 and 2 are on the same edge

                IntPoint tempPoint = ( distance3 > distance4 ) ? point3 : point4;

                // try to find 3rd point
                PointsCloud.GetFurthestPointsFromLine( cloud, point1, tempPoint,
                    out point3, out distance3, out point4, out distance4 );

                bool thirdPointIsFound = false;

                if ( ( distance3 >= distortionLimit ) && ( distance4 >= distortionLimit ) )
                {
                    if ( point4.DistanceTo( point2 ) > point3.DistanceTo( point2 ) )
                        point3 = point4;

                    thirdPointIsFound = true;
                }
                else
                {
                    PointsCloud.GetFurthestPointsFromLine( cloud, point2, tempPoint,
                        out point3, out distance3, out point4, out distance4 );

                    if ( ( distance3 >= distortionLimit ) && ( distance4 >= distortionLimit ) )
                    {
                        if ( point4.DistanceTo( point1 ) > point3.DistanceTo( point1 ) )
                            point3 = point4;

                        thirdPointIsFound = true;
                    }
                }

                if ( !thirdPointIsFound )
                {
                    // failed to find 3rd edge point, which is away enough from the temp point.
                    // this means that the clound looks more like triangle
                    corners.Add( tempPoint );
                }
                else
                {
                    corners.Add( point3 );

                    // try to find 4th point
                    double tempDistance;

                    PointsCloud.GetFurthestPointsFromLine( cloud, point1, point3,
                        out tempPoint, out tempDistance, out point4, out distance4 );

                    if ( ( distance4 >= distortionLimit ) && ( tempDistance >= distortionLimit ) )
                    {
                        if ( tempPoint.DistanceTo( point2 ) > point4.DistanceTo( point2 ) )
                            point4 = tempPoint;
                    }
                    else
                    {
                        PointsCloud.GetFurthestPointsFromLine( cloud, point2, point3,
                            out tempPoint, out tempDistance, out point4, out distance4 );

                        if ( ( tempPoint.DistanceTo( point1 ) > point4.DistanceTo( point1 ) ) &&
                             ( tempPoint != point2 ) && ( tempPoint != point3 ) )
                        {
                            point4 = tempPoint;
                        }
                    }

                    if ( ( point4 != point1 ) && ( point4 != point2 ) && ( point4 != point3 ) )
                        corners.Add( point4 );
                }
            }

            // put the point with lowest X as the first
            for ( int i = 1, n = corners.Count; i < n; i++ )
            {
                if ( ( corners[i].X < corners[0].X ) ||
                     ( ( corners[i].X == corners[0].X ) && ( corners[i].Y < corners[0].Y ) ) )
                {
                    IntPoint temp = corners[i];
                    corners[i] = corners[0];
                    corners[0] = temp;
                }
            }

            // sort other points in counter clockwise order
            double k1 = ( corners[1].X != corners[0].X ) ?
                ( (double) ( corners[1].Y - corners[0].Y ) / ( corners[1].X - corners[0].X ) ) :
                ( ( corners[1].Y > corners[0].Y ) ? double.PositiveInfinity : double.NegativeInfinity );

            double k2 = ( corners[2].X != corners[0].X ) ?
                ( (double) ( corners[2].Y - corners[0].Y ) / ( corners[2].X - corners[0].X ) ) :
                ( ( corners[2].Y > corners[0].Y ) ? double.PositiveInfinity : double.NegativeInfinity );

            if ( k2 < k1 )
            {
                IntPoint temp = corners[1];
                corners[1] = corners[2];
                corners[2] = temp;

                double tk = k1;
                k1 = k2;
                k2 = tk;
            }

            if ( corners.Count == 4 )
            {
                double k3 = ( corners[3].X != corners[0].X ) ?
                    ( (double) ( corners[3].Y - corners[0].Y ) / ( corners[3].X - corners[0].X ) ) :
                    ( ( corners[3].Y > corners[0].Y ) ? double.PositiveInfinity : double.NegativeInfinity );

                if ( k3 < k1 )
                {
                    IntPoint temp = corners[1];
                    corners[1] = corners[3];
                    corners[3] = temp;

                    double tk = k1;
                    k1 = k3;
                    k3 = tk;
                }
                if ( k3 < k2 )
                {
                    IntPoint temp = corners[2];
                    corners[2] = corners[3];
                    corners[3] = temp;

                    double tk = k2;
                    k2 = k3;
                    k3 = tk;
                }
            }

            return corners;
        }

Usage Example

Example #1
0
 // Get optimized quadrilateral area
 private List <IntPoint> GetShapeCorners(List <IntPoint> edgePoints)
 {
     return(shapeOptimizer.OptimizeShape(PointsCloud.FindQuadrilateralCorners(edgePoints)));
 }