Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting silver and reflecting balls with OpenCV

I am trying to detect silver balls reflecting the environment with OpenCV: a silver ball

With black balls, I successfully did it by detecting circles:

gray = cv2.cvtColor(frame, cv2.COLOR_BGR2GRAY)

gray = cv2.GaussianBlur(gray,(5,5),0);
gray = cv2.medianBlur(gray,5)

gray = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_GAUSSIAN_C, cv2.THRESH_BINARY,11,3.5)

kernel = np.ones((3,3),np.uint8)

gray = cv2.erode(gray,kernel,iterations = 1)

gray = cv2.dilate(gray,kernel,iterations = 1)

circles = cv2.HoughCircles(gray, cv.CV_HOUGH_GRADIENT, 1, 260, \
                    param1=30, param2=65, minRadius=0, maxRadius=0)

But when using the program with silver balls, we don't get any result.

When looking at the edges calculated by the program, the edges of the ball are quite sharp. But the Code is not recognizing any ball.

edges of a silver ball

How do I improve the detection rate of the silver ball? I think of two ways doing that: - Improving edge calculation - Make the circle detection accept an image with unclear edges Is that possible? What is the best way of doing so?

Help is very appreciated.

like image 811
fecavy Avatar asked Jan 28 '23 09:01

fecavy


1 Answers

You have to tune your parameters. The HoughCircles function does a good job in detecting circles (even with gaps). Note that HoughCircles performs an internal binarization using canny edge detection. Thus, you don't have to do thresholding.

Given your image above, the code

import cv2
from matplotlib import pyplot as plt
import numpy as np

PATH = 'path/to/the/image.jpg'    

img = cv2.imread(PATH, cv2.IMREAD_GRAYSCALE)
plt.imshow(img, cmap='gray')
circles = cv2.HoughCircles(img, cv2.HOUGH_GRADIENT, 1, 20, param1=130, param2=30, minRadius=0, maxRadius=0)
if circles is not None:
    for x, y, r in circles[0]:
        c = plt.Circle((x, y), r, fill=False, lw=3, ec='C1')
        plt.gca().add_patch(c)
plt.gcf().set_size_inches((12, 8))
plt.show()

yields the result

What do the different parameters mean?

The function signature is defined as

cv.HoughCircles(image, method, dp, minDist[, circles[, param1[, param2[, minRadius[, maxRadius]]]]])

image and circles are self explanatory and will be skipped.

method

Specifies the variant of the hough algorithm that is used internally. As stated in the documentation, only HOUGH_GRADIENT is support atm. This method utilizes the 21HT (p.2, THE 2-1 HOUGH TRANSFORM) algorithm. The major advantage of this variant lies in the reduction of memory usage. The standard way of detecting circles using hough transform requires a search in a 3D hough space (x, y and radius). However, with 21HT your hough space is reduced to only 2 dimensions, which lowers the memory consumption by a fair amount.

dp

The dp parameter sets the inverse accumulator resolution. A good explanation can be found here. Note that this explanation uses the standard hough transform as an example. But the effect is the same for 21HT. The accumulator for 21HT is just a bit different as for the standard HT.

minDist

Simply specifies the minimum distance between the centers of circles. In the code example above it's set to 20 which means that the centers of two detected circles have to be at least 20 pixels away from each other. I'm not sure how opencv filters the circles out, but scanning the source code it looks like circles with lower matches are thrown out.

param1

Specifies the thresholds that are passed to the Canny Edge algorithm. Basically it's called like cv2.Canny(image, param1 / 2, param1).

param2

This paragraph should probably be validated by someone who is more familiar with the opencv source code. param2 specifies the accumulator threshold. This value decides how complete a circle has to be in order to count as a valid circle. I'm not sure in which unit the parameter is given, tho. But (scanning the source code again) it looks like it is an absolute vote threshold (meaning that it is directly affected by different radii). The image below shows different circles (or what can be identified as a circle). The further you go to the right, the lower the threshold has to be in order to detect that circle.

Accumulator threshold

minRadius and maxRadius

Simply limits the circle search in the range [minRadius, maxRadius] for the radius. This is useful (and can increase performance) if you can approximate (or know) the size of the circles you are searching for.

like image 171
Timo Avatar answered Jan 31 '23 08:01

Timo