赞
踩
图片和数据之间的转换,有两个要点,一个是size的transpose,一个是归一化和反归一化。
torch里数据的格式是(数量
×
\times
×通道数
×
\times
×长
×
\times
×宽),而初始图片读取得到的格式是(长
×
\times
×宽
×
\times
×通道数),因此在转变时得用 transpose
转置一下。归一化和反归一化,前者是为了把图片数据转换到神经网络友好的数值范围,后者是为了还原到人眼友好的数值范围。
主要包括图片的读取和转置操作。图片的读取有更好的方式,请参阅:
https://blog.csdn.net/weixin_42468475/article/details/127536163
from torchvision.io import image
img=image.read_image('./test2.png')
print(type(img))
print(img.shape)
import numpy as np
from PIL import Image
import torchvision
import torchvision.transforms as transforms
path = './imgs/input/img1.jpg'
image = Image.open(path).convert("RGB")
# 查看shape
print(np.array(image).shape)
# 得到 (251, 201, 3),如果要转化成神经网络可读的格式,我们要转化成 (3, 251, 201)
# ToTensor() 自带 transpose 的操作 ,很方便
transform_list = [transforms.ToTensor()]
transformer = transforms.Compose(transform_list)
print(transformer(image).shape)
# 得到 torch.Size([3, 251, 201])
当然,也可以进行手动进行转置:
import numpy as np
from PIL import Image
import torchvision
import torchvision.transforms as transforms
path = './imgs/input/img1.jpg'
image = Image.open(path).convert("RGB")
# 查看shape
data = np.array(image)
print(data.shape)
# 得到 (251, 201, 3),如果要转化成神经网络可读的格式,我们要转化成 (3, 251, 201)
# 将第三个维度放到最前面
data = data.transpose(2,0,1)
data = torch.tensor(data)
print(data.shape)
# 得到 torch.Size([3, 251, 201])
如何把 tensor 转换成 Image?:
torchvision.transforms.functional.to_pil_image(tensor)
为了神经网络更快收敛,我们需要把读取图片得到的 tensor 进行归一化,处理后的图片如果
如果不进行反归一化到 [0,1],出现了负值,就会变成下面这样,(即经过归一化后的图像,满足均值为0方差为1):
总结一下他们的关系:
读取的图片得到数值(范围大小在 [0,255] 或 [0,1] ) = = = 归 一 化 = = = 》 ===归一化===》 ===归一化===》 神经网络适合处理的数值(均值为0,方差为1) = = = 反 归 一 化 = = = 》 ===反归一化===》 ===反归一化===》 原图得到数值(范围大小在 [0,255] 或 [0,1] )
反归一化是为了还原原来人眼可以识别的图。
归一化的目的:
经过这样处理后的数据符合标准正态分布,即均值为0,标准差为1。使模型更容易收敛。并非是归于[-1,1]或是[0,1]!!!
归一化需要计算 mean 和 std,我们先来看一下他的格式,即(数量
×
\times
×通道数
×
\times
×长
×
\times
×宽):
显然有负值,那么接下来我们开始计算mean 和 std吧:
nb_samples = 0
#创建3维的空列表
channel_mean = torch.zeros(3)
channel_std = torch.zeros(3)
print(image.shape)
N, C, H, W = image.shape[:4]
image = image.view(N, C, -1) #将w,h维度的数据展平,为batch,channel,data,然后对三个维度上的数分别求和和标准差
print(image.shape)
#展平后,w,h属于第二维度,对他们求平均,sum(0)为将同一纬度的数据累加
channel_mean += image.mean(2).sum(0)
#展平后,w,h属于第二维度,对他们求标准差,sum(0)为将同一纬度的数据累加
channel_std += image.std(2).sum(0)
#获取所有batch的数据,这里为1
nb_samples += N
#获取同一batch的均值和标准差
channel_mean /= nb_samples
channel_std /= nb_samples
print(channel_mean, channel_std)
然后利用transforms.Normalize
进行转换:
# 归一化生成器
normalizer = transforms.Normalize(mean=channel_mean, std=channel_std)
# 归一化得到可处理的值
data = normalizer(image)
根据归一化计算得到的mean和std,我们可以反推出反归一化的 mean 和 std,从而利用 transforms.Normalize
进行转换,计算方法如下:
d
e
M
E
A
N
=
[
−
m
e
a
n
/
s
t
d
f
o
r
m
e
a
n
,
s
t
d
i
n
z
i
p
(
M
E
A
N
,
S
T
D
)
]
de_MEAN = [-mean/std for mean, std in zip(MEAN, STD)]
deMEAN=[−mean/stdformean,stdinzip(MEAN,STD)]
d
e
S
T
D
=
[
1
/
s
t
d
f
o
r
s
t
d
i
n
S
T
D
]
de_STD = [1/std for std in STD]
deSTD=[1/stdforstdinSTD]
MEAN是指归一化时计算出来的均值,de_MEAN是计算出来反归一化的均值,后面需要用。
完整的流程是这样的:
# 定义一个image图像,torch.Size([1, 3, 319, 256])
image = torch.rand([1,3,319,256])
# 计算原图的 mean 和std
nb_samples = 0
#创建3维的空列表
channel_mean = torch.zeros(3)
channel_std = torch.zeros(3)
print(image.shape)
N, C, H, W = image.shape[:4]
#将w,h维度的数据展平,为batch,channel,data,然后对三个维度上的数分别求和和标准差
image = image.view(N, C, -1)
print(image.shape)
#展平后,w,h属于第二维度,对他们求平均,sum(0)为将同一纬度的数据累加
channel_mean += image.mean(2).sum(0)
#展平后,w,h属于第二维度,对他们求标准差,sum(0)为将同一纬度的数据累加
channel_std += image.std(2).sum(0)
#获取所有batch的数据,这里为1
nb_samples += N
#获取同一batch的均值和标准差
channel_mean /= nb_samples
channel_std /= nb_samples
print(channel_mean, channel_std)
# 这是归一化的 mean 和std
channel_mean = torch.tensor([-0.5321, -0.8102, -0.5532])
channel_std = torch.tensor([1.2582, 1.0009, 0.9211])
# 这是反归一化的 mean 和std
MEAN = [-mean/std for mean, std in zip(channel_mean, channel_std)]
STD = [1/std for std in channel_std]
# 归一化和反归一化生成器
normalizer = transforms.Normalize(mean=channel_mean, std=channel_std)
denormalizer = transforms.Normalize(mean=MEAN, std=STD)
# 归一化得到可处理的值
data = normalizer(image)
# 反归一化得到原图
image2 = denormalizer(data)
# image ≈ image2 因为浮点数计算有误差,
# 所以不会完全一样,但是问题不大~
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。