Tensorflow Deeplab图像色彩地图去除混淆

5
在下面的代码中,我只看到一张图片被读取并重新写入。但是为什么图像像素值会发生如此巨大的变化? 显然,将PIL图像对象转换为numpy数组会导致这种情况,但不知道原因。我已经阅读了PIL图像的文档,但没有看到任何合理的解释来说明这种情况发生的原因。
import numpy as np
from PIL import Image


def _remove_colormap(filename):
  return np.array(Image.open(filename))


def _save_annotation(annotation, filename):
  pil_image = Image.fromarray(annotation.astype(dtype=np.uint8))
  pil_image.save(filename)


def main():
  raw_annotation = _remove_colormap('2007_000032.png')
  _save_annotation(raw_annotation, '2007_000032_output.png')


if __name__ == '__main__':
  main()

输入图像为,

输入图像

这是输出结果,

输出图像

注意: 输入图像中红色区域的值为[128,0,0],而在输出图像中为[1,1,1]。

代码的实际来源在这里

编辑:如@taras在他的评论中所明确的那样,

基本上,调色板是一个由256个红色值、256个绿色值和256个蓝色值组成的3 * 256值列表。您的PIL图像是一个灰度像素数组,每个像素取0..255范围内的单个值。当使用'P'模式时,像素值k被映射到颜色(调色板[k],调色板[256 + k],调色板[2*256 + k])。当使用'L'模式时,颜色就是k或(k,k,k)的RGB值。

分割图像注释为每种对象类型使用唯一的颜色。因此,我们不需要实际的颜色调色板来进行可视化,我们可以摆脱不必要的颜色调色板。


它与“P”有关(8位像素,使用调色板映射到任何其他模式)。当您编写输出图像时,此信息将丢失,您将得到灰度图像。 - taras
1
我在这里已经非常详细地解释了... https://dev59.com/nq3la4cB1Zd3GeqPMGMO#51677796 - Mark Setchell
可能是以下问题的重复:Python: Use PIL to load png file gives strange results - Alistair Carscadden
2个回答

3

快速检查打开的图像模式

Image.open(filename).mode

显示输入文件以'P'模式打开,该模式代表

8位像素,使用调色板映射到任何其他模式

因此,当您使用Image.fromarray生成图像时,调色板会被简单地丢失, 而您会得到'L'模式的灰度图像。

只需在创建输出数组时提供调色板信息即可。

可以使用Image.getpalette()提取调色板:

def _remove_colormap(filename):
    img = Image.open(filename)
    palette = img.getpalette()
    return np.array(img), palette

一旦您创建了pil_image,您可以使用Image.putpalette(palette)将调色板设置回去。

def _save_annotation(annotation, palette, filename):
    pil_image = Image.fromarray(annotation.astype(dtype=np.uint8))
    pil_image.putpalette(palette)
    pil_image.save(filename)

你的main相应地发生了变化:
def main():
    raw_annotation, palette = _remove_colormap('SqSbn.png')
    _save_annotation(raw_annotation, palette, '2007_000032_output.png')

编辑:

palette 是一个包含 3 * 256 个值的列表,其格式如下:
256 个红色值,256 个绿色值和 256 个蓝色值。

pil_image 是一个灰度像素数组,每个像素取值范围在 0 到 255 之间。在使用 'P' 模式时,像素值 k 映射为 RGB 颜色 (palette[k], palette[256 + k], palette[2*256 + k])。在使用 'L' 模式时,颜色为简单的 k 或者 (k, k, k) 的 RGB 值。


谢谢你的回答。但是我不想改变代码,我只是想知道这里的值是如何改变的。它是否遵循任何定义好的规则来转换调色板?我的意思是[128,0,0]是如何变成[1,1,1]的。 - Sumsuddin Shojib
基本上,调色板是一个由256个红色值、256个绿色值和256个蓝色值组成的3 * 256值列表。您的“pil_image”是一个灰度像素数组,每个像素取0..255范围内的单个值。当使用“'P'”模式时,像素值“k”被映射到颜色“(pallette[k],palette[256 + k],palette[2*256 + k])”。当使用“'L'”模式时,颜色简单地为“k”或RGB中的“(k,k,k)”。 - taras
我认为在P模式下,像素值k被映射到颜色(pallette[3*k], palette[3*k+1], palette[3*k+2])而不是(pallette[k], palette[256 + k], palette[2*256 + k])。 参考:https://pillow.readthedocs.io/en/5.1.x/handbook/image-file-formats.html#saving - pratsJ

1

_remove_colormap(filename) 中缺少模式转换。根据问题定义(以及@taras的答案),remove_colormap 将 PIL 图像转换为 numpy 数组。_save_annotation() 进一步将 numpy 数组转换为 PIL 图像。RGB 图像按原样保存。应使用 convert('L') 将其转换为灰度。修改后的函数定义如下:

def _remove_colormap(filename):
    img = Image.open(filename).convert('L')
    palette = img.getpalette()
    print("palette: ", type(palette))
    return np.array(img), palette

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接