Search code examples
pythonopencvocrtesseractcaptcha

Unable to read image text with python tesseract and OpenCV


I am trying read text from this

this image

using Python with OpenCV. However, it is not able to read it.

import cv2 as cv
import numpy as np
from matplotlib import pyplot as plt
img=cv.imread(file_path,0)

img = cv.medianBlur(img,5)
ret,th1 = cv.threshold(img,127,255,cv.THRESH_BINARY)

th2 =cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_MEAN_C,\
    cv.THRESH_BINARY,11,2)

th3 = cv.adaptiveThreshold(img,255,cv.ADAPTIVE_THRESH_GAUSSIAN_C,\
    cv.THRESH_BINARY,11,2)

titles = ['Original Image', 'Global Thresholding (v = 127)',
    'Adaptive Mean Thresholding', 'Adaptive Gaussian Thresholding']

images = [img, th1, th2, th3]

for i in range(4):
    plt.subplot(2,2,i+1),plt.imshow(images[i],'gray')
    plt.title(titles[i])
    plt.xticks([]),plt.yticks([])

plt.show()

anyway to do this?


Solution

  • Instead of working on the grayscale image, working on saturation channel of the HSV color space makes the subsequent steps easier.

    img = cv2.imread(image_path_to_captcha)
    hsv = cv2.cvtColor(img, cv2.COLOR_BGR2HSV)
    s_component = hsv[:,:,1]
    

    s_component enter image description here

    Next, apply a Gaussian blur of appropriate kernel size and sigma value, and later threshold.

    blur = cv2.GaussianBlur(s_component,(7,7), 7)
    ret,th3 = cv2.threshold(blur,127,255,cv2.THRESH_BINARY+cv2.THRESH_OTSU)
    

    th3 enter image description here

    Next, finding contours in the image above and preserving those above a certain area threshold in the black image variable which will be used as mask later on.

    contours, hierarchy = cv2.findContours(th3, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
    black = np.zeros((img.shape[0], img.shape[1]), np.uint8)
    
    for contour in contours:
        if cv2.contourArea(contour) >600 :
            cv2.drawContours(black, [contour], 0, 255, -1)
    

    black enter image description here

    Using the black image variable as mask over the threshold image

    res = cv2.bitwise_and(th3, th3, mask = black)   
    

    res enter image description here

    Finally, applying morphological thinning to the above result

    kernel = cv2.getStructuringElement(cv2.MORPH_ELLIPSE, (5,5))
    erode = cv2.erode(res, kernel, iterations=1)
    

    erode enter image description here

    The end result is not what you expect. You can try experimenting different morphology operations prior to drawing contours as well.

    EDIT

    You can perform distance transform on the above image and use the result:

    dist = cv2.distanceTransform(res, cv2.DIST_L2, 3)
    dst = cv2.normalize(dist, dst=None, alpha=0, beta=255,norm_type=cv2.NORM_MINMAX, dtype=cv2.CV_8U)
    

    dst enter image description here