How to extract a white area into an image

I have a sample image like this

enter image description here

I’m looking for a way to dampen the noise from the image so that I end up with an image with black text on a white background so that I can send it to tesseract.

I tried morphing with

kernel = np.ones((4,4),np.uint8) opening = cv2.morphologyEx(img, cv2.MORPH_OPEN, kernel) cv2.imshow("opening", opening) 

but it does not seem to work.

I also tried to find outlines

 img = cv2.cvtColor(rotated, cv2.COLOR_BGR2GRAY) (cnts, _) = cv2.findContours(img, cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE) cnts = sorted(cnts, key = cv2.contourArea, reverse = True)[:1] for c in cnts: x,y,w,h = cv2.boundingRect(c) roi=rotated[y:y+h,x:x+w].copy() cv2.imwrite("roi.png", roi) 

With the above code, I get the following outlines:

enter image description here

which leads to this image when cropping:

enter image description here

which is still not good enough. I want black text on a white background so that I can send it to Tesseract OCR and have a good chance of success.

Is there anything else I can try?

Update

Here is another similar image. This is a little easier because it has a smooth rectangle.

enter image description here

+5
source share
3 answers

The following is an example of your example, although adjustments may need to be made for a wider range of images.

 import numpy as np import cv2 image_src = cv2.imread("input.png") gray = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY) ret, gray = cv2.threshold(gray, 250,255,0) image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) largest_area = sorted(contours, key=cv2.contourArea)[-1] mask = np.zeros(image_src.shape, np.uint8) cv2.drawContours(mask, [largest_area], 0, (255,255,255,255), -1) dst = cv2.bitwise_and(image_src, mask) mask = 255 - mask roi = cv2.add(dst, mask) roi_gray = cv2.cvtColor(roi, cv2.COLOR_BGR2GRAY) ret, gray = cv2.threshold(roi_gray, 250,255,0) image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) max_x = 0 max_y = 0 min_x = image_src.shape[1] min_y = image_src.shape[0] for c in contours: if 150 < cv2.contourArea(c) < 100000: x, y, w, h = cv2.boundingRect(c) min_x = min(x, min_x) min_y = min(y, min_y) max_x = max(x+w, max_x) max_y = max(y+h, max_y) roi = roi[min_y:max_y, min_x:max_x] cv2.imwrite("roi.png", roi) 

Providing you with the following types of output images:

enter image description here

A...

enter image description here

The code works by first determining the largest contour area. A mask is created from this, which is used for the first selection of only the area inside, that is, the text. Then the inverse of the mask is added to the image to convert the area outside the mask to white.

Finally, outlines are again found for this new image. Any areas of the contour outside a suitable size range are discarded (this is used to ignore any small noise areas), and a bounding box is defined for each of them. With each of these rectangles, the outer bounding box for all other paths is calculated, and these values ​​are cropped to give the final image.

Refresh . To get the rest of the image, i.e. with a remote scope, you can use the following:

 image_src = cv2.imread("input.png") gray = cv2.cvtColor(image_src, cv2.COLOR_BGR2GRAY) ret, gray = cv2.threshold(gray, 10, 255,0) image, contours, hierarchy = cv2.findContours(gray, cv2.RETR_LIST, cv2.CHAIN_APPROX_SIMPLE) largest_area = sorted(contours, key=cv2.contourArea)[-1] mask = np.zeros(image_src.shape, np.uint8) cv2.drawContours(mask, [largest_area], 0, (255,255,255,255), -1) image_remainder = cv2.bitwise_and(image_src, 255 - mask) cv2.imwrite("remainder.png", image_remainder) 
+3
source

The main idea of ​​this answer is to use a border around the text.

1) Erode is horizontal with a very large core, say 100 pixels or 8 times the size of a single expected character, something like this. This has to be done in different ways. The extreme ordinate will give the y-location of the borders around the text.

2) The process is vertical to get the x-location of the borders around the text. Then use these places to cut the image you want.

β€œOne of the advantages of this method is that you get each sentence / word , segmented separately , which, I believe, is useful for OCR.

Happy coding :)

Edited by Mark Setchell

Here is a demo 1)

enter image description here

Here is a demo 2)

enter image description here

0
source

I get this: Result

Source:

 if __name__ == '__main__': SrcImg = cv2.imread('./Yahi9.png', cv2.CV_LOAD_IMAGE_GRAYSCALE) _, BinImg = cv2.threshold(SrcImg, 80, 255, cv2.THRESH_OTSU) Contours, Hierarchy = cv2.findContours(image=copy.deepcopy(SrcImg), mode=cv2.cv.CV_RETR_EXTERNAL, method=cv2.cv.CV_CHAIN_APPROX_NONE) MaxContour, _ = getMaxContour(Contours) Canvas = np.ones(SrcImg.shape, np.uint8) cv2.drawContours(image=Canvas, contours=[MaxContour], contourIdx=0, color=(255), thickness=-1) mask = (Canvas != 255) RoiImg = copy.deepcopy(BinImg) RoiImg[mask] = 255 RoiImg = cv2.morphologyEx(src=RoiImg, op=cv2.MORPH_CLOSE, kernel=np.ones((3,3)), iterations=4) cv2.imshow('RoiImg', RoiImg) cv2.waitKey(0) 

Functions:

 def getMaxContour(contours): MaxArea = 0 Location = 0 for idx in range(0, len(contours)): Area = cv2.contourArea(contours[idx]) if Area > MaxArea: MaxArea = Area Location = idx MaxContour = np.array(contours[Location]) return MaxContour, MaxArea 

Ehh, this is python code. It only works when the white area is the maximum outline.

0
source

Source: https://habr.com/ru/post/1232930/


All Articles