Reputation: 381
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.
After performing greyscaling and thresholding I get following thresholded image
My Final individual character image rendered are like
But my expected images(28*28) are was like ..
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
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()
and so on ....
Upvotes: 1
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
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
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
if (w > 20 and h > 20) and (w < 130 and h < 120):
cv2.imwrite(str(i) + str(time.time()) + '{}.png'.format(i), resize)
Upvotes: 2