28

Using the Python Imaging Library PIL how can someone detect if an image has all it's pixels black or white?

~Update~

Condition: Not iterate through each pixel!

Jimmy Kane
  • 16,223
  • 11
  • 86
  • 117
  • 4
    What have you tried so far? Detecting if only one colour is used for a whole picture is not that hard. – Martijn Pieters Dec 26 '12 at 13:55
  • Just iterate over each pixel and check its value. Have you read the [handbook](http://www.pythonware.com/library/pil/handbook/index.htm)? – David Cain Dec 26 '12 at 13:56
  • @David I dont't want to do that. Yes I am not that newb man. – Jimmy Kane Dec 26 '12 at 13:57
  • @MartijnPieters I am trying with the histogram but no luck so far. – Jimmy Kane Dec 26 '12 at 13:58
  • 3
    Well, your question is very low on detail, so we have to assume the lowest common denominator. Showing what you tried and how that didn't work would help us understand what you already know and what you are trying to achieve better. – Martijn Pieters Dec 26 '12 at 14:06
  • The question includes PIL so I asked for the library's methods and general advice on how to detect if it's black or white. – Jimmy Kane Dec 26 '12 at 17:32

4 Answers4

36
if not img.getbbox():

... will test to see whether an image is completely black. (Image.getbbox() returns the falsy None if there are no non-black pixels in the image, otherwise it returns a tuple of points, which is truthy.) To test whether an image is completely white, invert it first:

if not ImageChops.invert(img).getbbox():

You can also use img.getextrema(). This will tell you the highest and lowest values within the image. To work with this most easily you should probably convert the image to grayscale mode first (otherwise the extrema might be an RGB or RGBA tuple, or a single grayscale value, or an index, and you have to deal with all those).

extrema = img.convert("L").getextrema()
if extrema == (0, 0):
    # all black
elif extrema == (1, 1):
    # all white

The latter method will likely be faster, but not so you'd notice in most applications (both will be quite fast).

A one-line version of the above technique that tests for either black or white:

if sum(img.convert("L").getextrema()) in (0, 2):
    # either all black or all white
kindall
  • 178,883
  • 35
  • 278
  • 309
  • That was exactly what I was asking about! Thank you for your time. – Jimmy Kane Dec 26 '12 at 17:22
  • Are you sure? I got extrema equal to (255, 255) for this white image http://wordpress.com/i/blank.jpg – ducu May 27 '14 at 17:53
  • And for other white images of different formats as well. I'm using Pillow though, might be the cause. – ducu May 27 '14 at 18:19
  • 2
    Yeah, one and a half years ago Pillow was under my radar. I wouldn't be surprised if they decided to represent image values as bytes rather than as floats in the range 0.0 to 1.0. Any of these techniques are easily adapted to whatever values are used, though. – kindall May 27 '14 at 19:09
14

Expanding on Kindall: if you look at an image called img with:

extrema = img.convert("L").getextrema()

It gives you a range of the values in the images. So an all black image would be (0,0) and an all white image is (255,255). So you can look at:

if extrema[0] == extrema[1]:
    return("This image is one solid color, so I won't use it")
else:
    # do something with the image img
    pass

Useful to me when I was creating a thumbnail from some data and wanted to make sure it was reading correctly.

Thane Brimhall
  • 9,256
  • 7
  • 36
  • 50
Jeremy S.
  • 1,086
  • 8
  • 18
11
from PIL import Image
img = Image.open("test.png")
clrs = img.getcolors()

clrs contains [("num of occurences","color"),...]

By checking for len(clrs) == 1 you can verify if the image contains only one color and by looking at the second element of the first tuple in clrs you can infer the color.

In case the image contains multiple colors, then by taking the number of occurences into account you can also handle almost-completly-single-colored images if 99% of the pixles share the same color.

Raffael
  • 19,547
  • 15
  • 82
  • 160
2

I tried the Kindall solution ImageChops.invert(img).getbbox() without success, my test images failed.

I had noticed a problem, white should be 255 BUT I have found white images where numeric extrema are (0,0).. why? See the update below.

I have changed Kindall second solution (getextrema), that works right, in a way that doesn't need image conversion, I wrote a function and verified that works with Grayscale and RGB images both:

def is_monochromatic_image(img):
    extr = img.getextrema()
    a = 0
    for i in extr:
        if isinstance(i, tuple):
            a += abs(i[0] - i[1])
        else:
            a = abs(extr[0] - extr[1])
            break
    return a == 0

The img argument is a PIL Image object. You can also check, with small modifications, if images are black or white.. but you have to decide if "white" is 0 or 255, perhaps you have the definitive answer, I have not. :-) Hope useful

UPDATE: I suppose that white images with zeros inside.. may be PNG or other image format with transparency.

Fabiano Tarlao
  • 3,024
  • 33
  • 40