3
votes

I want to draw a box around the watermark in my image. I have extracted the watermark and have found the contours. However, the contour is not drawn around the watermark. The contour is drawn across my full image. Kindly help me with the correct code.

The output of contour co-ordinates are:

[array([[[  0,   0]],

       [[  0, 634]],

       [[450, 634]],

       [[450,   0]]], dtype=int32)]

The output image is:

enter image description here

My code snippet is as follows:

img = cv2.imread('Watermark/w3.png')

gr = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
bg = gr.copy()

closing = cv2.morphologyEx(bg, cv2.MORPH_CLOSE, kernel)  #dilation followed by erosion
#plt.imshow(cv2.subtract(img,opening))
plt.imshow(closing)

_,contours, hierarchy = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(contours)
print(len(contours))

if len(contours)>0 :
    cnt=contours[len(contours)-1]
    cv2.drawContours(closing, [cnt], 0, (0,255,0), 3)
    
plt.imshow(closing)
1

1 Answers

3
votes

The function findContours is having difficulty to find your box contour because expects to run over a binary image. From the documentation:

For better accuracy, use binary images. So before finding contours, apply threshold or canny edge detection.

In OpenCV, finding contours is like finding white object from black background. So remember, object to be found should be white and background should be black.

Thus, after cvtColor function apply the threshold making sure you have a black background.

...
img = cv2.imread('sample.png')
gr = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)
_, bg = cv2.threshold(gr, 127, 255, cv2.THRESH_BINARY_INV)
...

If you run the findContours over this binary image you will find multiple boxes

enter image description here enter image description here

To get a single box around the whole text you can search for the number of iterations parameter over the morphologyEx function that creates one single blob.

...
kernel = np.ones((3,3))
closing = cv2.morphologyEx(bg, cv2.MORPH_CLOSE, kernel, iterations=5)
...

So, after creating the blob apply the findContours you already have and use the minAreaRect to find the rotated rectangle with the minimum area enclosing the set of points passed.

...
contours, hierarchy = cv2.findContours(closing, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
print(len(contours))

for i in range(len(contours)):
    rect = cv2.minAreaRect(contours[i])
    box = cv2.boxPoints(rect)
    box = np.int0(box)
    cv2.drawContours(img,[box],0,(127,60,255),2)

cv2.imwrite("output_box.png", img)

enter image description here enter image description here