Прозрачность превращается в оливково-зеленый - PullRequest
0 голосов
/ 14 января 2020

Этот код:

import numpy
import PIL.Image

base = PIL.Image.open('grin-emoji-by-twitter.png').convert('RGBA')
base2 = numpy.array(base)
print(base2.shape)
print(base2)

производит следующий вывод:

(512, 512, 4)        # 512 px by 512 px with RGBA channels
[[[ 71 112  76   0]  # list of all the RGBA pixels...
  [ 71 112  76   0]  # ...visible as an olive green shade when saved
  [ 71 112  76   0]
                     # ...and so on...

, который показывает пиксели верхнего левого угла: Хотя они должны быть прозрачными ( [0 0 0 0]) они вместо какого-то странного оливково-зеленого оттенка ([71 112 76 0]) (левое изображение: оригинал, правое изображение: «обработано»):

enter image description here

Ошибка странная, поскольку это «правильный» способ открывать изображения RGBA и преобразовывать их в NumPy. Использование numpy.asarray вместо этого тоже не помогло.

Исходный файл для воспроизведения - , здесь , и пока он имеет цветовую карту (изображение палитры), что может стать источником моей проблемы. Однако я использую .convert('RGBA'), который преобразует его из цветовой карты в изображение RGBA. Используемая версия PIL - 6.1.0.

Ответы [ 2 ]

0 голосов
/ 14 января 2020

Да, я неправильно понял в комментариях ...

Дело в том, что цвет RGB полностью прозрачного пикселя не имеет значения - [0 0 0 0] так же прозрачен, как [71 112 76 0] - какое-то программное обеспечение выбрало этот оттенок оливкового цвета * i sh зеленый для прозрачных пикселей для этого конкретного изображения.

Каким бы ни был просмотрщик - MatPlotLib, может быть? - вы используете для просмотра этих матриц, по-видимому, не в состоянии правильно показать альфа-канал, поэтому он решает вообще не интерпретировать его.

Если вам нужно просмотреть изображение с более ясным фоновым цветом, вы можете использовать .paste(im, mask=im), чтобы Pillow использовал альфа-канал изображения в качестве маски прозрачности.

Я использовал # FF00FF, , ласково известный как Magi c Pink , чтобы показать эффект лучше, но вы можете вместо этого белый.

import PIL.Image

background_color = (255, 0, 255)

base = PIL.Image.open('grin-emoji-by-twitter.png').convert('RGBA')

matte = PIL.Image.new('RGBA', base.size)
matte.paste(background_color, box=(0, 0) + base.size)
matte.paste(base, mask=base)
matte.save('matte.png')
0 голосов
/ 14 января 2020

В этом нет ошибки, но, возможно, неправильное понимание того, как работают различные режимы в Подушке.

Как вы выяснили, рассматриваемое изображение представляет собой изображение на поддоне. Но путем явного преобразования изображения в режим RGBA вся информация из исходной палитры и прозрачности «обрабатывается», так что при преобразовании в некоторый массив NumPy вы увидите только цвета, взятые из палитры, и извлеченный альфа-канал.

Если вы откроете изображение без какого-либо преобразования, режим P (или, возможно, PA) будет выбран автоматически, а в некотором извлеченном массиве NumPy будет только один канал. Давайте рассмотрим следующий пример:

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

plt.figure(1, figsize=(10, 9))

# Read image with Pillow, explicit RGBA mode
image_pil = Image.open('grin-emoji-by-twitter.png').convert('RGBA')
plt.subplot(2, 2, 1), plt.imshow(image_pil), plt.title('Pillow image; explicit RGBA mode')
image_np = np.array(image_pil)
plt.subplot(2, 2, 2), plt.imshow(image_np), plt.title('NumPy array')

print("Image.open(...).convert('RGBA'):")
print(image_np.shape, image_np.dtype, '\n')

# Palette of Pillow image
print("Palette:")
print(image_pil.getpalette(), '\n')

# Image info of Pillow image
print("Information:")
print(image_pil.info, '\n')

# Read image with Pillow, no mode set, P mode is taken implicitly
image_pil = Image.open('grin-emoji-by-twitter.png')
plt.subplot(2, 2, 3), plt.imshow(image_pil), plt.title('Pillow image; implicit P mode')
image_np = np.array(image_pil)
plt.subplot(2, 2, 4), plt.imshow(image_np), plt.title('NumPy array')

print("Image.open(...):")
print(image_np.shape, image_np.dtype, '\n')

# Palette of Pillow image
print("Palette:")
print(image_pil.getpalette(), '\n')

# Image info of Pillow image
print("Information:")
print(image_pil.info)

plt.tight_layout()
plt.show()

Это вывод изображения:

Output

Как видите, изображение подушки то же самое для обоих режимов, но извлеченные массивы NumPy отличаются (четыре канала RGBA по сравнению с одним каналом).

Давайте еще раз посмотрим на print выходы:

Image.open(...).convert('RGBA'):
(512, 512, 4) uint8 

Palette:
None 

Information:
{} 

Image.open(...):
(512, 512) uint8 

Palette:
[71, 112, 76, 255, 202, 78, ... ] 

Information:
{'transparency': b"\x00\x0e\x02\..."}

Мы снова видим разницу в NumPy массивах. Но вы также можете видеть, что информация о палитре и прозрачности больше не сохраняется как метаданные для явно RGBA преобразованного изображения подушки, но кодируется в сами значения пикселей, в то время как они сохраняются при загрузке в режиме P , Кроме того, вы видите, что [71, 112, 76] (оливково-зеленый) используется для всех значений 0 пикселей, которые являются фоном. (Почему этот цвет был выбран, это другой вопрос.)

Так что, в зависимости от того, чего вы хотите добиться с извлеченным массивом NumPy, используйте режим P при загрузке изображения с подушкой.

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

----------------------------------------
System information
----------------------------------------
Platform:    Windows-10-10.0.16299-SP0
Python:      3.8.1
Matplotlib:  3.2.0rc1
NumPy:       1.18.1
Pillow:      7.0.0
----------------------------------------
...