使用Numpy与Pillow生成图像:像素0-255转0-1后显示差异排查
问题:Numpy+Pillow生成图像显示不一致的原因
我用Python的Numpy和Pillow库生成示例图像,操作步骤如下:
- 第一张图像:用
np.random.randint(0, 255)生成形状为(16,16,3)的三维数组(像素值范围0-255),再通过PIL.Image.fromarray()转为图像; - 第二张图像:将上述数组除以255,把像素值缩放到0-1区间,同样用
PIL.Image.fromarray()转换。
我原本预期两张图像显示效果一致,但实际绘图后差异明显,请问问题出在哪里?
附上代码:
import numpy as np import matplotlib.pyplot as plt import PIL img_array_1 = np.random.randint(low=0, high=255, size=(16, 16, 3)) img_0_255 = PIL.Image.fromarray(img_array_1, 'RGB') img_array_2 = (img_array_1 / 255) img_0_1 = PIL.Image.fromarray(img_array_2, 'RGB') plt.subplot(1, 2, 1) plt.title("像素值0-255") plt.imshow(img_0_255) plt.subplot(1, 2, 2) plt.title("像素值0-1") plt.imshow(img_0_1) plt.show()
结果图:
核心问题原因
Pillow的Image.fromarray函数对RGB模式的输入数组类型有严格要求:
当指定'RGB'模式时,输入数组必须是uint8(8位无符号整数)类型,对应像素值范围0-255。你生成的img_array_2是浮点类型(float64),传入fromarray并指定'RGB'模式时,Pillow无法正确解析这种类型的数组,导致生成的图像数据异常,最终显示效果和预期完全不同。
另外补充:np.random.randint默认生成int64类型数组,虽然Pillow能兼容处理,但显式指定dtype=np.uint8更符合图像数据规范,可避免潜在问题。
解决方法
要让两张图像显示一致,有两种可行方案:
方案1:直接用Matplotlib显示浮点数组(跳过Pillow转换)
Matplotlib的plt.imshow支持直接解析0-1范围的浮点数组,无需转成Pillow图像:
import numpy as np import matplotlib.pyplot as plt import PIL # 显式指定uint8类型,符合图像数据规范 img_array_1 = np.random.randint(low=0, high=255, size=(16, 16, 3), dtype=np.uint8) img_0_255 = PIL.Image.fromarray(img_array_1, 'RGB') # 生成0-1范围的浮点数组 img_array_2 = img_array_1 / 255.0 plt.subplot(1, 2, 1) plt.title("像素值0-255") plt.imshow(img_0_255) plt.subplot(1, 2, 2) plt.title("像素值0-1") plt.imshow(img_array_2) # 直接传递浮点数组给imshow plt.show()
方案2:将浮点数组转回uint8类型后再转Pillow
如果必须通过Pillow处理,需要先把0-1的浮点数组恢复到0-255范围,再转为uint8类型:
import numpy as np import matplotlib.pyplot as plt import PIL img_array_1 = np.random.randint(low=0, high=255, size=(16, 16, 3), dtype=np.uint8) img_0_255 = PIL.Image.fromarray(img_array_1, 'RGB') # 先转回0-255范围,再转uint8类型 img_array_2 = (img_array_1 / 255.0) * 255 img_array_2 = img_array_2.astype(np.uint8) img_0_1 = PIL.Image.fromarray(img_array_2, 'RGB') plt.subplot(1, 2, 1) plt.title("像素值0-255") plt.imshow(img_0_255) plt.subplot(1, 2, 2) plt.title("0-1转回uint8") plt.imshow(img_0_1) plt.show()
内容的提问来源于stack exchange,提问作者Saber Vatankhah
相关产品推荐
相关产品推荐

