I'm trying to build an image analyser and I need a function that would take an image as an argument and return a list of masks representing each element. For example, given this image, I would like the function to give me 3 masks (so black for what's not visible and white for what's visible or the opposite). One for the red rectange, one for the weird green shape and one for the green rectangle. The example I gave before is just a simplification. Indeed my image could be filled by many shapes of colors I don't know.
I tried using the Pillow library but nothing I did seemed to work. As a brief overwiew, I tried spliting the image into bands and trying to create an image containing only the color I wanted. But the fact I don't know what the colors present on the image are made it impossible. Any ideas how I could do that? Thanks a lot.
Ok, here is the code to segment the image:
#!/usr/bin/env python3
from PIL import Image
import numpy as np
from skimage.measure import label
# Open image and ensure RGB, i.e. not palette or RGBA
im = Image.open('JbLxm.png').convert('RGB')
w, h = im.size
print(f'DEBUG: w={w}, h={h}')
# Make Numpy array version to simplify/accelerate processing
na = np.array(im)
# Count unique colours
# Arrange all pixels into a tall column of 3 RGB values and find unique rows (colours)
colours = np.unique(na.reshape(-1,3), axis=0)
print('DEBUG: Colours:')
print(colours)
# Iterate over unique colours in the image
for c in colours:
# Ignore white objects as that is background
if np.all(c==[255,255,255]):
print('DEBUG: Skipping white')
continue
print(f'Analysing colour: {c}')
# Make solid black canvas same size as original, then make everything this colour white
this = np.zeros((h,w), np.uint8)
this[np.all(na==c, axis=-1)] = 255
# Save for debugging
nameRoot = f'DEBUG-{c[0]}-{c[1]}-{c[2]}'
Image.fromarray(this).save(f'{nameRoot}.png')
# Label each unique object with a unique label
objects = label(this)
print(f'DEBUG: Unique objects found={np.max(objects)}')
# The first object will have greyscale value=0 in the image, the second object will have greyscale value=1
for objectIndex in range(np.max(objects)+1):
print(f'DEBUG: Object index={objectIndex}')
objectN = np.zeros((h,w), np.uint8)
# Make all objects with this label white, everything else black
objectN[objects==objectIndex] = 255
# Save this mask
Image.fromarray(objectN).save(f'{nameRoot}-object-{objectIndex}.png')
The output for your image is:
DEBUG: w=761, h=390
DEBUG: Colours:
[[ 34 177 76]
[237 28 36]
[255 255 255]]
Analysing colour: [ 34 177 76]
DEBUG: Unique objects found=2
DEBUG: Object index=0
DEBUG: Object index=1
DEBUG: Object index=2
Analysing colour: [237 28 36]
DEBUG: Unique objects found=1
DEBUG: Object index=0
DEBUG: Object index=1
DEBUG: Skipping white
And the intermediate debug images are:
DEBUG-34-177-76.png
DEBUG-237-28-36.png