A. 格式转换过程
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
import torch
from torchvision import transforms
img = Image.open("test.png")
# 查看shape
print(np.array(img).shape)
# 得到 (936, 1809, 4),如果要转化成神经网络可读的格式,我们要转化成(4,936,1809)
transformOper = transforms.Compose([
transforms.ToTensor()
])
img_tensor = transformOper(img)
print(img_tensor.shape) # (4,936,1809)
Tensor怎么转image?
torchvision.transforms.functional.to_pil_image(tensor)
B. 讨论
讨论a. Image对象的尺寸怎么输出?(w, h)?
1. Image对象输出图片尺寸使用size成员变量
img = Image.open("test.png")
print(img.size)
输出(1809, 936) #(w,h)
2. 没有size函数
img = Image.open("test.png")
print(img.size())
报错 TypeError: 'tuple' object is not callable
因为不可调用一个(w,h)()函数
3. Image对象没有shape函数
img = Image.open("test.png")
print(img.shape())
报错AttributeError: 'PngImageFile' object has no attribute 'shape'.
讨论b. np.array (Image)啥尺寸格式?
img = Image.open("test.png")
print(np.array(img).shape)
输出 (936, 1809, 4) # 真彩图
讨论c. array转tensor的底层实现.
from PIL import Image
import numpy as np
import matplotlib.pyplot as plt
# 用随机数模拟一张图像
image = np.random.randint(256, size=60)
image = image.reshape((5,4,3))
image_hwc = np.uint8(image)
# 展示图像
image_show = Image.fromarray(image_hwc)
plt.imshow(image_show)
plt.show()
# 打印图像像素值,[h, w, c]格式
print(image_hwc)
# 打印像素值,[c, h, w]格式
image_chw = np.transpose(image_hwc, (2,0,1))
print(image_chw)
【讨论c思考】所以数据只是一坨,不同的工具相当于是把数据按不同的方式规整起来。即,数据到整合工具之间的映射是不定的,即一张图片可能对应(c,h,w) / (w,h)/ (h,w,c)等多种规整形式。而显示出来的矩阵和对应规整形式的尺寸映射是单一的,即上图的矩阵一定对应的是(3, 5, 4)这个尺寸,上上图的矩阵一定对应的是(5,4,3)这个矩阵。
划分坨的方式:【c,h,w】1. tensor,按通道分成不同的堆,每堆中再按照高分成不同的堆(每一堆就是每一行),每堆中再按照宽分成不同的堆。【h,w,c】2. numpy,按照高分成不同的堆(每一堆就是每一行),每堆中再按照宽分成不同的堆,每堆中再按照通道分成不同的堆。尺寸组合[c,h,w]就和数据组织原理联系起来了![h,w,c]也是同理!
numpy到tensor格式转换底层实现:把numpy.array中第一大竖列拿出来bia到tensor的第一个通道各行。第二大竖列之后同理。
总结
注意1:
以后千万不要直接torch.tensor(numpy.array(Image.open('xx.png')
了。打个比方,numpy是现实世界的人(cpu上用的比较多),tensor是vr中的虚拟人物(gpu上用的比较多),人这个本体是联系两者的映射关系。transform.toTensor()可以让物理世界的人登录对应的虚拟账号,由于映射"非线性",所以扭曲后的信息格式肯定有所改变,但是信息没错。如果直接torch.tensor(),那就相当于登错号了,映射成了别的人的账号,那就出乱子了。有人说:那反正这里的映射关系是固定的,网络肯定能感知到吧?这点我暂时这么认为:你总要用别人的代码的,别人的格式是按照正确的登录方式去处理的,两段代码的数据处理对不齐,会出问题。除此以外,你用别人的权重和网络架构,自己写数据处理代码,也会出问题的,因为别人的是3,你的是5([5,4,3]的numpy直接torch.tensor了)。再除此以外,别人用你的权重,自己写数据处理代码,也会出问题,因为你的c是5,别人的是3。
参考资料:
https://zhuanlan.zhihu.com/p/644074730
https://blog.csdn.net/weixin_42468475/article/details/121869314