Search code examples
pythonopencvimage-processingscikit-image

opencv: Creating a binary mask from the image


enter image description here

I have this picture and I want to make a binary mask from it. The main (the biggest) rectangle should be white and other parts of the picture shound be black. Like this:

enter image description here

To solve this problem I want to find a contour of main rectangle. My plan is to find all external contours. Then get the contour with the highest area. Firstly, I tried to find all contours and plot them as a binary image. My attempt:

import numpy as np 
import cv2
import matplotlib.pyplot as plt
from skimage import data, io

im = cv2.imread('train_1.jpg', 0)
contours, hierarchy = cv2.findContours(im.copy(), cv2.RETR_EXTERNAL, cv2.CHAIN_APPROX_NONE)
out = np.zeros_like(im)
cv2.drawContours(out, contours, -1, 255, 10)
io.imshow(out)
plt.show()

But even this simple code didn't find any contours. What's wrong with it? And how to get the contour with the highest area? Maybe I should apply Canny algorithm here? Please, help me.


Solution

  • You should the logic of taking the max area of rectangles as shown below. You can use this snippet to get the mask image of the area:

    import cv2
    import numpy as np
    
    image = cv2.imread("jigsaw.jpg")
    
    image = cv2.resize(image, (image.shape[1] // 4, image.shape[0] // 4))
    gray = cv2.cvtColor(image, cv2.COLOR_BGR2GRAY)
    blur = cv2.GaussianBlur(gray, (5, 5), 0)
    
    thresh = cv2.adaptiveThreshold(blur, 255, 1, 1, 11, 2)
    
    contours, hierarchy = cv2.findContours(thresh, cv2.RETR_TREE, cv2.CHAIN_APPROX_SIMPLE)
    
    max_area = 0
    best_cnt = None
    for counter in contours:
        area = cv2.contourArea(counter)
        if area > 1000:
            if area > max_area:
                max_area = area
                best_cnt = counter
    
    mask = np.zeros((gray.shape), np.uint8)
    
    cv2.drawContours(mask, [best_cnt], 0, 255, -1)
    cv2.drawContours(mask, [best_cnt], 0, 0, 2)
    
    cv2.imwrite('mask_jigsaw.jpg', mask)
    
    cv2.imshow("Image Mask", mask)
    cv2.waitKey(0)
    

    Input image: enter image description here

    Output image: enter image description here