npn
npn

Reputation: 381

Image thresholding in OpenCV

I have following image ,which is scanned image of A4 paper.What I need to do is to render individual characters from scanned image in to 28*28 or 32*32 image. I am doing it for dataset generation for Devanagari OCR. I applied simple threshing that doesn't help me.But when I applied adaptive threshing the result is not like expected.This is my input scanned image

After performing greyscaling and thresholding I get following thresholded image threshed image

My Final individual character image rendered are likeenter image description here

But my expected images(28*28) are was like ..enter image description here

My source code is:

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

# binary
#simple threshing
#ret, thresh = cv2.threshold(gray, 127, 255, cv2.THRESH_BINARY_INV)
#cv2.imshow('threshold', thresh)
# adaptive threshing
thresh = cv2.adaptiveThreshold(gray,255,cv2.ADAPTIVE_THRESH_MEAN_C,cv2.THRESH_BINARY_INV,11,6)
cv2.imshow('threshold', thresh)

# dilation
kernel = np.ones((10, 1), np.uint8)
img_dilation = cv2.dilate(thresh, kernel, iterations=1)

# find contours
# cv2.findCountours() function changed from OpenCV3 to OpenCV4: now it have only two parameters instead of 3
cv2MajorVersion = cv2.__version__.split(".")[0]
# check for contours on thresh
if int(cv2MajorVersion) >= 4:
    ctrs, hier = cv2.findContours(img_dilation.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
else:
    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]
    roi = thresh[y:y + h, x:x + w]

    # resizing
    resize = cv2.resize(roi, (28, 28))

    if w > 15 and h > 15:
        cv2.imwrite(str(i) + str(time.time()) + '{}.png'.format(i), resize)

Please suggest me how to extract individual character in black and white 28*28 image for dataset collection.If you have any idea about dataset generation,It will be highly appriciated.

Upvotes: 1

Views: 1341

Answers (2)

lenik
lenik

Reputation: 23556

This works for me, gives nice pictures, black and white:

#!/usr/bin/env python

import cv2

counter = 0
img = cv2.imread( 'Downloads/dewangari.jpg' )
print img.shape #(2338, 1700, 3)
img = img[77:1942,91:1517]
img.shape   # (1426, 1623, 3)

_, img = cv2.threshold( img[:,:,2], 0, 255, cv2.THRESH_BINARY+cv2.THRESH_OTSU)

x_size = img.shape[0] / 15
y_size = img.shape[1] / 8

for i in range(8) :
    for j in range(15) :
        cell = img[j*x_size+7:(j+1)*x_size-7,i*y_size+7:(i+1)*y_size-7]
        cv2.imshow( 'frame', cell )

        cell = (255 - cell)   # this inverts the image

        cv2.imwrite( 'image_%03d.png' % counter, cell)
        counter += 1  # this saves the image

        cv2.waitKey(0)

cv2.destroyAllWindows()

enter image description here enter image description here enter image description here

and so on ....

Upvotes: 1

Sachin Patel
Sachin Patel

Reputation: 499

The problem is how you are finding contours.

An input parameter which requires Contour Retrieval Modes in a cv.findContours() (available options are)

cv.RETR_LIST, cv.RETR_TREE, cv.RETR_CCOMP, cv.RETR_EXTERNAL

cv.RETR_EXTERNAL only finds the outer most member in the nested contours family. More can be found here

So with your code at

if int(cv2MajorVersion) >= 4:
    ctrs, hier = cv2.findContours(img_dilation.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)

When drawing rectangles on contours shows Only parent contour in nested contours

On changing contours retrieval code using cv2.RETR_LIST

if int(cv2MajorVersion) >= 4:
    ctrs, hier = cv2.findContours(thresh.copy(), cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE)

When drawing rectangles on contours shows All contours irrespective of the hierarchy

Later on, using your logic with the restricted size of contours if w > 15 and h > 15: (on changing this dimension as needed) you can get you the images of characters

Edited

if (w > 20 and h > 20) and (w < 130 and h < 120):
   cv2.imwrite(str(i) + str(time.time()) + '{}.png'.format(i), resize)

Desired output

Upvotes: 2

Related Questions