Подтвердить что ты не робот

HoughCircles Не правильно определяет круги в OpenCV

Я использую Visual Studio 2015, OpenCV.3 и EmguCV.3. Мой код представлен ниже, и результат показан на картинке. Я знаю, что проблема заключается в входных значениях функции HoughCircles, но я не знаю, какие входы подходят для этого изображения. Я ценю любую помощь.

                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();

Исходное изображение:

введите описание изображения здесь

Основанные круги:

введите описание изображения здесь

4b9b3361

Ответ 1

Работая с полными фигурами, вам может быть легче работать с обнаружением краев, а затем найти контуры. Вот пример:

    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");

Здесь результат слева направо:

  • Исходное изображение
  • Размытое изображение (с использованием пирда/пирупа)
  • Результат обнаружения canny edge
  • Реконструированные круги из контуров

процесс от исходного изображения до результата

Ответ 2

Вот решение (основанное на OpenCvSharp, а не на emgucv, что позволяет С# -коду очень близко ко всему коду OpenCV что вы можете найти в С++ или Python, но вы можете легко преобразовать его обратно в emgucv).

Я удалил шаг Erode и Dilate (который в этом случае слишком сильно разрушил исходное изображение).

То, что я использовал, - это цикл для вызовов houh circle (изменение обратного отношения к разрешению аккумулятора), чтобы я обнаружил более одного круга, а не круги, которые меня не интересуют.

  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 ok, we don't play with millions...
      public int GetHashCode(CircleSegment obj) => 0;
  }

Вот результат:

введите описание изображения здесь