Peter
Peter

Reputation: 337

Fill empty enclosed parts from image

Before

After

I'm looking for an algorithm that would produce the result I'm showing above. I tried so far some dilatation and erosion from PIL but the results are not the ones I'm looking for because I'm losing some essential details of the letters. Furthermore, they tend to be very bold afterwards, and erosion doesn't help. My second try was some type of flood algorithm, but I can't think of anything useful, as some letters have gaps, and I don't know how to deal with this. I would highly appreciate if you could guide me towards some idea of algorithm in order to solve this problem.

Upvotes: 1

Views: 990

Answers (1)

Ha Bom
Ha Bom

Reputation: 2917

As Mark Setchell mentioned above, you can use cv2.findContours and then use hierarchy to find letters' holes.

First I find all contours in the image.

To find holes of the letters, I used hierarchy to get the contours with no child (most inner contour) and then fill it with white in a black (called mask image). I also apply a threshold of area to get rid of small black dots inside the letters and keep the holes only. The threshold is area>int(w*h/200) with w, h are the length and width of the image.

I fill the contours in gray image with black. Then I just add the gray image and the mask image) to get the final result.

Here is the code.

import cv2
import numpy as np

img = cv2.imread("1.png")

print(img.shape)
w = img.shape[0]
h = img.shape[1]

gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_,thresh = cv2.threshold(gray,128,255,cv2.THRESH_BINARY_INV)

im2, contours, hierarchy = cv2.findContours(thresh,cv2.RETR_TREE,cv2.CHAIN_APPROX_SIMPLE)
cv2.drawContours(img, contours,-1,(0,0,255),1)

mask = np.zeros(gray.shape, dtype="uint8")

for i in range(len(contours)):
    area = cv2.contourArea(contours[i])
    print(hierarchy[0][i][2])
    if(hierarchy[0][i][2]==-1 and area>int(w*h/200)): #contour has no child
        cv2.fillPoly(mask, pts =[contours[i]], color=255)
    cv2.fillPoly(gray, pts =[contours[i]], color=0)

res = mask + gray

cv2.imshow("img", img)    
cv2.imshow("gray", gray)      
cv2.imshow("mask", mask)
cv2.imshow("res", res)

cv2.waitKey()
cv2.destroyAllWindows() 

enter image description here

Upvotes: 3

Related Questions