png 文件通常是使用默认调色板关联的索引值。 默认情况下,PIL 映像可以读取索引值,例如:
import tensorflow as tf
from PIL import Image
import numpy as np
path = '1.png'
image1 = Image.open(path)
print(image1.mode)
array1 = np.array(image1)
print(array1.shape)
print(set(list(array1.reshape(-1))))
结果:
P
(1024, 543)
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
索引可以转换为调色板颜色:
image2 = image1.convert('RGB')
print(image2.mode)
array2 = np.array(image2)
print(array2.shape)
print(set([tuple(x) for x in list(array2.reshape(-1, 3))]))
结果是
RGB
(1024, 543, 3)
{(0, 255, 255), (255, 255, 0), (0, 0, 255), (85, 255, 170), (170, 255, 85), (255, 0, 0), (255, 170, 0), (0, 170, 255), (0, 85, 255), (255, 85, 0), (0, 0, 170)}
问题是,默认情况下,TensorFlow 2.x API 读取调色板颜色,有没有办法读取索引值?
tensor = tf.io.read_file(path)
tensor = tf.image.decode_png(tensor, channels=3)
array3 = tensor.numpy()
print(array3.shape)
print(set([tuple(x) for x in list(array3.reshape(-1, 3))]))
(1024, 543, 3)
{(0, 255, 255), (255, 255, 0), (0, 0, 255), (85, 255, 170), (170, 255, 85), (255, 0, 0), (255, 170, 0), (0, 170, 255), (0, 85, 255), (255, 85, 0), (0, 0, 170)}
我的临时解决方案是删除与 png 文件关联的所有调色板。仍在寻找更高效的解决方案
from PIL import Image
import numpy as np
img = Image.open('1.png')
img = np.array(img)
img = Image.fromarray(img)
img.save('2.png')
理想的解决方案
一个干净的解决方案是重新实现自定义操作来解码 PNG,而无需调色板转换。
目前,TF 中decode_png
-op 的调色板转换是在核心级别完成的:
// convert palette to rgb(a) if needs be.
if (context->color_type == PNG_COLOR_TYPE_PALETTE)
png_set_palette_to_rgb(context->png_ptr);
解决方法(TF2.十(
正如您在示例代码中提到的 PIL,您可以使用tf.py_function
包装 PIL 调用以获得所需的行为,例如:
def read_png(mask):
def read_fn(p):
return np.asarray(Image.open(p.numpy().decode()))
return tf.py_function(read_fn, [mask], tf.uint8)
然后在没有自动调色板应用程序的情况下读取调色板PNG 图像,例如:
img = read_png(path)
img= img.numpy()
print(img.shape)
print(set(list(img.reshape(-1))))
示例输出
(1024, 543)
{1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11}
注意:在 TF1 中。X 这仅适用于图形模式,您必须使用tf.py_func
将 TF 包装在 PIL 函数周围(+一些小的更改(。