4

I have multiple pictures, each of which has an object with its background removed. The pictures are 500x400 pixels in size.

I am looking for a way to programmatically (preferably using python) calculate the total number of pixels of the image inside the picture (inside the space without the background).

I used the PIL package in Python to get the dimensions of the image object, as follows:

print(image.size)

This command successfully produced the dimensions of the entire picture (500x400 pixels) but not the dimensions of the object of interest inside the picture.

Does anyone know how to calculate the dimensions of an object inside a picture using python? An example of a picture is embedded below.

Picture

arkadiy
  • 746
  • 1
  • 10
  • 26
  • What do you mean by *"calculate the pixels"*? Maybe you want to mask just the non-background pixels and get their mean? – Mark Setchell Oct 05 '19 at 17:31
  • @MarkSetchell I am looking for a way to calculate how many pixels the image occupies- not the mean. Do you know how that can be done? – arkadiy Oct 05 '19 at 17:39
  • 1
    "an object with its background removed" any chance to get a binary mask from the step that removed the background ? Do you have a knowledge on the color of the replacement background ? It seems to me that your question is really about background-foreground detection. – Gabriel Devillers Oct 16 '19 at 11:11

1 Answers1

3

You could floodfill the background pixels with some colour not present in the image, e.g. magenta, then count the magenta pixels and subtract that number from number of pixels in image (width x height).

Here is an example:

#!/usr/bin/env python3

from PIL import Image, ImageDraw
import numpy as np

# Open the image and ensure RGB
im = Image.open('man.png').convert('RGB')

# Make all background pixels magenta
ImageDraw.floodfill(im,xy=(0,0),value=(255,0,255),thresh=50)

# Save for checking
im.save('floodfilled.png')

# Make into Numpy array
n = np.array(im)

# Mask of magenta background pixels
bgMask =(n[:, :, 0:3] == [255,0,255]).all(2)
count = np.count_nonzero(bgMask)

# Report results
print(f"Background pixels: {count} of {im.width*im.height} total")

Sample Output

Background pixels: 148259 of 199600 total

enter image description here

Not sure how important the enclosed areas between arms and body are to you... if you just replace all greys without using the flood-filling technique, you risk making, say, the shirt magenta and counting that as background.

Mark Setchell
  • 191,897
  • 31
  • 273
  • 432
  • If the parts between the arms and the body are important, you can surely find the coordinates of a pixel inside each lake and floodfill the lakes. – Post169 Oct 16 '19 at 14:50
  • @Post169 Yes, I could do that, but what if I find a pixel that colour in the shirt or the beard? – Mark Setchell Oct 16 '19 at 14:54
  • 1
    Depending on how accurate the result needs to be, there exist various [image segmentation methods](https://scikit-image.org/docs/stable/auto_examples/index.html#segmentation-of-objects) to separate the foreground from the background of an image. After creating a segmentation mask, you can just use `np.count_nonzero` to extract the number pixels in the object as done in this answer. Simply using floodfill might already be sufficiently accurate though, since other methods are a bit more complicated to implement. – Jonathan Feenstra Oct 16 '19 at 20:01