예제 #1
0
        private static List <EllipticalFit> AddWithoutOverlap(List <EllipticalFit> ellipseList, EllipticalFit fit)
        {
            List <EllipticalFit> outList = new List <EllipticalFit>();

            if (ellipseList.Count == 0)
            {
                outList.Add(fit);
                return(outList);
            }
            else
            {
                bool addFit = true;
                for (int i = 0; i < ellipseList.Count; i++)
                {
                    if (ellipseList[i].BoundingRectangle().IntersectsWith(fit.BoundingRectangle()))
                    {
                        // In case over overlap: only add the best one
                        if (ellipseList[i].DifferenceFromCircle < fit.DifferenceFromCircle)
                        {
                            addFit = false;
                            outList.Add(ellipseList[i]);
                        }
                    }
                    else // Add both
                    {
                        outList.Add(ellipseList[i]);
                    }
                }
                if (addFit)
                {
                    outList.Add(fit);
                }
                return(outList);
            }
        }
예제 #2
0
        private static List <EllipticalFit> FindPointsByCanny(int numberToFind,
                                                              int currentCross, byte[,] cannyData, int searchSize, ref int searchShift, ref int attempt, ref bool ellipsesValid)
        {
            searchSize = (int)(Math.Round((double)searchSize / 2) * 2); // has to be even
            int shiftX     = searchShift == 1 || searchShift == 3 ? (int)(searchSize / 4) : 0;
            int shiftY     = searchShift == 2 || searchShift == 3 ? (int)(searchSize / 4) : 0;
            int searchJump = searchSize / 2;
            int w          = cannyData.GetLength(0);
            int h          = cannyData.GetLength(1);

            // Create a list with areas to look => cannot be reused due to (even very small) differences in size of scans
            List <Point> searchPoints = new List <Point>();

            for (int x = shiftX; x < w; x += searchJump)
            {
                int searchX = x;
                if (x + searchSize >= w)
                {
                    searchX = w - searchSize;
                    x       = w;
                }
                for (int y = shiftY; y < h; y += searchJump)
                {
                    int searchY = y;
                    if (y + searchSize >= h)
                    {
                        searchY = h - searchSize;
                        y       = h;
                    }
                    searchPoints.Add(new Point(searchX, searchY));
                }
            }

            // Assumed that the paper is oriented right => faster
            searchPoints.Sort(delegate(Point p1, Point p2) { return(Math.Min(w - p1.X, h - p1.Y).CompareTo(Math.Min(w - p2.X, h - p2.Y))); });

            /*
             *
             *
             *
             *
             ********
             */

#if DEBUG
            var img = Processing.ByteToImage(cannyData);
#endif

            // Crop small rectangles from canny
            List <EllipticalFit> ellipseList = new List <EllipticalFit>();
            for (int i = 0; i < searchPoints.Count; i++)
            {
                // Fit an ellipse
                EllipticalFit fit = null;
                RectangleF    boundingRectangle = new RectangleF();
                try
                {
                    var searchRectangle = new Rectangle(searchPoints[i].X, searchPoints[i].Y, searchSize, searchSize);
                    fit = new EllipticalFit(cannyData, 255, searchRectangle);

#if DEBUG
                    using (Graphics g = Graphics.FromImage(img))
                    {
                        g.DrawRectangle(new Pen(Color.Yellow), searchRectangle);
                    }
#endif

                    // Empty search areas are already ignored in fit
                    boundingRectangle = fit.BoundingRectangle();

                    // If a valid ellipse is found
                    if (!double.IsNaN(boundingRectangle.X) && boundingRectangle.X > 0 &&
                        !double.IsNaN(boundingRectangle.Y) && boundingRectangle.Y > 0 &&
                        boundingRectangle.Width < searchSize && boundingRectangle.Height < searchSize &&
                        boundingRectangle.Width > .25 * searchSize && boundingRectangle.Height > .25 * searchSize &&
                        boundingRectangle.Width > 15 && boundingRectangle.Height > 15)
                    {
                        var    observed   = Processing.Crop(cannyData, searchRectangle);
                        var    moments    = Processing.Moments(observed);
                        double squareness = Math.Min((double)boundingRectangle.Width, (double)boundingRectangle.Height) / Math.Max((double)boundingRectangle.Width, (double)boundingRectangle.Height);

                        // Ellipse has to be more or less round, based on enough points and have some variance in each direction
                        if (squareness > .9 && moments[0] >= 8 && moments[3] > 0 && moments[4] > 0)
                        {
                            // Fill the ellipse with floodfill
                            var observedFilled = Processing.FloodFill(observed, 1, new PointF(
                                                                          boundingRectangle.X - searchRectangle.X + (boundingRectangle.Width / 2),
                                                                          boundingRectangle.Y - searchRectangle.Y + (boundingRectangle.Height / 2)));

                            var momentsFilled = Processing.Moments(observedFilled);

                            if (momentsFilled[1] > (boundingRectangle.Width / 2) && momentsFilled[1] < searchRectangle.Width - (boundingRectangle.Width / 2) &&
                                momentsFilled[2] > (boundingRectangle.Height / 2) && momentsFilled[2] < searchRectangle.Height - (boundingRectangle.Height / 2))
                            {
                                // Create a white circle of similar size
                                var expectedFilled = Processing.WhiteCircle(observedFilled.GetLength(0), observedFilled.GetLength(1), new RectangleF(
                                                                                boundingRectangle.X - searchRectangle.X, boundingRectangle.Y - searchRectangle.Y, boundingRectangle.Width, boundingRectangle.Height));

                                // Compare the result of the floodfill with the white circle
                                fit.DifferenceFromCircle = Processing.AverageDifference(observedFilled, expectedFilled);

                                // Only if ellipse was closed they will be similar
                                if (fit.DifferenceFromCircle < .1)
                                {
                                    ellipseList = AddWithoutOverlap(ellipseList, fit);
                                }
                            }
                        }
                    }
                }
                catch (Exception ex)
                {
                    Logger.LogLow(ex.Message);
                }
                if (ellipseList.Count == numberToFind)
                {
                    break;
                }
            }

            ellipsesValid = EllipsePointsAreValid(Program.Test, ellipseList); // Count and colinearity have to be correct

            /*
             * using (Graphics g = Graphics.FromImage(img))
             * {
             *  for (int i = 0; i < ellipseList.Count; i++)
             *  {
             *      g.DrawLine(new Pen(Color.Blue, 2), ellipseList[i].MidPoint().X - 15, ellipseList[i].MidPoint().Y, ellipseList[i].MidPoint().X + 15, ellipseList[i].MidPoint().Y);
             *      g.DrawLine(new Pen(Color.Blue, 2), ellipseList[i].MidPoint().X, ellipseList[i].MidPoint().Y - 15, ellipseList[i].MidPoint().X, ellipseList[i].MidPoint().Y + 15);
             *  }
             * }
             * img.Save(Program.UserSettings.defaultDirectory + "\\img\\"
             + Convert.ToString(DateTime.Now.Minute)
             + " - " + Convert.ToString(DateTime.Now.Second)
             + " - " + Convert.ToString(DateTime.Now.Millisecond)
             + " - " + currentCross
             + " - " + searchSize
             + " - " + searchShift
             + " - " + attempt
             + " - " + ellipseList.Count
             + " - " + ellipsesValid
             + ".bmp");
             */

            Logger.LogHigh(
                "Attempt:\t" + attempt +
                "\tCanny:\t" + currentCross +
                "\tSearch size:\t" + searchSize +
                "\tSearch shift:\t" + searchShift +
                "\tEllipses found:\t" + ellipseList.Count +
                "\tEllipses valid:\t" + ellipsesValid);

            // If not all ellipses are found, retry with shifted searcharea
            if (ellipseList.Count != numberToFind && searchShift < 3)
            {
                searchShift++;
                attempt++;
                ellipseList = FindPointsByCanny(numberToFind, currentCross, cannyData, searchSize, ref searchShift, ref attempt, ref ellipsesValid);
            }

            return(ellipseList);
        }