[OpenCV] It's better to use a minimum circumscribed circle than to use Hough Circle Transform for circle detection

   2020/08/09

This is a tip I found when I tried to detect a red ball.

One of the popular methods is using Hough Circle Transform.
This method is difficult to explain, so I list some references.↓↓

However, the Hough transform is heavy, slow, and inaccurate. Besides, the size of the detected circle is not stable.

I was wondering how to deal with it, then an experienced friend told me that "it is better to use a minimum circumscribed circle".
I actually used it, and I found it was much more accurate (it doesn't mean truly accurate, though) and smooth.
it would be more accurate to say that it seems to recognize circles with good accuracy because it's actually not recognizing circles. It only detects certain colors, so the detection is fast and accurate.

I recognized a red ball displayed on my smartphone as a demo.
It seems good, isn't it?

Of course, there are cases of the Hough Circle Transform is a suitable choice, but this time I want to recognize only one red ball, so using the minimum circumscribed circle was comfortable enough.

An example code is shown below.

# -*- coding: utf-8 -*-
import numpy as np
import cv2


def getCircle(frame, lower_color, upper_color):
  MIN_RADIUS = 25

  # Convert color space of an image to HSV
  hsv = cv2.cvtColor(frame, cv2.COLOR_BGR2HSV)

  # Apply Gaussian blur to improve recognition accuracy
  blur = cv2.GaussianBlur(hsv, (9, 9), 0)

  # Extract color in specified range
  color = cv2.inRange(blur, lower_color, upper_color)

  # Noise reduction with opening and closing
  element8 = np.array([[1, 1, 1], [1, 1, 1], [1, 1, 1]], np.uint8)
  oc = cv2.morphologyEx(color, cv2.MORPH_OPEN, element8)
  oc = cv2.morphologyEx(oc, cv2.MORPH_CLOSE, element8)

  # Extract contours
  img, contours, hierarchy = cv2.findContours(oc, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
  print("{} contours.".format(len(contours)))

  if len(contours) > 0:
    # Get the most biggest red area
    contours.sort(key=cv2.contourArea, reverse=True)
    cnt = contours[0]

    # Detect a circle using a minimum circumscribed circle
    (x, y), radius = cv2.minEnclosingCircle(cnt)
    center = (int(x), int(y))
    radius = int(radius)

    # Omit a too small circle
    if radius < MIN_RADIUS:
      return None
    else:
      return center, radius
  else:
    return None


if __name__ == '__main__':
  # Start an internal camera (set 0 as an argument if only one camera is connected)
  cap = cv2.VideoCapture(0)

  while True:
    # Extract an red circle
    frame = cap.read()[1]
    getframe = getCircle(frame, np.array([130, 80, 80]), np.array([200, 255, 255]))

    if getframe is not None:
      # Draw a blue circle on a circle we found
      # getframe[0]:Center coordinates、getframe[1]:radius
      cv2.circle(frame, getframe[0], getframe[1], (255, 0, 0), 2)
      print(getframe[1])

    # Show movie with the result of detection
    cv2.imshow('Circle Detect', frame)

    if cv2.waitKey(1) & 0xFF == ord('q'):
      break

  # Release the camera
  cap.release()
  cv2.destroyAllWindows()

Everyone, let's use the minimum circumscribed circle!

タイトルとURLをコピーしました

この記事へのコメントはこちら

メールアドレスは公開されませんのでご安心ください。
また、* が付いている欄は必須項目となりますので、必ずご記入をお願いします。

内容に問題なければ、下記の「コメント送信」ボタンを押してください。

19 − eight =

This site uses Akismet to reduce spam. Learn how your comment data is processed.