vdvaxel
vdvaxel

Reputation: 745

Python OpenCV: remove border from image

Let's say I have an image like this:

enter image description here

For which I want to remove the border and get this:

enter image description here

So exactly the same image, without the border.

I found a "hacky" way to do it which finds the outer contour and draws a line over it... To be honest it's not the best way because I need to adjust the "thickness" of the line so that it is thick enough to cover up the border, but not too thick so it doesn't cover any of the circles.

The image variable is the image you see above (already grayscaled, thresholded).

cnts = cv2.findContours(image, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_SIMPLE)
cnts = cnts[0] if imutils.is_cv2() else cnts[1]
cv2.drawContours(image, cnts, -1, 0, 15) # 15 is the right thickness for this image, but might not be for other ones...

The results is the 2nd picture above. Works great, but it doesn't work for ALL images (because of different thickness). Is there a better way to do this?

Upvotes: 1

Views: 17676

Answers (3)

uchiha tashi
uchiha tashi

Reputation: 92

Here I am considering you had done all the image processing and others. The recommended threshold (cv2.THRESH_OTSU)!

mask = np.zeros(img.shape, dtype=img.dtype)
cont = cv2.findContours(img_th, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
cont = cont[0] if len(cont) == 2 else cont[1] 

for c in cont:
    area = cv2.contourArea(c)
    if area < 500:
        cv2.drawContours(mask, [c], -1, (255, 255, 255), -1)
print(mask.shape)
mask = cv2.cvtColor(mask, cv2.COLOR_BGR2GRAY) # making it to 2D (removing the channel value)
removed_border = cv2.bitwise_and(img, img, mask=mask) 
cv2.imshow("result", removed_border)
cv2.waitKey()
cv2.destroyAllWindows()

If you have any problem with understanding the code please let me know. I m happy to help you out and if you like the answer please thumps up!!! :)

With border

Result:

Removed border and keep original format

Upvotes: 3

Mark Setchell
Mark Setchell

Reputation: 207345

This is what I meant in the comments... fill everything that is black like the top-left corner, and connected to it, with white so that the bit you want is now entirely surrounded by white all the way to the edges. Then fill everything that is white and connected to the top-left corner with black.

#!/usr/local/bin/python3

import numpy as np
import cv2
from PIL import Image

# Load image and greyscale it
im = np.array(Image.open("framedcircles.jpg").convert('L'))

# Normalize and threshold image
im = cv2.normalize(im, None, alpha=0, beta=255, norm_type=cv2.NORM_MINMAX)
res, im = cv2.threshold(im, 64, 255, cv2.THRESH_BINARY)

# Fill everything that is the same colour (black) as top-left corner with white
cv2.floodFill(im, None, (0,0), 255)

# Fill everything that is the same colour (white) as top-left corner with black
cv2.floodFill(im, None, (0,0), 0)

# Save result
Image.fromarray(im).save("result.png")

Result:

enter image description here

Upvotes: 6

Nitin Pawar
Nitin Pawar

Reputation: 178

I have a little hack for this. If you're falling low on thickness, repeat the process. Again, it's not the best way to do it, but it should work.

Upvotes: 0

Related Questions