HoughCircles circle detection using opencv and python-
I am trying to use OpenCV's (Hough) Circle definition to detect circles. I created a solid circle on a black background, tried to play with the options, used blur and that's it, but I just can't find anything.
Any ideas, suggestions, etc. would be great, thanks!
my current code looks something like this:
import cv2 import numpy as np """ params = dict(dp=1, minDist=1, circles=None, param1=300, param2=290, minRadius=1, maxRadius=100) """ img = np.ones((200,250,3), dtype=np.uint8) for i in range(50, 80, 1): for j in range(40, 70, 1): =200 (120,120), 20, (100,200,80), -1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) canny = cv2.Canny(gray, 200, 300) canny) gray = cv2.medianBlur(gray, 5) circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, 1, 20, param1=100, param2=30, minRadius=0, maxRadius=0) print circles circles = np.uint16(np.around(circles)) for i in circles[0,:]: cv2.circle(img,(i,i),i,(0,255,0),2) cv2.circle(img,(i,i),2,(0,0,255),3) img) k = cv2.waitKey(0) if k == 27: cv2.destroyAllWindows()
source to share
Your code is working fine. The problem is with your thresholds
Try to understand the options you are using from the OpenCV docs :
param1 - The first parameter, specific to the method. In the case of CV_HOUGH_GRADIENT, this is the higher threshold of the two that passed to the edge of the Canny () detector (the lower one is half as much).
param2 - The second parameter is specific to the method. In the case of CV_HOUGH_GRADIENT, this is the accumulator threshold for the circle of centers in the detection phase. The smaller it is, the more false circles can be detected. The circles corresponding to the larger accumulator value will be returned first.
So, as you can see, the inner HoughCircles function calls the Canny edge detector, which means that you can use the grayscale in the function instead of your outlines.
to 30 and
15 and see the results in the following code:
import cv2 import numpy as np img = np.ones((200,250,3), dtype=np.uint8) for i in range(50, 80, 1): for j in range(40, 70, 1): =200 (120,120), 20, (100,200,80), -1) gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY) circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, 1, 20, param1=30, param2=15, minRadius=0, maxRadius=0) print circles circles = np.uint16(np.around(circles)) for i in circles[0,:]: cv2.circle(img,(i,i),i,(0,255,0),2) cv2.circle(img,(i,i),2,(0,0,255),3) img) k = cv2.waitKey(0) if k == 27: cv2.destroyAllWindows()
source to share
If you don't get HoughCircles to bring you pixel perfect solutions for visible circles, you are not using them correctly.
Your mistake is that you are trying to manually tweak your hyperparameters yourself. It won't work. Ask the computer to automatically adjust the settings for you:
import numpy as np import argparse import cv2 import signal from functools import wraps import errno import os import copy ap = argparse.ArgumentParser() ap.add_argument("-i", "--image", required = True, help = "Path to the image") args = vars(ap.parse_args()) image = cv2.imread(args["image"]) orig_image = np.copy(image) output = image.copy() gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY) cv2.imshow("gray", gray) cv2.waitKey(0) circles = None minimum_circle_size = 100 #this is the range of possible circle in pixels you want to find maximum_circle_size = 150 #maximum possible circle size you're willing to find in pixels guess_dp = 1.0 number_of_circles_expected = 1 #we expect to find just one circle breakout = False max_guess_accumulator_array_threshold = 100 #minimum of 1, no maximum, (max 300?) the quantity of votes #needed to qualify for a circle to be found. circleLog =  guess_accumulator_array_threshold = max_guess_accumulator_array_threshold while guess_accumulator_array_threshold > 1 and breakout == False: #start out with smallest resolution possible, to find the most precise circle, then creep bigger if none found guess_dp = 1.0 print("resetting guess_dp:" + str(guess_dp)) while guess_dp < 9 and breakout == False: guess_radius = maximum_circle_size print("setting guess_radius: " + str(guess_radius)) print(circles is None) while True: #HoughCircles algorithm isn't strong enough to stand on its own if you don't #know EXACTLY what radius the circle in the image is, (accurate to within 3 pixels) #If you don't know radius, you need lots of guess and check and lots of post-processing #verification. Luckily HoughCircles is pretty quick so we can brute force. print("guessing radius: " + str(guess_radius) + " and dp: " + str(guess_dp) + " vote threshold: " + str(guess_accumulator_array_threshold)) circles = cv2.HoughCircles(gray, cv2.cv.CV_HOUGH_GRADIENT, dp=guess_dp, #resolution of accumulator array. minDist=100, #number of pixels center of circles should be from each other, hardcode param1=50, param2=guess_accumulator_array_threshold, minRadius=(guess_radius-3), #HoughCircles will look for circles at minimum this size maxRadius=(guess_radius+3) #HoughCircles will look for circles at maximum this size ) if circles is not None: if len(circles) == number_of_circles_expected: print("len of circles: " + str(len(circles))) circleLog.append(copy.copy(circles)) print("k1") break circles = None guess_radius -= 5 if guess_radius < 40: break; guess_dp += 1.5 guess_accumulator_array_threshold -= 2 #Return the circleLog with the highest accumulator threshold # ensure at least some circles were found for cir in circleLog: # convert the (x, y) coordinates and radius of the circles to integers output = np.copy(orig_image) if (len(cir) > 1): print("FAIL before") exit() print(cir[0, :]) cir = np.round(cir[0, :]).astype("int") for (x, y, r) in cir: cv2.circle(output, (x, y), r, (0, 0, 255), 2) cv2.rectangle(output, (x - 5, y - 5), (x + 5, y + 5), (0, 128, 255), -1) cv2.imshow("output", np.hstack([orig_image, output])) cv2.waitKey(0)
For more information on what this does see https://stackoverflow.com/a/46500223/445131
source to share