title: Writing robust (color and size invariant) circle detection with OpenCV (based on Hough transform or other features)
body: <p>I wrote the following very simple python code to find circles in an image:</p>
  
  <pre><code>import cv
  import numpy as np
  
  WAITKEY_DELAY_MS = 10
  STOP_KEY = 'q'
  
  cv.NamedWindow("image - press 'q' to quit", cv.CV_WINDOW_AUTOSIZE);
  cv.NamedWindow("post-process", cv.CV_WINDOW_AUTOSIZE);
  
  key_pressed = False
  while key_pressed != STOP_KEY:
  
      # grab image
      orig = cv.LoadImage('circles3.jpg')
  
      # create tmp images
      grey_scale = cv.CreateImage(cv.GetSize(orig), 8, 1)
      processed = cv.CreateImage(cv.GetSize(orig), 8, 1)
  
  
      cv.Smooth(orig, orig, cv.CV_GAUSSIAN, 3, 3)
  
      cv.CvtColor(orig, grey_scale, cv.CV_RGB2GRAY)
  
      # do some processing on the grey scale image
      cv.Erode(grey_scale, processed, None, 10)
      cv.Dilate(processed, processed, None, 10)
      cv.Canny(processed, processed, 5, 70, 3)
      cv.Smooth(processed, processed, cv.CV_GAUSSIAN, 15, 15)
  
      storage = cv.CreateMat(orig.width, 1, cv.CV_32FC3)
  
      # these parameters need to be adjusted for every single image
      HIGH = 50
      LOW = 140
  
      try: 
          # extract circles
          cv.HoughCircles(processed, storage, cv.CV_HOUGH_GRADIENT, 2, 32.0, HIGH, LOW)
  
          for i in range(0, len(np.asarray(storage))):
              print "circle #%d" %i
              Radius = int(np.asarray(storage)[i][0][2])
              x = int(np.asarray(storage)[i][0][0])
              y = int(np.asarray(storage)[i][0][1])
              center = (x, y)
  
              # green dot on center and red circle around
              cv.Circle(orig, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
              cv.Circle(orig, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)
  
              cv.Circle(processed, center, 1, cv.CV_RGB(0, 255, 0), -1, 8, 0)
              cv.Circle(processed, center, Radius, cv.CV_RGB(255, 0, 0), 3, 8, 0)
  
      except:
          print "nothing found"
          pass
  
      # show images
      cv.ShowImage("image - press 'q' to quit", orig)
      cv.ShowImage("post-process", processed)
  
      cv_key = cv.WaitKey(WAITKEY_DELAY_MS)
      key_pressed = chr(cv_key &amp; 255)
  </code></pre>
  
  <p>As you can see from the following two examples, the 'circle finding quality' varies quite a lot:</p>
  
  <p><strong>CASE1:</strong></p>
  
  <p><img src="https://i.stack.imgur.com/5iiwQ.jpg" alt="input1">
  <img src="https://i.stack.imgur.com/FUprb.png" alt="detection1">
  <img src="https://i.stack.imgur.com/rE2LV.png" alt="post-processed1"></p>
  
  <p><strong>CASE2:</strong></p>
  
  <p><img src="https://i.stack.imgur.com/n9tzQ.jpg" alt="input2">
  <img src="https://i.stack.imgur.com/sQ73w.png" alt="detection2">
  <img src="https://i.stack.imgur.com/uh39C.png" alt="post-processed2"></p>
  
  <p>Case1 and Case2 are basically the same image, but still the algorithm detects different circles. If I present the algorithm an image with differently sized circles, the circle detection might even fail completely. This is mostly due to the <code>HIGH</code> and <code>LOW</code> parameters which need to be adjusted individually for each new picture.</p>
  
  <p><strong>Therefore my question:</strong> What are the various possibilities of making this algorithm more robust? It should be size and color invariant so that different circles with different colors and in different sizes are detected. Maybe using the Hough transform is not the best way of doing things? Are there better approaches?</p>