Странное поведение PIL.Image.fromarray с numpy нулями и единицами в режиме = '1' - PullRequest
2 голосов
/ 10 января 2020

Должна быть какая-то загадка для меня.

В соответствии с документацией PIL он имеет разные режимы изображения (например, 1, L, 8, RGB, RGBA и т. Д.), Но меня интересовал режим '1' (1-битные пиксели, черно-белые , хранится с одним пикселем на байт).

Я создал 2 матрицы размером 100 на 100: первые только нули (np.zeros) и вторые только (np.ones), ожидая полностью черного изображения с единицами и белое изображение с нулями в режиме '1' только для черно-белого изображения.

Изображение результата

Вопрос: что я делаю неправильно ?

UPD. я пытался использовать np.dtype uint8, не сработало: enter image description here

Окончательно приемлемый UPD: кажется, есть ошибка PIL, которая не была исправлена ​​в течение некоторого времени, тогда вы должны использовать обходной путь, чтобы создать белый прямоугольник таким образом. Странно, но теперь я даже не уверен, для чего предназначен режим «1»: D enter image description here

Ответы [ 3 ]

1 голос
/ 10 января 2020

В вашем втором случае есть две проблемы Image.fromarray(numpy.ones((100, 100)), '1')

  1. numpy.ones(...) создает значение единицы, для которого установлен только один из 8 битов. Вам нужно значение 255, чтобы установить все восемь битов
  2. , вам нужно явно установить numpy dtype на uint8
from PIL import Image
import numpy

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

Это приведет к чисто белому изображению как хочешь.

1 голос
/ 10 января 2020

Что касается оригинального выпуска, это самая короткая версия, которая работает для меня:

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

Я получаю правильное полностью белое изображение.

Как указано ранее , при переходе в режим "1" дизеринг активирован по умолчанию. Таким образом, возможно, цель режима «1» именно в этом: обеспечить быстрый способ создания размытых изображений. Давайте посмотрим на этот короткий пример:

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()

Это будет вывод:

Output

Размытое изображение выглядит очень похоже на обычное изображение в градациях серого, когда оно достаточно маленькое. Когда дизеринг деактивирован (правое изображение), вы фактически получаете пороговое изображение, где все значения> = 128 установлены на белый или черный.

Надеюсь, это поможет!

-----------------------
System information
-----------------------
Python:      3.8.1
Matplotlib:  3.2.0rc1
NumPy:       1.18.1
Pillow:      7.0.0
-----------------------
1 голос
/ 10 января 2020

Вам нужно указать dtype при создании массивов, иначе вы получите что-то вроде int64:

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