2
votes

I am trying to detect the circles that are black dots or have black dots in them(the ones that I pointed with arrow in the following image). enter image description here

My current approach is to use HoughCircles function in OpenCV in order to detect the circles with a radius greater than 2 pixels. My question for the community is: let's say I detect these circles(as shown bellow), how can I separate the circles that I pointed with arrows from the rest. The circles pointed with arrow are the circles of my interest, the ones that have black/dark color in them. The pink highlights are the ones that HoughCircles detected. Also, I added the arrows myself in order to show the circle of my interest.

enter image description here

Here is the python code that I've been using. Here is the link to the image in case you want to try it.

import sys
import cv2 as cv
import numpy as np
import math
filename = '72471_125_df.jpg'
src = cv.imread("72471_125_df.jpg", cv.IMREAD_COLOR)
gray = cv.cvtColor(src, cv.COLOR_BGR2GRAY)
gray = cv.medianBlur(gray, 3)
# Inverse ratio of the accumulator resolution to the image resolution. For example, if dp=1 , the accumulator has the same resolution as the input image. If dp=2 , the accumulator has half as big width and height.
accum_size = 1
# Minimum distance between the centers of the detected circles.
minDist = 30
#First method-specific parameter. In case of CV_HOUGH_GRADIENT , it is the higher threshold of the two passed to the Canny() edge detector (the lower one is twice smaller).
param1 = 50
# Second method-specific parameter. In case of CV_HOUGH_GRADIENT , it is the accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.
param2 = 5
#
minRadius = 1
# 
maxRadius = 10
circles = cv.HoughCircles(gray, cv.HOUGH_GRADIENT, accum_size, minDist,
                           param1=param1, param2=param2,
                           minRadius=minRadius, maxRadius=maxRadius)
circles = circles.reshape(1,circles.shape[1], circles.shape[2])
if circles is not None:
    circles = np.uint16(np.around(circles))
    for ind, i in enumerate(circles[0, :]):
        center = (i[0], i[1])
        radius = 15
        cv.circle(src, center, radius, (255, 0, 255), 3)

cv.imwrite("modif_"+filename,src)

Note that, I did use the configuration in which minRadius = 2 and maxRadius = 5 however it did not give me the circles with black/dark dots in them. For some reason it returns other circles as well. Also, I did try the thresholding approaches, however it was not robust under all lighting conditions. Please refer to this link in order to observe images of different lighting conditions.

1
The pink circles are drawn over the image. Why do you need to detect them? The software that drew them already knows where they are! - Cris Luengo
I first detected the pink circles with HoughCircle and then drew them, however I am interested in the circles that are pointed with the arrow. I want to detect those. I pointed the arrow to show which circle I am interested in. The ones with black dots in them. - Rouzbeh
Oh, you detected the black dots and circles, then drew the pink circles around them. Now I see. I was confused by you saying you detected the pink circles. - Cris Luengo
If you want to detect the black dots, use a dot detector, not a circle detector. Look for example at the Laplacian of Gaussian filter. - Cris Luengo
Can you elaborate how that can be useful for detecting those black circles? - Rouzbeh

1 Answers

1
votes

This is the approach I took and can be used for inspiration. I'm not sure it catches all the cases of "black dots" but you can be the judge on that. I just added a threshold to the loaded image and then reused the code you provided.

import cv2
import numpy as np

img = cv2.imread('blackdots.jpg')
gray_img = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

ret, thresh = cv2.threshold(gray_img, 170, 255, cv2.THRESH_BINARY) # <--- Try different values here

accum_size = 1
# Minimum distance between the centers of the detected circles.
minDist = 30
#First method-specific parameter. In case of CV_HOUGH_GRADIENT , it is the higher threshold of the two passed to the Canny() edge detector (the lower one is twice smaller).
param1 = 50
# Second method-specific parameter. In case of CV_HOUGH_GRADIENT , it is the accumulator threshold for the circle centers at the detection stage. The smaller it is, the more false circles may be detected. Circles, corresponding to the larger accumulator values, will be returned first.
param2 = 5
#
minRadius = 1
#
maxRadius = 10
circles = cv2.HoughCircles(thresh, cv2.HOUGH_GRADIENT, accum_size, minDist,
                           param1=param1, param2=param2,
                           minRadius=minRadius, maxRadius=maxRadius)
circles = circles.reshape(1,circles.shape[1], circles.shape[2])
if circles is not None:
    circles = np.uint16(np.around(circles))
    for ind, i in enumerate(circles[0, :]):
        center = (i[0], i[1])
        radius = 15
        cv2.circle(img, center, radius, (255, 0, 255), 3)

thresh = cv2.resize(thresh, (1280, 720)) # <---- This is just for easier display
img = cv2.resize(img, (1280, 720)) # <---- This is just for easier display
cv2.imwrite('circles_black_dot.png', img)
cv2.imwrite('threshold_black_dots.png', thresh)

Threshold image:

enter image description here

Original image with circles:

enter image description here