3

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.

martineau
  • 119,623
  • 25
  • 170
  • 301
Neil
  • 3,020
  • 4
  • 25
  • 48

1 Answers1

13

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.

Tim Roberts
  • 48,973
  • 4
  • 21
  • 30
  • 1
    "what might be a more readable way" understatement. Never seen that "trick" 9 years of Python coding. Hope I never see it again. Thanks for the answer. – Neil Aug 28 '21 at 11:48