无法从 PIL 保存的 PNG 图像中恢复相同的 numpy 数组

Can't recover the same numpy array from PIL-saved PNG image

我正在使用 PIL 将 Numpy 数组保存为 PNG 图像,但是当我读回它时,我没有得到相同的数组编号。

我保存了一张 PNG 图像,其中一个像素的值为 2^16,但是当我将其读回 Numpy 数组时,该像素的值为 2^16 - 1。

似乎位深度范围被限制为 2^16 -1 位,但文档说保存为 PNG,我可以使用 'I' 模式,它适用于 32 位有符号整数。

From the Pillow docs:

The mode of an image is a string which defines the type and depth of a pixel in the image. Each pixel uses the full range of the bit depth. So a 1-bit pixel has a range of 0-1, an 8-bit pixel has a range of 0-255 and so on. The current release supports the following standard modes:

I (32-bit signed integer pixels)

From the Pillow PNG docs:

Pillow identifies, reads, and writes PNG files containing 1, L, LA, I, P, RGB or RGBA data.

可重现的例子:

import tempfile
from PIL import Image
import numpy as np


im_np = np.array([[1, 1], [1, 2**16]], dtype=np.int32)
im_pil = Image.fromarray(im_np, mode='I')

with tempfile.TemporaryFile() as f:
    im_pil.save(f, 'PNG')
    
    with Image.open(f) as im:
        recovered_im_np = np.array(im)
        
        print(f"Numpy array:\n{im_np}")
        print(f"Numpy array receovered from PNG:\n {recovered_im_np}")

我明白了:

Numpy array:
[[    1     1]
 [    1 65536]]
Numpy array receovered from PNG:
 [[    1     1]
 [    1 65535]]

Python版本:3.9.10 (main, Feb 17 2022, 18:15:00) \n[GCC 9.3.0]

PIL 版本:9.0.1

Numpy 版本:1.22.2

Pillow 可能支持 32 位有符号整数图像,但 png 不支持。 png 格式支持的每个像素的最大颜色深度为 16 位。我不确定它们在什么意义上意味着支持保存 I 模式图像。

您始终可以直接使用 numpy.save 保存 numpy 数组。

正如@mateusreis 正确指出的那样,.png 格式仅支持每像素 16 位灰度,因此您必须将该值转换为每像素 3x8 24 位 RGB 值,或者您应该保存采用支持每像素 32 位的图像格式,如 TIFF:

import tempfile
from PIL import Image
import numpy as np

im_np = np.array([[1, 1], [1, 2 ** 16]], dtype=np.int32)
im_pil = Image.fromarray(im_np, mode='I')

with tempfile.TemporaryFile() as f:
    im_pil.save(f, 'TIFF')

    with Image.open(f) as im:
        recovered_im_np = np.array(im)

        print(f"Numpy array:\n{im_np}")
        print(f"Numpy array receovered from PNG:\n {recovered_im_np}")

结果:

Numpy array:
[[    1     1]
 [    1 65536]]
Numpy array receovered from PNG:
 [[    1     1]
 [    1 65536]]

这里的关键是要意识到你进行了 2 次转换(双向):

  • 1.) numpy 数组 -> 2.) PIL 图片 -> 3.) 图片文件格式

您的 mode='I' 涵盖 1 -> 2,但您需要选择正确的格式以保留 2 -> 3 的数据。