如何使用 TensorFlow 2.x API 解码 PNG,而无需使用 png 文件中包含的调色板



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 函数周围(+一些小的更改(。

最新更新