1

I'm trying to recognize a license plate but got error such as wrong/not reading the character

Here's a visualization of each step:

Obtained mask from color thresholding + morph closing

color thresholding morph closing

Filter for license plate contours highlighted in green

countour

Pasted plate contours onto a blank mask

contours

The expected result from Tesseract OCR

BP 1309 GD

But the result I got is

BP 1309 6D

and I try to slices the contour to 3 slices

enter image description here

enter image description here enter image description here

and yes it's working but if I insert difference image to this method some image not recognize for example this one

enter image description here

the letter N is not recognized but if using first method it's working

enter image description here

Here's is the code

import numpy as np
import pytesseract
import cv2
import os

pytesseract.pytesseract.tesseract_cmd = r"C:\Program Files\Tesseract-OCR\tesseract.exe"
image_path = "data"

for nama_file in sorted(os.listdir(image_path)):
    print(nama_file)
    # Load image, create blank mask, convert to HSV, define thresholds, color threshold
    I = cv2.imread(os.path.join(image_path, nama_file))
    dim = (500, 120)
    I = cv2.resize(I, dim, interpolation = cv2.INTER_AREA)
    (thresh, image) = cv2.threshold(I, 127, 255, cv2.THRESH_BINARY)
    result = np.zeros(image.shape, dtype=np.uint8)
    result = 255 - result
    hsv = cv2.cvtColor(image, cv2.COLOR_BGR2HSV)
    lower = np.array([0,0,0])
    upper = np.array([179,100,130])
    mask = cv2.inRange(hsv, lower, upper)
    slices = []
    slices.append(result.copy())
    slices.append(result.copy())
    slices.append(result.copy())
    i = 0
    j = 0
    xs = []

    # Perform morph close and merge for 3-channel ROI extraction
    kernel = cv2.getStructuringElement(cv2.MORPH_RECT, (3,3))
    close = cv2.morphologyEx(mask, cv2.MORPH_CLOSE, kernel, iterations=1)
    extract = cv2.merge([close,close,close])

    # Find contours, filter using contour area, and extract using Numpy slicing
    cnts = cv2.findContours(close, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    cnts = cnts[0] if len(cnts) == 2 else cnts[1]
    boundingBoxes = [cv2.boundingRect(c) for c in cnts]
    (cnts, boundingBoxes) = zip(*sorted(zip(cnts, boundingBoxes),
    key=lambda b:b[1][0], reverse=False))
    for c in cnts:
        x,y,w,h = cv2.boundingRect(c)
        area = w * h
        ras = format(w / h, '.2f')
        if h >= 40 and h <= 70 and w >= 10 and w <= 65 and float(ras) <= 1.3:
            cv2.rectangle(I, (x, y), (x + w, y + h), (36,255,12), 3)
            result[y:y+h, x:x+w] = extract[y:y+h, x:x+w]
            # Slice
            xs.append(x)
            if i > 0:
                if (xs[i] - xs[i-1]) > 63:
                    j = j+1
            i = i + 1
            slices[j][y:y+h, x:x+w] = extract[y:y+h, x:x+w]

    # Split throw into Pytesseract
    j=0
    for s in slices:
        cv2.imshow('result', s)
        cv2.waitKey()
        if j != 1 :
            data = pytesseract.image_to_string(s, lang='eng',config='--psm 6 _char_whitelist=ABCDEFGHIJKLMNOPQRTUVWXYZ')
        else :
            data = pytesseract.image_to_string(s, lang='eng',config='--psm 6 _char_whitelist=1234567890')
        print(data)

    # Block throw into Pytesseract
    data = pytesseract.image_to_string(result, lang='eng',config='--psm 6')
    print(data)

    cv2.imshow('image', I)
    cv2.imshow('close', close)
    cv2.imshow('extract', extract)
    cv2.imshow('result', result)
    cv2.waitKey()

Maybe someone knows why this happens and what should do?

Thanks in advance

elandh ricky
  • 41
  • 1
  • 8

2 Answers2

1

I have tried many things and found some sort of solution:

Apply dilate morphological operation to make the letter thinner:

# Split throw into Pytesseract
j=0
for s in slices:
    cv2.imshow('result', s)
    cv2.waitKey(1)
    if j != 1:
        data = pytesseract.image_to_string(s, config="-c tessedit"
                                                      "_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
                                                      " --psm 6"
                                                      " ")


        if data=='':            
            s = cv2.dilate(s, cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5)))
            cv2.imshow('cv2.dilate(s)', s)
            cv2.waitKey(1)
            data = pytesseract.image_to_string(s, config="-c tessedit"
                                                         "_char_whitelist=ABCDEFGHIJKLMNOPQRSTUVWXYZ1234567890"
                                                         " --psm 6"
                                                         " ")
    else:
        pytesseract.pytesseract.tessedit_char_whitelist = '1234567890'
        data = pytesseract.image_to_string(s, lang='eng',config='--psm 6 _char_whitelist=1234567890')

    print(data)

This behavior is very weird.
There are many complains, and the suggested solutions are not working.

See the following post for example: Tesseract does not recognize single characters

At least I learned how to use _char_whitelist option (you need to add -c tessedit)...

I suppose the solution is not robust enough (probably working by chance).
I think there in no simple solution in the current version of Tesseract.

Rotem
  • 30,366
  • 4
  • 32
  • 65
0

I can decode the plate instantly by using a simple command in ubuntu shell. But in order to do that, you must upgrade tesseract from version 4 to 5.

license plate

tesseract a364k.png stdout -l eng --oem 3 --psm 7 -c tessedit_char_whitelist="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
BP 1309 GD

In your code, you can add this to config

-l eng --oem 3 --psm 7 -c tessedit_char_whitelist="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "
us2018
  • 603
  • 6
  • 11
  • Hi, @us2018 I tried the code above and the first one I using CMD is working, but the second one is still error I got BP 1309 6D – elandh ricky Apr 12 '20 at 16:30
  • I add the second like this data = pytesseract.image_to_string(result,config='-l eng --oem 3 --psm 7 -c tessedit_char_whitelist="ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789 "') – elandh ricky Apr 12 '20 at 16:39
  • I got consistent result with the CMD. I am using Ubuntu 18.04 and tesseract 5.0.0-alpha-647-g4a00. Can you post the raw image? – us2018 Apr 12 '20 at 22:26
  • yes so do I get the right result using CMD using Windows 10 and tesseract v5.0.0-alpha.20200328, but when using python it's not working, I use python Python 3.8.2, here's the [raw image](https://i.imgur.com/m2FC7mz.jpg) – elandh ricky Apr 13 '20 at 09:43
  • When I use your code and the raw image, I got the same result. There is a slight difference between the image you posted (a364k.png) and the result image. Nevertheless, the problem seems to be tesseract can not recognize image correctly if the image is tilted. So I rotated the image (using gimp) and then do OCR via CMD and it worked. I think you should try rotate the image a bit and then use tesseract. – us2018 Apr 13 '20 at 12:07
  • well the image is from the CCTV camera it can be from any angle, so I'll put it on the best angle, and the resulting image and the raw image is difference because I resize it on python in my code, thanks for the suggestion – elandh ricky Apr 14 '20 at 14:58