为何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
相关产品推荐
相关产品推荐

