Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Detecting decimal points using OpenCV

Using opencv-python, I'm trying to find the location of dot characters in images similar to this one:

enter image description here

42 images set here can be seen found here: https://i.sstatic.net/4ezTX.jpg - Bulk download available

I cant create an opencv detector that can consistently find most of the dots in those type of images, whatever works on a single image (blob detector with some parameters) usually fails on other images.

Most of my tries were around using SimpleBlobDetector is it the right approach? Is opencv not the right tool for the task? (I need a ready to use tool, training a neural net is not possible at the moment)

Your help is appreciated.

like image 311
Aviran Avatar asked Sep 25 '26 16:09

Aviran


1 Answers

Instead of using SimpleBlobDetector here's a simple approach using thresholding + contour filtering:

  • Convert image to grayscale then Otsu's threshold to obtain a binary image
  • Perform morphological opening to remove small noise
  • Find contours and filter using contour area

Here's the result with some of your images. The decimal is highlighted in green

enter image description here enter image description here

enter image description here enter image description here

enter image description here enter image description here

Code

import cv2
import numpy as np

image = cv2.imread('3.jpg')
original = image.copy()
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
thresh = cv2.threshold(gray, 0, 255, cv2.THRESH_BINARY + cv2.THRESH_OTSU)[1]

kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (3,3))
opening = cv2.morphologyEx(thresh, cv2.MORPH_OPEN, kernel, iterations=2)

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)
    print(area)
    if area < 200:
        cv2.drawContours(original, [c], -1, (36,255,12), -1)

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

Note: This method will work well with the assumption that the images include only the numbers and no other artifacts. Alternative approaches include:

  • Hough Circle Transform already implemented as cv2.HoughCircles(). The downside is that the function has plenty of arguments and usually only works for "perfect" circles. Since your images have decimal dots that are not perfect circles, you may not get consistent results and may get false-positives.
  • Contour approximation using cv2.arcLength() and cv2.approxPolyDP() which uses the Ramer-Douglas-Peucker algorithm, also known as the split-and-merge algorithm. The idea is that a curve can be approximated by a series of short line segments. In order to do this, we compute the perimeter of the contour and then approximate the shape of the contour depending on the number of vertices. Take a look at this for an example.
like image 198
nathancy Avatar answered Sep 27 '26 04:09

nathancy



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!