0

I'm looking to split number on image. My main problem is that the number may touch each other. so all technique with OpenCV contour found online doesn't work.

Here the steps i've done so far. It's working well with image that have number well separated, but not with number touching each other. One of the image i try to solve:

One of the image i try to solve

I'm trying to do that as part of the preprocessing step so i can after that use the number in my MNIST model.

My actual code:

import cv2
import numpy as np


# 3 - detect and extract ROI's
#image = cv2.imread('imgs/01.jpg')
#image = cv2.imread('imgs/03.jpg')
image = cv2.imread('imgs/01_tresh_210.jpg')
#cv2.imshow('i', image)
#cv2.waitKey(0)

# grayscale
gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
cv2.imshow('gray', gray)
cv2.waitKey(0)

# binary
ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
cv2.imshow('thresh', thresh)
cv2.waitKey(0)

# dilation
kernel = np.ones((10, 1), np.uint8)  # values set for this image only - need to change for different images
img_dilation = cv2.dilate(thresh, kernel, iterations=1)
cv2.imshow('dilated', img_dilation)
cv2.waitKey(0)

# find contours
im2, ctrs, hier = cv2.findContours(img_dilation.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

# sort contours
sorted_ctrs = sorted(ctrs, key=lambda ctr: cv2.boundingRect(ctr)[0])

for i, ctr in enumerate(sorted_ctrs):
    # Get bounding box
    x, y, w, h = cv2.boundingRect(ctr)

    # Getting ROI
    roi = image[y:y + h, x:x + w]

    # show ROI
    #cv2.imshow('segment no:'+str(i),roi)
    cv2.imwrite('imgs\\roi\\{}.png'.format(i), roi)
    cv2.rectangle(image, (x, y), (x + w, y + h), (0, 0, 0), 1)
    #cv2.waitKey(0)

    # save only the ROI's which contain a valid information
    if h > 20 and w > 75:
        cv2.imwrite('roi\\{}.png'.format(i), roi)

cv2.imshow('marked areas', image)
cv2.waitKey(0)

  • 1
    any assumptions that can be used? Like a known number of digits/characters? One approach could be to measure the average width of contours/numbers and if one seems to be about twice the width, it could be that it is two touching numbers that have to be split near the middle?!? – Micka Apr 11 '19 at 20:40
  • 1
    i don't know the exact number of digit. almost always between 8 and 12. it's a good suggestion i could take the average length and split too long number. Won't work everytime, but worth the try – Maxime Massé Pouliot Apr 12 '19 at 19:37
  • feel free to update/comment after trying :) – Micka Apr 12 '19 at 21:14
  • It's not working so well, sometime i can have more than 2 number who are touching each other. And even in the exemple up there, the second "2" is bigger than the first one, so when i cut it in the middle, i cut the second number in half. – Maxime Massé Pouliot Apr 18 '19 at 19:33
  • but you can detect that one contour is ptobsbly too big? Maybe you can find better heuristics to decide where exactly to split?! – Micka Apr 18 '19 at 21:09
  • 1
    I once used a code based on the first comment @Micka posted. The idea is not bad for that kind of given input but the results are awful. For example I had a ROI of two digits touching themselves (83) and the result was a cut 8 and a 3 with too much from the eight. I suggest to give a try to opencv histogram function to detect if a white image could contain one/two/three digits by searching for high black pixel values (from what I remember of my old code) – lucians Sep 28 '20 at 14:17

0 Answers0