1

I have a black and white drawing that was drawn online, so the pixels are only solid black or solid white. The drawing is a png, which I am analyzing in python.

im = Image.open(os.path.join(dir))
im = img_as_float(im)
plt.imshow(im)

Does anyone have advice on how to count the number of black pixels in a png?

jtlz2
  • 7,700
  • 9
  • 64
  • 114
psychcoder
  • 543
  • 3
  • 14
  • 1
    Does this answer your question? [count number of black pixels in an image in Python with OpenCV](https://stackoverflow.com/questions/32590932/count-number-of-black-pixels-in-an-image-in-python-with-opencv) – Chris Apr 02 '20 at 01:02
  • You can access the individual pixels of a PIL `Image` object using its [`getdata()`](https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getdata) or much slower [`getpixel()`](https://pillow.readthedocs.io/en/latest/reference/Image.html#PIL.Image.Image.getpixel) methods. Here's [sample code](https://stackoverflow.com/a/40729543/355230) of using the latter on a black & white image (a color image would be very similar). – martineau Apr 02 '20 at 01:10

4 Answers4

0

Simple script to count black pixels:

def countBlack (image):
    blacks = 0
    for color in image.flatten():
        if color < 0.0001:
            blacks += 1
    return blacks
Thiago Romano
  • 577
  • 5
  • 14
  • Thank you! I'm getting the error `''numpy.ndarray' object has no attribute 'getdata'` when I try this. Do you have advice? – psychcoder Apr 02 '20 at 19:42
  • Awesome, thanks!! I'm new at coding, so do you mind explaining your code? For example, I am now trying to count white pixels (to calculate the proportion of white to black). I changed color to `color > 0.0001` thinking that that's how I'd count white pixels, but the output is less than the original count for black. The png contains more white than black pixels, so I'm confused. – psychcoder Apr 02 '20 at 20:24
0

Assuming all pixels are either black or white, this should work:

len([px for px in list(im.getdata()) if px[1] < 0.01])

Amit Aviv
  • 1,816
  • 11
  • 10
  • I also receive this error `'numpy.ndarray' object has no attribute 'getdata'`. But thanks as well! – psychcoder Apr 02 '20 at 19:43
  • My code assumes `im` is an `Image` and not `ndarray`. So you should use it before the `im = img_as_float(im)`. You can add the code for `img_as_float` and we can adapt the answer – Amit Aviv Apr 02 '20 at 19:46
  • Is this what you mean? I think this returns the total pixels. `for i,im in enumerate(sketch_paths): im = Image.open(os.path.join(sketch_dir,f)) count = len([px for px in list(im.getdata()) if px[1] < 0.01]) im = img_as_float(im) plt.imshow(im) print(count)` I calculated the total pixels with `im.shape[0] * im.shape[1]` (Ack, so sorry, I'm new and don't know how to properly format my code in this comment!) – psychcoder Apr 02 '20 at 20:29
0

Since it's now a numpy array, use a mask and sum:

nblack = im[np.where(im==0)].sum()
print(nblack)

This assumes - as per your question - solid black. Any other threshold is arbitrary.

jtlz2
  • 7,700
  • 9
  • 64
  • 114
0

If you are opening an image with PIL and expecting a pure, single-channel greyscale image (rather than a colour one or a palettised one) you should ensure that is what you get with:

# Open image and ensure single channel greyscale image
im = Image.open(...).convert('L') 

Explanation here.

You can then convert to a Numpy array with:

na = np.array(im)

Now, Numpy will count the white pixels for you:

white = np.count_nonzero(im)

And the black pixels:

black = np.count_nonzero(im==0)

Alternatively, you can subtract the number of white pixels from the total number of pixels:

black = im.size - white
Mark Setchell
  • 191,897
  • 31
  • 273
  • 432