Graham scan algorithm for finding convex hull.

The class implements Graham scan algorithm for finding convex hull of a given set of points.

Sample usage:

// generate some random points Random rand = new Random( ); List<IntPoint> points = new List<IntPoint>( ); for ( int i = 0; i < 10; i++ ) { points.Add( new IntPoint( rand.Next( 200 ) - 100, rand.Next( 200 ) - 100 ) ); } // find the convex hull IConvexHullAlgorithm hullFinder = new GrahamConvexHull( ); List<IntPoint> hull = hullFinder.FindHull( points );
Inheritance: IConvexHullAlgorithm
Exemple #1
0
        // Set monochromeImage to display by the control
        public int ScanImage(Bitmap monochromeImage)
        {
            this.hulls.Clear();

            this.image = monochromeImage;

            this.blobCounter.ProcessImage(this.image);

            this.blobs = this.blobCounter.GetObjectsInformation();

            var grahamScan = new GrahamConvexHull();

            foreach (var blob in this.GetBlobs())
            {
                List<IntPoint> leftEdge;
                List<IntPoint> rightEdge;
                List<IntPoint> topEdge;
                List<IntPoint> bottomEdge;

                // collect edge points
                this.blobCounter.GetBlobsLeftAndRightEdges(blob, out leftEdge, out rightEdge);
                this.blobCounter.GetBlobsTopAndBottomEdges(blob, out topEdge, out bottomEdge);

                // find convex hull
                var edgePoints = new List<IntPoint>();
                edgePoints.AddRange(leftEdge);
                edgePoints.AddRange(rightEdge);

                List<IntPoint> hull = grahamScan.FindHull(edgePoints);
                this.hulls.Add(blob.ID, hull);
            }

            return this.blobs.Length;
        }
Exemple #2
0
        public ImageProcessor()
        {
            shapeChecker = new SimpleShapeChecker();
            hullFinder = new GrahamConvexHull();

            blobCounter = new BlobCounter();

            HotGoal = 0;

            greenPen = new Pen(Color.FromArgb(0, 255, 0), 1);
            yellowPen = new Pen(Color.FromArgb(255, 255, 0), 1);
            redPen = new Pen(Color.FromArgb(255, 0, 0), 2);
            orangePen = new Pen(Color.FromArgb(255, 127, 0), 1);
            purplePen = new Pen(Color.FromArgb(102, 51, 153), 1);
            redBrush = new SolidBrush(Color.FromArgb(255, 0, 0));
            blueBrush = new SolidBrush(Color.FromArgb(0, 0, 255));
        }
        public Bitmap ProcessFrame(Bitmap inputBitmap, int x, int y)
        {
            // Create an image for AForge to process
            Bitmap workingImage = new Bitmap(inputBitmap.Width, inputBitmap.Height);
            workingImage = AForge.Imaging.Image.Clone(inputBitmap, PixelFormat.Format24bppRgb);

            // Create a mask for ROI selection
            Rectangle roi = new Rectangle(x - 30, y-30, 80, 80);

            Crop roicrop = new Crop(roi);
            Bitmap outimage = roicrop.Apply(workingImage);

            BlobCounter blobCounter = new BlobCounter();
            blobCounter.ObjectsOrder = ObjectsOrder.Area;

            Blob[] blobs;

            // Find the blobs
            blobCounter.ProcessImage(outimage);
            blobs = blobCounter.GetObjectsInformation();
            List<IntPoint> edgePoints = blobCounter.GetBlobsEdgePoints(blobs[0]);

            GrahamConvexHull grahamScan = new GrahamConvexHull();
            List<IntPoint> hullPoints = grahamScan.FindHull(edgePoints);

            Graphics g = Graphics.FromImage(outimage);
            Pen redPen = new Pen(Color.Red, 2);

            g.DrawPolygon(redPen, ToPointsArray(hullPoints));

            //g.Clear(Color.Black);
            //g.DrawImage(handImage, x, y);
            //g.DrawRectangle(redPen, roi);
            //g.DrawEllipse(redPen, x, y, 20, 20);

            ResizeNearestNeighbor resizeFilter = new ResizeNearestNeighbor(160, 160);
            Bitmap resizedImage = resizeFilter.Apply(outimage);

            return resizedImage;
        }
Exemple #4
0
        // Set monochromeImage to display by the control
        public IList<Polygon> ScanImage(Bitmap monochromeImage)
        {
            this.hulls.Clear();

            this.image = monochromeImage;

            this.blobCounter.ProcessImage(this.image);

            this.blobs = this.blobCounter.GetObjectsInformation();

            var grahamScan = new GrahamConvexHull();

            var polygons = new List<Polygon>();
            foreach (var blob in this.GetBlobs())
            {
                List<IntPoint> leftEdge;
                List<IntPoint> rightEdge;

                // collect edge points
                this.blobCounter.GetBlobsLeftAndRightEdges(blob, out leftEdge, out rightEdge);

                // find convex hull
                var edgePoints = new List<IntPoint>();
                edgePoints.AddRange(leftEdge);
                edgePoints.AddRange(rightEdge);

                var hull = grahamScan.FindHull(edgePoints);
                this.hulls.Add(blob.ID, hull);

                var minX = edgePoints.Min(x => x.X);
                var minY = edgePoints.Min(x => x.Y);
                var maxY = edgePoints.Max(x => x.Y);
                var maxX = edgePoints.Max(x => x.X);

                polygons.Add(new Polygon(new Point(minX, minY), new Point(maxX, maxY)));
            }

            return polygons;
        }
Exemple #5
0
        // ==========================================================================================================
        // 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;
        }
        public void FindHullTest( )
        {
            GrahamConvexHull grahamHull = new GrahamConvexHull( );

            for ( int i = 0, n = pointsLists.Count; i < n; i++ )
            {
                ComparePointsLists( grahamHull.FindHull( pointsLists[i] ), expectedHulls[i] );
            }
        }
        /**
         * Loops through our depth range filtered data and saves our tracked points
         */
        private void ProcessTrackedPoints()
        {
            System.Drawing.Rectangle[] rects = pointTracker.GetObjectsRectangles();

            Points.Clear();

            float xPos, yPos;

            for (int i = 0; i < rects.Length; i++)
            {
                xPos = (((float)rects[i].X + ((float)rects[i].Width / 2)) / (float)trackingRegion.Width) * depthWidth;
                yPos = (((float)rects[i].Y + ((float)rects[i].Height / 2)) / (float)trackingRegion.Height) * depthHeight;

                Points.Add(new System.Drawing.Point((int)xPos, (int)yPos));
            }

            // create convex hull searching algorithm
            GrahamConvexHull hullFinder = new GrahamConvexHull();

            // lock image to draw on it
            BitmapData data = regionedBmp.LockBits(
                new Rectangle(0, 0, regionedBmp.Width, regionedBmp.Height),
                    ImageLockMode.ReadWrite, regionedBmp.PixelFormat);

            // process each blob
            foreach (Blob blob in pointTracker.GetObjectsInformation())
            {
                List<IntPoint> edgePoints = new List<IntPoint>();

                List<IntPoint> leftPoints, rightPoints;

                // get blob's edge points
                pointTracker.GetBlobsLeftAndRightEdges(blob,
                    out leftPoints, out rightPoints);

                edgePoints.AddRange(leftPoints);
                edgePoints.AddRange(rightPoints);

                // blob's convex hull
                List<IntPoint> hull = hullFinder.FindHull(edgePoints);

                Drawing.Polygon(data, hull, Color.Red);
            }

            regionedBmp.UnlockBits(data);
        }
Exemple #8
0
        // Set image to display by the control
        public int SetImage( Bitmap image )
        {
            leftEdges.Clear( );
            rightEdges.Clear( );
            topEdges.Clear( );
            bottomEdges.Clear( );
            hulls.Clear( );
            quadrilaterals.Clear( );

            selectedBlobID = 0;

            this.image  = AForge.Imaging.Image.Clone( image, PixelFormat.Format24bppRgb );
            imageWidth  = this.image.Width;
            imageHeight = this.image.Height;

            blobCounter.ProcessImage( this.image );
            blobs = blobCounter.GetObjectsInformation( );

            GrahamConvexHull grahamScan = new GrahamConvexHull( );

            foreach ( Blob blob in blobs )
            {
                List<IntPoint> leftEdge   = new List<IntPoint>( );
                List<IntPoint> rightEdge  = new List<IntPoint>( );
                List<IntPoint> topEdge    = new List<IntPoint>( );
                List<IntPoint> bottomEdge = new List<IntPoint>( );

                // collect edge points
                blobCounter.GetBlobsLeftAndRightEdges( blob, out leftEdge, out rightEdge );
                blobCounter.GetBlobsTopAndBottomEdges( blob, out topEdge, out bottomEdge );

                leftEdges.Add( blob.ID, leftEdge );
                rightEdges.Add( blob.ID, rightEdge );
                topEdges.Add( blob.ID, topEdge );
                bottomEdges.Add( blob.ID, bottomEdge );

                // find convex hull
                List<IntPoint> edgePoints = new List<IntPoint>( );
                edgePoints.AddRange( leftEdge );
                edgePoints.AddRange( rightEdge );

                List<IntPoint> hull = grahamScan.FindHull( edgePoints );
                hulls.Add( blob.ID, hull );

                // find quadrilateral
                List<IntPoint> quadrilateral = PointsCloud.FindQuadrilateralCorners( hull );
                quadrilaterals.Add( blob.ID, quadrilateral );

                // shift all points for vizualization
                IntPoint shift = new IntPoint( 1, 1 );

                PointsCloud.Shift( leftEdge, shift );
                PointsCloud.Shift( rightEdge, shift );
                PointsCloud.Shift( topEdge, shift );
                PointsCloud.Shift( bottomEdge, shift );
                PointsCloud.Shift( hull, shift );
                PointsCloud.Shift( quadrilateral, shift );
            }

            UpdatePosition( );
            Invalidate( );

            return blobs.Length;
        }
        private System.Drawing.Image ProcessBlobs(Bitmap image, Bitmap ProcessedImage, Input input)
        {
            Bitmap ResultImage;                                     // our return image variable
            // Choose which view to overlay our data on
            if (NoFilters)
            {
                ResultImage = (Bitmap)image.Clone();
            }
            else
            {
                ResultImage = new Bitmap(xMax / 2,yMax);
            }

            // Create the blob counter and get the blob info array for further processing
            BlobCounter blobCounter = new BlobCounter();
            // We *COULD* filter blobs here, but as pointed out that blocks the ability to eventually twist the hand/fingers horizontally.
            //blobCounter.FilterBlobs = true;
            //blobCounter.MinHeight = minHeight;
            //blobCounter.MaxWidth = maxWidth;
            blobCounter.ProcessImage(ProcessedImage);
            Blob[] blobs = blobCounter.GetObjectsInformation();

            // create convex hull searching algorithm
            GrahamConvexHull hullFinder = new GrahamConvexHull();

            // Create graphics control to draw in the picture
            Graphics g = Graphics.FromImage(ResultImage);

            // Label the camfeeds just to prove this works right...
            g.DrawString(input.ToString(), new Font("Arial", 16), new SolidBrush(Color.Blue), new PointF(0, 0));

            // process each blob
            foreach (Blob blob in blobs)
            {
                if (CheckBlob(blob))
                {
                    List<IntPoint> leftPoints, rightPoints;
                    List<IntPoint> edgePoints = new List<IntPoint>();

                    // get blob's edge points
                    blobCounter.GetBlobsLeftAndRightEdges(blob,
                        out leftPoints, out rightPoints);

                    edgePoints.AddRange(leftPoints);
                    edgePoints.AddRange(rightPoints);

                    // calculate the blob's convex hull
                    List<IntPoint> hull = hullFinder.FindHull(edgePoints);

                    // Calculate depth
                    int pix = (int)CvInvoke.cvGet2D(disparity, blob.Rectangle.Top, ((blob.Rectangle.Left + blob.Rectangle.Right) / 2)).v0;

                    // Draw the blob hull and id it with the width/height
                    g.DrawPolygon(new Pen(Color.Blue), IntPointsToPointFs(hull.ToArray()));
                    string coord = "";
                    coord += blob.Rectangle.Width.ToString() + ",";         // X
                    coord += blob.Rectangle.Height.ToString() + ",";        // Y
                    coord += pix.ToString();                              // Z
                    g.DrawString(coord, new Font("Arial", 16), new SolidBrush(Color.Blue), new PointF(hull[0].X, hull[0].Y));

                    // This next line is all we should need once done debugging/designing. Toss the image manipulation.
                    hand.AddFinger(new System.Drawing.Point(((blob.Rectangle.Left + blob.Rectangle.Right) / 2), blob.Rectangle.Top), pix, (Hand.Input)input);
                }
            }

            return ResultImage;
        }
Exemple #10
0
        /// <summary>
        /// Event to trigger upon clicking the "Calibrate" button
        /// </summary>
        /// <param name="sender">Sender of the event</param>
        /// <param name="e">Event arguments</param>
        private void button1_Click(object sender, EventArgs e)
        {
            // what to do when progress changed (update the progress bar for example)
            ProgressChangedEventHandler prog = new ProgressChangedEventHandler(
            delegate(object o, ProgressChangedEventArgs args)
            {
                progress = args.ProgressPercentage;
                instructions.Text = string.Format("{0}% Completed", args.ProgressPercentage);
            });

            // what to do when worker completes its task (notify the user)
            RunWorkerCompletedEventHandler compl = new RunWorkerCompletedEventHandler(
            delegate(object o, RunWorkerCompletedEventArgs args)
            {
                if (!args.Cancelled && (null == args.Error))
                {
                    instructions.Text = "Ready to go!";
                    detectionRate.Start();
                    Bitmap[,] samples = (Bitmap[,])args.Result;

                    BackgroundWorker showRes = new BackgroundWorker();
                    showRes.DoWork += new DoWorkEventHandler(delegate(object obj, DoWorkEventArgs arguments)
                        {
                            try
                            {
                                Blob[] blobs;
                                List<IntPoint> leftEdge, rightEdge, topEdge, bottomEdge;

                                for (int i = 0; i < 10; i++)
                                {
                                    //Build a convex hull around blobs
                                    //maxBlobFilter = new ExtractBiggestBlob();
                                    Bitmap image = samples[0, i];
                                    lock (image)
                                    {
                                        blobCounter.ProcessImage(image);
                                        blobs = blobCounter.GetObjectsInformation();
                                        // lock image to draw on it
                                        BitmapData data = image.LockBits(new Rectangle(0, 0, image.Width, image.Height), ImageLockMode.ReadWrite, image.PixelFormat);

                                        GrahamConvexHull grahamScan = new GrahamConvexHull();
                                        foreach (Blob blob in blobs)
                                        {
                                            // collect edge points
                                            blobCounter.GetBlobsLeftAndRightEdges(blob, out leftEdge, out rightEdge);
                                            blobCounter.GetBlobsTopAndBottomEdges(blob, out topEdge, out bottomEdge);

                                            // find convex hull
                                            List<IntPoint> edgePoints = new List<IntPoint>();
                                            edgePoints.AddRange(leftEdge);
                                            edgePoints.AddRange(rightEdge);

                                            List<IntPoint> hull = grahamScan.FindHull(edgePoints);

                                            // Paint the control
                                            Drawing.Polygon(data, hull, Color.Red);

                                            Line l1, l2, l3;
                                            int vertexNum = hull.Count;
                                            for (int firstEdge = 0; firstEdge < vertexNum - 3; firstEdge++)
                                            {
                                                l1.start = hull.ElementAt(firstEdge);
                                                l1.end = hull.ElementAt(firstEdge + 1);
                                                for (int secondEdge = 1; secondEdge < vertexNum - 2; secondEdge++)
                                                {
                                                    l2.start = hull.ElementAt(secondEdge);
                                                    l2.end = hull.ElementAt(secondEdge);
                                                    for (int thirdEdge = 2; thirdEdge < vertexNum - 1; thirdEdge++)
                                                    {
                                                        l3.start = hull.ElementAt(thirdEdge);
                                                        l3.end = hull.ElementAt(thirdEdge);


                                                    }
                                                }
                                            }
                                        }

                                        image.UnlockBits(data);
                                    }
                                    //trainingPic.Image = image;

                                    //System.Threading.Thread.Sleep(1000);
                                }
                            }
                            catch (TargetInvocationException ex)
                            {
                                Console.Out.WriteLine(ex.Message);
                            }
                        });
                    showRes.WorkerReportsProgress = false;
                    showRes.RunWorkerAsync();
                    bool working = showRes.IsBusy;
                }
            });
            //trainingPic.Image = mirror.Apply(bgm.MotionFrame).ToManagedImage();
            
            learner.Learn((frameWidth / 2) - ((int)calibrationBoxWidth.Value / 2), (frameHeight / 2) - 120, (int)calibrationBoxWidth.Value, 200, 1, getMovementImage, prog, compl);
        }