I have an image that contains some values in meters handwritten, I would like to find the position of the letter m so I can crop it and leave only the number.
This is an example:
Original Image: The input images are like the following, actually this one is the best handwritten input I can get, normally it's much worse.
Train Image: I have a list of many types of the m letter, cut from the different handwritten images I have.
Resulting Image: The result I want to get
I have already tried using opencv template matching functions but it didn't work, also found this github but it also uses template matching. I would like to know if there is any other way to solve this.
It seems that the letter is always at the end of the number. If this is true, you can follow a much simpler approach:
Source code for Python 2.7 and OpenCV 2.4:
import cv2
### load input image and convert it to grayscale
img = cv2.imread("input.png")
print("img shape=", img.shape)
gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
#### extract all contours
_, contours, _ = cv2.findContours(gray.copy(), cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
# debug: draw all contours
#cv2.drawContours(img, contours, -1, (0, 0, 255), 2)
#cv2.imwrite("all_contours.jpg", img)
#### create one bounding box for every contour found
bb_list = []
for c in contours:
bb = cv2.boundingRect(c)
# save all boxes except the one that has the exact dimensions of the image (x, y, width, height)
if (bb[0] == 0 and bb[1] == 0 and bb[2] == img.shape[1] and bb[3] == img.shape[0]):
continue
bb_list.append(bb)
# debug: draw boxes
#img_boxes = img.copy()
#for bb in bb_list:
# x,y,w,h = bb
# cv2.rectangle(img_boxes, (x, y), (x+w, y+h), (0, 0, 255), 2)
#cv2.imwrite("boxes.jpg", img_boxes)
#### sort bounding boxes by the X value: first item is the left-most box
bb_list.sort(key=lambda x:x[0])
# debug: draw the last box of the list (letter M)
#print("letter M @ ", bb_list[-1])
#x,y,w,h = bb_list[-1]
#cv2.rectangle(img, (x, y), (x+w, y+h), (0, 0, 255), 2)
#cv2.imwrite("last_contour.jpg", img)
### remove the last item from the list, i.e. remove box for letter M
bb_list = bb_list[:-1]
### and now the fun part: create one large bounding box to rule them all
x_start, _, _, _ = bb_list[0]
x_end, _, w_end, _ = bb_list[-1]
x = x_start
w = (x_end + w_end) - x_start
bb_list.sort(key=lambda y:y[1]) # sort by Y value: the first item has the smallest Y value
_, y, _, _ = bb_list[0]
bb_list.sort(key=lambda y:y[3]) # sort by Height value: the last item has the largest Height value
_, _, _, h = bb_list[-1]
print("x=", x, "y=", y, "w=", w, "h=", h)
# debug: draw the final region of interest
roi_img = img.copy()
cv2.rectangle(roi_img, (x, y), (x+w, y+h), (0, 0, 255), 2)
cv2.imwrite("roi.jpg", roi_img)
# crop to the roi
crop_img = img[y:y+h, x:x+w]
cv2.imwrite("crop.jpg", crop_img)
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With