Martin Perry
Martin Perry

Reputation: 9527

Detect small dots in image

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.

Upvotes: 3

Views: 6853

Answers (1)

nathancy
nathancy

Reputation: 46620

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()

Upvotes: 3

Related Questions