Reputation: 285
When using image = image.convert("1")
on a very light grey, it'll add little black pixels to "average" it out. I'm looking for something that just looks at every individual pixel and determines whether that pixel is closer to black or to white.
Upvotes: 0
Views: 2483
Reputation: 18905
Please pay attention to the documentation on PIL.Image.convert
:
The default method of converting a greyscale (“L”) or “RGB” image into a bilevel (mode “1”) image uses Floyd-Steinberg dither to approximate the original image luminosity levels. If dither is NONE, all values larger than 128 are set to 255 (white), all other values to 0 (black). To use other thresholds, use the
point()
method.
So, you actually want no dithering and must set this option explicitly when converting:
from matplotlib import pyplot as plt
import numpy as np
from PIL import Image
# Grayscale image as NumPy array with values from [0 ... 255]
image = np.reshape(np.tile(np.arange(256, dtype=np.uint8), 256), (256, 256))
# PIL grayscale image with values from [0 ... 255]
image_pil = Image.fromarray(image, mode='L')
# PIL grayscale image converted to mode '1' without dithering
image_pil_conv = image_pil.convert('1', dither=Image.NONE)
# Threshold PIL grayscale image using point with threshold 128 (for comparison)
threshold = 128
image_pil_thr = image_pil.point(lambda p: p > threshold and 255)
# Result visualization
plt.figure(1, figsize=(9, 8))
plt.subplot(2, 2, 1), plt.imshow(image, cmap=plt.gray()), plt.ylabel('NumPy array')
plt.subplot(2, 2, 2), plt.imshow(image_pil, cmap=plt.gray()), plt.ylabel('PIL image')
plt.subplot(2, 2, 3), plt.imshow(image_pil_conv, cmap=plt.gray()), plt.ylabel('PIL image converted, no dithering')
plt.subplot(2, 2, 4), plt.imshow(image_pil_thr, cmap=plt.gray()), plt.ylabel('PIL image thresholded')
plt.tight_layout()
plt.show()
The documentation is also imprecise: Actually, all values greater than OR EQUAL 128 are set to white, both for convert
as well as for point
– which makes sense, since [0 ... 127]
are 128 values, and [128 ... 255]
are 128 values.
Hope that helps!
Upvotes: 1