Search code examples
pythonpython-3.xopencvpython-imaging-library

How to extract specific region marked as black in a mask from the corresponding image in python?


I have 2 images - one is the original image and the other is a mask of the same image that contains the to be extracted region in black. I want the final image to have white background and extracted region should be of same color as the original image.

For example, these are the 2 images - original and the mask

I want the final image to contain only the colored shirt with white background.

I tried to implement using the following code but it only generates the mask as inverted color and does not includes the colored shirt image.

def extract_cloth(input, mask, output):
    if not os.path.exists(mask):
        os.makedirs(mask)

    if not os.path.exists(output):
        os.makedirs(output)

    input_image_filenames = [filename for filename in os.listdir(input) if filename.endswith('.png')]

    for input_filename in input_image_filenames:
        input_path = os.path.join(input, input_filename)
        mask_filename = os.path.splitext(input_filename)[0] + '.png'  # Change mask filename
        mask_path = os.path.join(mask, mask_filename)

        if os.path.exists(mask_path):
            original_image = cv2.imread(input_path)
            mask_image = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)

            # Invert the mask (black to white and vice versa)
            inverted_mask = cv2.bitwise_not(mask_image)

            # Extract cloth using original image and inverted mask
            extracted_cloth = cv2.bitwise_and(original_image, original_image, mask=inverted_mask)

            # Create a white background
            white_background = 255 * np.ones_like(original_image, dtype=np.uint8)
            
            # Combine extracted cloth with white background
            extracted_cloth_on_white = cv2.bitwise_or(extracted_cloth, white_background, mask=inverted_mask)

            output_filename = os.path.splitext(input_filename)[0] + '.png'
            output_path = os.path.join(output, output_filename)
            cv2.imwrite(output_path, extracted_cloth_on_white)
            print(f'Saved: {output_path}')
        else:
            print(f'Mask not found for {input_filename}')```

Solution

  • My initial search with negative operation :

    def extract_cloth(input, mask, output):
        if not os.path.exists(mask):
            os.makedirs(mask)
    
        if not os.path.exists(output):
            os.makedirs(output)
    
        input_image_filenames = [filename for filename in os.listdir(input) if filename.endswith('.png')]
        for input_filename in input_image_filenames:
            input_path = os.path.join(input, input_filename)
            mask_filename = os.path.splitext(input_filename)[0] + '.png'  # Change mask filename
            mask_path = os.path.join(mask, mask_filename)
    
            if os.path.exists(mask_path):
                original_image = cv2.imread(input_path)
                mask_image = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
    
                # Invert the mask (black to white and vice versa)
                inverted_mask = cv2.bitwise_not(mask_image)
    
                # Extract cloth using original image and inverted mask
                extracted_cloth = cv2.bitwise_not(original_image, original_image, mask=inverted_mask)
                
                # Create a white background
                white_background = 255 * np.ones_like(original_image, dtype=np.uint8)
                
                # Combine extracted cloth with white background
                extracted_cloth_on_white = cv2.bitwise_not(extracted_cloth,white_background, mask=inverted_mask)
                output_filename = os.path.splitext(input_filename)[0] + '.png'
                output_path = os.path.join(output, output_filename)
                cv2.imwrite(output_path, extracted_cloth_on_white)
                
                print(f'Saved: {output_path}')
            else:
                print(f'Mask not found for {input_filename}')
    

    My response with the code (more elegant) provided by fmw42 (+1) :

    def extract_cloth(input, mask, output):
        if not os.path.exists(mask):
            os.makedirs(mask)
    
        if not os.path.exists(output):
            os.makedirs(output)
    
        input_image_filenames = [filename for filename in os.listdir(input) if filename.endswith('.png')]
        for input_filename in input_image_filenames:
            input_path = os.path.join(input, input_filename)
            mask_filename = os.path.splitext(input_filename)[0] + '.png'  # Change mask filename
            mask_path = os.path.join(mask, mask_filename)
    
            if os.path.exists(mask_path):
            original_image = cv2.imread(input_path)
            mask_image = cv2.imread(mask_path, cv2.IMREAD_GRAYSCALE)
    
            # Invert the mask (black to white and vice versa)
            inverted_mask = cv2.bitwise_not(mask_image)
    
            # Extract cloth using original image and inverted mask
            extracted_cloth = cv2.bitwise_and(original_image, original_image, mask=inverted_mask)
          
            extracted_cloth_on_white = extracted_cloth.copy()
            extracted_cloth_on_white[mask_image==255] = (255,255,255)
            output_filename = os.path.splitext(input_filename)[0] + '.png'
            output_path = os.path.join(output, output_filename)
            cv2.imwrite(output_path, extracted_cloth_on_white)
                
                print(f'Saved: {output_path}')
            else:
                print(f'Mask not found for {input_filename}')
    

    Final image Negative cloth