Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

HoughCircles Doesn't detect circles correctly in OpenCV

I am using Visual Studio 2015, OpenCV.3 and EmguCV.3. My code represented below and the result is shown in the picture. I know that the problem is the input values of HoughCircles function, but I don't know which inputs are suitable for this picture. I appreciate any help.

                Image<Gray, byte> OriginalImage = new Image<Gray, byte>(Openfile.FileName);
                Image<Gray, byte> ResizedImage = OriginalImage.Resize(OriginalImage.Width / 2, OriginalImage.Height / 2, Emgu.CV.CvEnum.Inter.Cubic);

                //********** Convert Image to Binary
                Image<Gray, byte> smoothImg = 
                ResizedImage.SmoothGaussian(5);
                smoothImg._Erode(5);
                smoothImg._Dilate(5);
                Image<Gray, byte> BinaryImage = 
                smoothImg.ThresholdBinary(new Gray(20), new Gray(255));

                //********** Find Circles
                Image<Rgb, byte> ROIImgScaledCircles = ROIImgScaled.Convert<Rgb, byte>();
                CircleF[] circles = smoothImg.HoughCircles(
                    new Gray(180),//cannyThreshold
                    new Gray(60),//circleAccumulatorThreshold
                    2.0, //dp:Resolution of the accumulator used to detect centers of the circles
                    10.0, //min distance 
                    10, //min radius
                    128 //max radius
                    )[0]; //Get the circles from the first channel
                foreach (CircleF cir in circles)
                {
                    ROIImgScaledCircles.Draw(cir, new Rgb(235, 20, 30), 1);
                }                   
                pbxCircles.Image = ROIImgScaledCircles.ToBitmap();

Original Image:

enter image description here

Founded Circles:

enter image description here

like image 769
mjyazdani Avatar asked Jul 08 '17 15:07

mjyazdani


People also ask

How to detect circles in OpenCV?

HoughCircles function in OpenCV to detect circles in images. Unlike detecting squares or rectangles in images, detecting circles is substantially harder since we cannot reply on approximating the number of points in a contour. To help us detect circles in images, OpenCV has supplied the cv2. HoughCircles function.

How to detect circles in an image python OpenCV?

Syntax. cv2. HoughCircles(image, method, dp, minDist) Where Image is the image file converted to grey scale Method is the algorithm used to detct the circles. Dp is the inverse ratio of the accumulator resolution to the image resolution.

How to detect circles in images?

Edge detection. In order to detect the circles, or any other geometric shape, we first need to detect the edges of the objects present in the image. The edges in an image are the points for which there is a sharp change of color. For instance, the edge of a red ball on a white background is a circle.


2 Answers

Working with complete shapes, you may find it easier to work detect edges and then find contours. Here's an example:

    Image<Bgr, byte> original = new Image<Bgr, byte>(@"E:\Downloads\original.jpg");
    UMat grayscale = new UMat();            
    UMat pyrdown = new UMat();
    UMat canny = new UMat();

    double cannyThreshold = 128;

    CvInvoke.CvtColor(original, grayscale, ColorConversion.Bgr2Gray);        
    // remove noise and run edge detection
    CvInvoke.PyrDown(grayscale, pyrdown);
    CvInvoke.PyrUp(pyrdown, grayscale);
    CvInvoke.Canny(grayscale, canny, cannyThreshold, cannyThreshold * 2);

    Image<Bgr, byte> result = original.Copy();
    // find and draw circles   
    VectorOfVectorOfPoint contours = new VectorOfVectorOfPoint();
    CvInvoke.FindContours(canny, contours, null, RetrType.List, ChainApproxMethod.ChainApproxSimple);
    //CvInvoke.DrawContours(result, contours, -1, new MCvScalar(0, 0, 255));
    for (int i = 0; i < contours.Size; i++)
    {
        Ellipse ellipse = new Ellipse(CvInvoke.FitEllipse(contours[i]));
        result.Draw(ellipse, new Bgr(Color.Red), 1);
    }

    result.Save(@"E:\Downloads\circles.jpg");

Here's the result, from left to right:

  1. The original image
  2. The blurred image (using pyrdown/pyrup)
  3. Result from canny edge detection
  4. Reconstructed circles from contours

process from the original image to the result

like image 183
Wolfgang Radl Avatar answered Oct 16 '22 06:10

Wolfgang Radl


Here is a solution (based on OpenCvSharp, not on emgucv, which allows C# code to be very close to all OpenCV code that you can find in C++ or Python, but you can easily convert it back to emgucv).

I've removed the Erode and Dilate step (which in this case just destroy the original image too much).

What I used is a loop on hough circle calls (varying the inverse ratio to accumulator resolution) to ensure that I detect more than one circle, and not the circles I'm not interested in.

  int blurSize = 5;
  using (var src = new Mat("2Okrv.jpg"))
  using (var gray = src.CvtColor(ColorConversionCodes.BGR2GRAY))
  using (var blur = gray.GaussianBlur(new Size(blurSize, blurSize), 0))
  using (var dst = src.Clone())
  {
      // this hashset will automatically store all "unique" detected circles
      // circles are stored modulo some "espilon" value, set to 5 here (half of min size of hough circles below)
      var allCircles = new HashSet<CircleSegment>(new CircleEqualityComparer { Epsilon = 5 });

      // vary inverse ratio of accumulator resolution
      // depending on image, you may vary start/end/step
      for (double dp = 1; dp < 5; dp += 0.2)
      {
          // we use min dist = 1, to make sure we can detect concentric circles
          // we use standard values for other parameters (canny, ...)
          // we use your min max values (the max may be important when dp varies)
          var circles = Cv2.HoughCircles(blur, HoughMethods.Gradient, dp, 1, 100, 100, 10, 128);
          foreach (var circle in circles)
          {
              allCircles.Add(circle);
          }
      }

      // draw final list of unique circles
      foreach (var circle in allCircles)
      {
          Cv2.Circle(dst, circle.Center, (int)circle.Radius, Scalar.FromRgb(235, 20, 30), 1);
      }

      // display images
      using (new Window("src image", src))
      using (new Window("dst image", dst))
      {
          Cv2.WaitKey();
      }
  }

  public class CircleEqualityComparer : IEqualityComparer<CircleSegment>
  {
      public double Epsilon { get; set; }

      public bool Equals(CircleSegment x, CircleSegment y) => x.Center.DistanceTo(y.Center) <= Epsilon && Math.Abs(x.Radius - y.Radius) <= Epsilon;

      // bit of a hack... we return a constant so only Equals is used to compare two circles
      // since we have only few circles that's ok, we don't play with millions...
      public int GetHashCode(CircleSegment obj) => 0;
  }

Here is the result:

enter image description here

like image 38
Simon Mourier Avatar answered Oct 16 '22 05:10

Simon Mourier