pythonpython-imaging-librarybinary-image

Pillow - How to binarize an image with threshold?


I would like to binarize a png image. I would like to use Pillow if possible. I've seen two methods used:

image_file = Image.open("convert_image.png") # open colour image
image_file = image_file.convert('1') # convert image to black and white

This method appears to handle a region filled with a light colour by dithering the image. I don't want this behaviour. If there is, for example, a light yellow circle, I want that to become a black circle.

More generally, if a pixel's RGB is (x,y,z) the I want the pixel to become black if x<=t OR y<=t OR z<=t for some threshold 0<t<255

I can covert the image to greyscale or RGB and then manually apply a threshold test but this seems inefficient.

The second method I've seen is this:

threshold = 100
im = im2.point(lambda p: p > threshold and 255)

from here I don't know how this works though or what the threshold is or does here and what "and 255" does.

I am looking for either an explanation of how to apply method 2 or an alternative method using Pillow.


Solution

  • I think you need to convert to grayscale, apply the threshold, then convert to monochrome.

    image_file = Image.open("convert_iamge.png")
    # Grayscale
    image_file = image_file.convert('L')
    # Threshold
    image_file = image_file.point( lambda p: 255 if p > threshold else 0 )
    # To mono
    image_file = image_file.convert('1')
    

    The expression "p > threshhold and 255" is a Python trick. The definition of "a and b" is "a if a is false, otherwise b". So that will produce either "False" or "255" for each pixel, and the "False" will be evaluated as 0. My if/else does the same thing in what might be a more readable way.