You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何pil_to_tensor()与read_image()生成的张量存在差异?

图像转张量的差异问题

背景

我有一张JPG格式图片,用两种方式读取为PyTorch张量:

方式1:使用torchvision.io.read_image

from torchvision.io import read_image

read_image(image_path)

生成的张量:

tensor([[[255, 255, 255,  ..., 191, 191, 191],
         [255, 255, 255,  ..., 191, 191, 191],
         [255, 255, 255,  ..., 191, 191, 191],
         ...,
         [255, 255, 255,  ..., 191, 191, 191],
         [255, 255, 255,  ..., 191, 191, 191],
         [255, 255, 255,  ..., 191, 191, 191]],

        [[255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255],
         ...,
         [255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255]],

        [[255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255],
         ...,
         [255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255],
         [255, 255, 255,  ..., 255, 255, 255]],

        [[129, 143, 143,  ..., 255, 255, 255],
         [143, 255, 254,  ..., 255, 255, 255],
         [143, 254, 255,  ..., 255, 255, 255],
         ...,
         [143, 255, 255,  ..., 255, 255, 255],
         [144, 254, 255,  ..., 255, 255, 255],
         [129, 144, 143,  ..., 255, 255, 255]]], dtype=torch.uint8)

方式2:使用PIL.Image.open + pil_to_tensor

from torchvision.transforms.functional import pil_to_tensor
from PIL import Image

img = Image.open(image_path) 
pil_to_tensor(img)

生成的张量:

tensor([[[  0,   0,   0,  ...,  64,  64,  64],
         [  0,   0,   0,  ...,  64,  64,  64],
         [  0,   0,   0,  ...,  64,  64,  64],
         ...,
         [  0,   0,   0,  ...,  64,  64,  64],
         [  0,   0,   0,  ...,  64,  64,  64],
         [  0,   0,   0,  ...,  64,  64,  64]],

        [[  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0],
         ...,
         [  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0]],

        [[  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0],
         ...,
         [  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0],
         [  0,   0,   0,  ...,   0,   0,   0]],

        [[126, 112, 112,  ...,   0,   0,   0],
         [112,   0,   1,  ...,   0,   0,   0],
         [112,   1,   0,  ...,   0,   0,   0],
         ...,
         [112,   0,   0,  ...,   0,   0,   0],
         [111,   1,   0,  ...,   0,   0,   0],
         [126, 111, 112,  ...,   0,   0,   0]]], dtype=torch.uint8)

实际测试:方式1的张量能正确还原原图,方式2的不行;且从数值看,second_tensor = 255 - first_tensor(比如255-255=0,255-191=64)。


问题解答

1. 为何第二种方式会将原图反转?

本质是PIL与torchvision对带Alpha通道的图像编码逻辑不同:

  • 标准RGBA编码中,Alpha通道的0代表完全透明,255代表完全不透明,torchvision.io.read_image遵循这个规则;
  • 但PIL读取部分带Alpha的JPG(或RGBA格式图像)时,会将Alpha通道的值反转,用0表示完全不透明,255表示完全透明,也就是执行了alpha_pil = 255 - alpha_original的操作;
  • 你的图像中RGB通道和Alpha通道绑定紧密(比如是蒙版类图像),Alpha通道的反转直接导致了整体视觉上的图像反转。

2. 使用转换公式255 + second_tensor = first_tensor是否总能得到正确结果?

不能,分情况讨论:

  • 首先要纠正:从你的张量数值看,正确的转换公式应该是first_tensor = 255 - second_tensor(因为second_tensor = 255 - first_tensor),如果直接用255 + second_tensor,会因为torch.uint8是无符号8位整数出现溢出(比如255+64=319,超过255后会被截断为63,反而出错);
  • 仅当差异是**PIL反转Alpha通道(或同类反向编码)**导致时,first_tensor = 255 - second_tensor才能还原正确的张量;
  • 如果是其他原因(比如图像是CMYK格式、PIL自动转换了色彩空间、图像带颜色映射表),这个公式完全不适用。

内容的提问来源于stack exchange,提问作者gülsemin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.07 16:37:03