Strange PIL.Image.fromarray behaviour with numpy zeros and ones in mode='1'

给你一囗甜甜゛ 提交于 2021-02-10 12:20:31

问题


There should be some kinda puzzle for me.

Accordingly to PIL documentation it has different image modes (as 1, L, 8, RGB, RGBA, and so on), but I was interested about mode '1' (1-bit pixels, black and white, stored with one pixel per byte).

I've created 2 matrices size 100 by 100: first only zeroes (np.zeros) and second only ones (np.ones), expecting totally black image with ones, and white image with zeros in mode '1' for Black and White image only.

Picture of result

Question: what I'm doing wrong?

UPD. i've tried using np.dtype uint8, didn't worked:

Final acceptable UPD: Seem there is a PIL bug, what wasn't fixed for some time, so then you should be using a workarond to create a white rectangle that way. Strange but now I'm not even sure what mode '1' is even meant for :D


回答1:


Regarding the original issue, this is the shortest version, which works for me:

Image.fromarray(255 * np.ones((100, 100), np.uint8), '1')

I get a proper all white image.

As pointed out earlier, when converting to mode "1", dithering is activated by default. So, maybe the intention of mode "1" is exactly that: Providing a fast way to create dithered images. Let's see this short example:

from matplotlib import pyplot as plt
import numpy as np
from PIL import Image

plt.figure(1, figsize=(15, 5))

# Open some image
img = Image.open('path/to/your/image.png')
plt.subplot(1, 3, 1), plt.imshow(img)

# Convert to '1'; dithering activated by default
plt.subplot(1, 3, 2), plt.imshow(img.convert('1'))

# Convert to '1'; dithering deactivated
plt.subplot(1, 3, 3), plt.imshow(img.convert('1', dither=Image.NONE))

plt.tight_layout()
plt.show()

That'd be the output:

The dithered image quite looks like a usual grayscale image when small enough. When dithering is deactivated (right image), you actually get a thresholded image, where all values >= 128 are set to white, or black otherwise.

Hope that helps!

-----------------------
System information
-----------------------
Python:      3.8.1
Matplotlib:  3.2.0rc1
NumPy:       1.18.1
Pillow:      7.0.0
-----------------------



回答2:


You need to specify the dtype when you create the arrays, else you get something like int64:

im = np.zeros((100,100), dtype=np.uint8)



回答3:


There are two problems with your second case Image.fromarray(numpy.ones((100, 100)), '1')

  1. numpy.ones(...) creates a value of one, which has only one of the 8 bits set. You need a value of 255 to set all eight bits
  2. you need to explicitly set the numpy dtype to uint8
from PIL import Image
import numpy

white_image = Image.fromarray(numpy.full(shape=(100, 100), fill_value=255, dtype=numpy.uint8), '1')

This will produce a pure white image like you want.



来源:https://stackoverflow.com/questions/59672473/strange-pil-image-fromarray-behaviour-with-numpy-zeros-and-ones-in-mode-1

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!