Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

python opencv crop using contour hierarchy

Tags:

python

opencv

I was looking to remove the borders from the below image enter image description here

what I have tried till now is using OpenCV to get edges code:

def autocrop(image, threshold=0):
    """Crops any edges below or equal to threshold

    Crops blank image to 1x1.

    Returns cropped image.

    """
    if len(image.shape) == 3:
        flatImage = np.max(image, 2)
    else:
        flatImage = image
    assert len(flatImage.shape) == 2

    rows = np.where(np.max(flatImage, 0) > threshold)[0]
    if rows.size:
        cols = np.where(np.max(flatImage, 1) > threshold)[0]
        image = image[cols[0]: cols[-1] + 1, rows[0]: rows[-1] + 1]
    else:
        image = image[:1, :1]

    return image

no_border = autocrop(new_image)


cv2.imwrite('no_border.png',no_border)

the result is this image , next how to remove those boxes

enter image description here

Update :

I have found that the solution works for a white background but when I change the background color border are not removed

enter image description here

Edited

I have tried the solution on this image

enter image description here

But the result was like this

enter image description here

How I can achieve a complete removal of the boundary boxes .

like image 563
ahmed osama Avatar asked Jun 07 '26 17:06

ahmed osama


1 Answers

For this we use floodFill function.

import cv2
import numpy as np

if __name__ == '__main__':
    # read image and convert to gray
    img = cv2.imread('image.png',cv2.IMREAD_UNCHANGED)
    gray = cv2.cvtColor(img, cv2.COLOR_BGR2GRAY)

    # threshold the gray image to binarize, and negate it
    _,binary = cv2.threshold(gray, 150, 255, cv2.THRESH_BINARY)
    binary = cv2.bitwise_not(binary)

    # find external contours of all shapes
    _,contours,_ = cv2.findContours(binary, cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)

    # create a mask for floodfill function, see documentation
    h,w,_ = img.shape
    mask = np.zeros((h+2,w+2), np.uint8)

    # determine which contour belongs to a square or rectangle
    for cnt in contours:
        poly = cv2.approxPolyDP(cnt, 0.02*cv2.arcLength(cnt,True),True)
        if len(poly) == 4:
            # if the contour has 4 vertices then floodfill that contour with black color
            cnt = np.vstack(cnt).squeeze()
            _,binary,_,_ = cv2.floodFill(binary, mask, tuple(cnt[0]), 0)
    # convert image back to original color
    binary = cv2.bitwise_not(binary)        

    cv2.imshow('Image', binary)
    cv2.waitKey(0)
    cv2.destroyAllWindows()

result

like image 165
zindarod Avatar answered Jun 10 '26 07:06

zindarod



Donate For Us

If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!