/// <summary>
 /// Construct from values.
 /// </summary>
 /// <param name="contour"></param>
 /// <param name="ellipse"></param>
 /// <param name="rating"></param>
 public DetectedEllipse(
   Emgu.CV.Contour<System.Drawing.Point> contour,
   Emgu.CV.Structure.Ellipse ellipse,
   double rating) {
   _contour = contour;
   _ellipse = ellipse;
   _rating = rating;
 }
Esempio n. 2
0
 /// <summary>
 /// Construct from values.
 /// </summary>
 /// <param name="contour"></param>
 /// <param name="ellipse"></param>
 /// <param name="rating"></param>
 public DetectedEllipse(
     Emgu.CV.Contour <System.Drawing.Point> contour,
     Emgu.CV.Structure.Ellipse ellipse,
     double rating)
 {
     _contour = contour;
     _ellipse = ellipse;
     _rating  = rating;
 }
Esempio n. 3
0
        /// <summary>
        /// Fit ellipse through contour points in a least square sense.
        /// </summary>
        /// <param name="c">Contour</param>
        /// <returns>Ellipse</returns>
        private Emgu.CV.Structure.Ellipse FitByContour(Emgu.CV.Contour <System.Drawing.Point> c)
        {
            System.Drawing.PointF[] mypoints = Array.ConvertAll(
                c.ToArray <System.Drawing.Point>(),
                value => new System.Drawing.PointF(value.X, value.Y)
                );

            Emgu.CV.Structure.Ellipse  e   = Emgu.CV.PointCollection.EllipseLeastSquareFitting(mypoints);
            Emgu.CV.Structure.MCvBox2D box = e.MCvBox2D;
            // Modify ellipse to have width = a, height = b in the ellipse equation.
            box.size.Height *= 0.5f;
            box.size.Width  *= 0.5f;
            return(new Emgu.CV.Structure.Ellipse(box));
        }
Esempio n. 4
0
        /// <summary>
        /// Get the affine matrix ellipse frame. Frame is with respect to world frame and
        /// scales the ellipse to become a circle of radius b, where b is the height of
        /// the rotated rect that contains the ellipse.
        /// </summary>
        public static Matrix GetAffineFrame(Emgu.CV.Structure.Ellipse e)
        {
            // The required scaling is given by the ratio of the extensions
            // of the ellipse main axes.

            double a       = e.MCvBox2D.size.Width;
            double b       = e.MCvBox2D.size.Height;
            double scaling = 1.0;

            if (a > b)
            {
                scaling = b / a;
            }
            else
            {
                scaling = a / b;
            }

            Matrix scale = Matrix.Identity(3, 3);

            scale[0, 0] = scaling;

            // Translation is simply the center of the ellipse

            Matrix translation = Matrix.Identity(3, 3);

            translation[0, 2] = e.MCvBox2D.center.X;
            translation[1, 2] = e.MCvBox2D.center.Y;

            // The rotation is the angle of the rotated rect with the x-axis
            // This rotation transform is equal to rotating a frame in reverse
            // direction.

            Matrix rotation = Matrix.Identity(3, 3);
            double angle    = e.MCvBox2D.angle / 180 * Math.PI;

            rotation[0, 0] = Math.Cos(-angle);
            rotation[0, 1] = -Math.Sin(-angle);
            rotation[1, 0] = Math.Sin(-angle);
            rotation[1, 1] = Math.Cos(-angle);

            // The pose of the ellipse coordinate frame with respect
            // to the world (image) coordinate frame is given by
            Matrix m = translation * rotation * scale;

            return(m);
        }
Esempio n. 5
0
        /// <summary>
        /// Detect ellipses in image
        /// </summary>
        /// <param name="image">Binary image with white foreground</param>
        /// <returns>List of ellipses found</returns>
        public DetectedEllipse[] DetectEllipses(Emgu.CV.Image <Emgu.CV.Structure.Gray, byte> image)
        {
            List <DetectedEllipse> ellipses = new List <DetectedEllipse>();

            Emgu.CV.Contour <System.Drawing.Point> c = image.FindContours();

            while (c != null)
            {
                if (c.Count() >= _min_contour_count)
                {
                    Emgu.CV.Structure.Ellipse e = FitByContour(c);
                    double rating = GoodnessOfFit(e, c);
                    ellipses.Add(new DetectedEllipse(c, e, rating));
                }
                c = c.HNext;
            }

            return(ellipses.ToArray());
        }
Esempio n. 6
0
        /// <summary>
        /// Evaluate goodness of fit.
        /// </summary>
        /// <remarks>
        /// Calculates the average distance of all contour points to the ellipse. The distance of point to
        /// an ellipse is given by calculating the point on the ellipse that is closest to the query. This calculation
        /// is performed by transforming the point into a coordinate system where the ellipse is in main-pose
        /// (x-axis points toward a, y-axis points toward b, the origin is the center of the ellipse). Additionally,
        /// the coordinate system is crafted in such a way (non-uniform scaling) that the ellipse becomes a circle.
        /// Then, the closest point is simply the closest point on the circle. This point is transformed back into
        /// the world coordinate system where the distance between the query and the returned point is computed.
        /// </remarks>
        /// <param name="e">Ellipse</param>
        /// <param name="c">Contour points</param>
        /// <returns>Goodness of fit</returns>
        private double GoodnessOfFit(Emgu.CV.Structure.Ellipse e, Emgu.CV.Contour <System.Drawing.Point> c)
        {
            Matrix        m         = EllipseDetector.GetAffineFrame(e);
            Matrix        inv       = m.Inverse();
            List <double> distances = new List <double>();

            double avg_distance = 0.0;

            foreach (System.Drawing.Point p in c)
            {
                // Bring the point into the ellipse coordinate frame
                Vector x = p.ToParsley().ToHomogeneous(1.0);
                Vector r = (inv.Multiply(x.ToColumnMatrix())).GetColumnVector(0);
                // Find the closest point on the circle to r
                // From the above scaling construction the resulting circle has radius b
                Vector closest = r.ToNonHomogeneous().Normalize().Scale(e.MCvBox2D.size.Height);
                // Transform the closest point back
                Vector closest_in_world = (m.Multiply(closest.ToHomogeneous(1.0).ToColumnMatrix())).GetColumnVector(0);
                // Calculate the squared distance between the query and the point.
                avg_distance += (closest_in_world - x).ToNonHomogeneous().SquaredNorm();
            }
            return(Math.Sqrt(avg_distance / c.Count()));
        }