OCR, Cropping the letters

Question:

I’m building a simple OCR, I’m facing a problem of not being to crop the letters after segmenting them using OpenCV. Can anyone help me with a simple way to crop the letters?

Here’s the segmenting code.

import cv2
import numpy as np


mser = cv2.MSER_create()
# original image
# -1 loads as-is so if it will be 3 or 4 channel as the original
image = cv2.imread('1.jpg', -1)
# mask defaulting to black for 3-channel and transparent for 4-channel
# (of course replace corners with yours)
mask = np.zeros(image.shape, dtype=np.uint8)

gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
vis = image.copy()

regions = mser.detectRegions(gray)
hulls = [cv2.convexHull(p.reshape(-1, 1, 2)) for p in regions[0]]

channel_count = image.shape[2]  # i.e. 3 or 4 depending on your image
ignore_mask_color = (255,)*channel_count
cv2.fillConvexPoly(mask, hulls, ignore_mask_color)
# from Masterfool: use cv2.fillConvexPoly if you know it's convex
masked_image = cv2.bitwise_and(vis, hulls)
cv2.imwrite('img')

#for m in range(len(hulls)):
    #masked_image = cv2.bitwise_and(vis, ignore_mask_color)
    # save the result
    #cv2.imwrite('img'+m, masked_image)

This results:
after segmenting letters

I need each letter to be cropped using the same hulls. Any help?

Asked By: Mahmoud S. Ahmed

||

Answers:

You can’t crop and directly save the hulls as you can see them in the example you posted. Or, better, you can crop and paste them in a square/rectangle canvas. But it’s not the answer you want for this question.

So, if you have all the text which is computer written, best option to begin is to apply cv2.findContours() to the image. There are also other specific tools you can use, but for now (and relatively to this question) use this.

import cv2
import numpy as np

#import image
image = cv2.imread('image.png')

#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('second', thresh)
cv2.waitKey(0)

#dilation
kernel = np.ones((1,1), np.uint8)
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.rectangle(image,(x,y),( x + w, y + h ),(0,255,0),2)
    #cv2.waitKey(0)

    if w > 15 and h > 15:
        cv2.imwrite('roi{}.png'.format(i), roi)

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

You can tweak the kernel for more or less wide of the rectangle detection.

res

Answered By: lucians