2
votes

I have grayscale image with dark dots that I can convert to binary (black / white) image.

Sample:

Grayscale input:

enter image description here

B&W image:

enter image description here

I need to find dots in red circles as on

enter image description here

The distance betwen dots is more-or-less uniform if there is no sharp corner.

I have a semi-working solution based on the original grayscale image and the Harris corner detector together with clustering, but it is quite slow and not so straigh-forward.

I have tried Hough transform for circles, but the dots are too small (10x10 px aprox.) to be detected correctly without too much noise.

However, I am able to quite correctly detect the line in grayscale image - see the red line in image. I already use this knowledge and filter dots based on the distance from the line.

enter image description here

However, in some cases this fail. For example the below image is quite problematic - the whick border has a "hole" and the dots are too close, connected to the thick line. I have also false positives from the numbers that are detected as dots.

enter image description here

Do you have any idea for a possible solution, ideally with OpenCV?

Note this is just a sample, the dots may not be on the thin line, but rather separate or the thin line is too bright etc. So the line cannot be used to detect dots.

1
This can takes time for computer but it may be an approach. What about checking every 10x10 pixel of every possibility in image. Then the square blackness percentage which are similar to black dot sample percentage. Then ıts probably the point. Even ıf some wrong detections exist, eliminate many wrong detections - Yunus Temurlenk

1 Answers

1
votes

A potential solution is to use morphological operations with a cv2.MORPH_ELLIPSE kernel to isolate the small dots. The idea is to obtain a binary image with Otsu's threshold then filter out large non-connecting objects using contour area filtering. From were we perform morph open to isolate the dots. Finally we find contours and isolate the dots. Here's the results:

enter image description here enter image description here

enter image description here enter image description here

Code

import cv2
import numpy as np

# Load image, grayscale, Otsu's threshold
image = cv2.imread('1.png')
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY_INV + cv2.THRESH_OTSU)[1]

# Filter out large non-connecting objects
cnts = cv2.findContours(thresh, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area < 500:
        cv2.drawContours(thresh,[c],0,0,-1)

# Morph open using elliptical shaped kernel
kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=3)

# Find circles 
cnts = cv2.findContours(opening, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if len(cnts) == 2 else cnts[1]
for c in cnts:
    area = cv2.contourArea(c)
    if area > 20 and area < 50:
        ((x, y), r) = cv2.minEnclosingCircle(c)
        cv2.circle(image, (int(x), int(y)), int(r), (36, 255, 12), 2)

cv2.imshow('thresh', thresh)
cv2.imshow('opening', opening)
cv2.imshow('image', image)
cv2.waitKey()