pytorch transform/tensor 基本操作

2018-08-24  本文已影响0人  conson_wm

pytorch官方文档
transform源码解读
莫烦pytorch

1 .transform

  torchvision.transforms是pytorch中的图像预处理包
  有很多图像预处理方法, 今天从图像维度出发, 讲一些我们经常会用到的

1.1 ToTensor & ToPILImage

  从Numpy到Tensor的转换有两种方法, 可以用torch.from_numpy(ndarray), 也可以用ToTensor()(ndarray), 这两种有什么区别呢?

np_data = np.random.random((260, 194, 3))
# np_data size (height, width, channel)
torch_data = torch.from_numpy(np_data)  # numpy -> tensor 1
# torch_data size [260, 194, 3]
torch2array = torch_data.numpy()
# torch2array size[260, 194, 3]
tensor_data = ToTensor()(np_data)    # numpy -> tensor 2
#tensor_data size[3, 260, 194]
tensor2array = tensor_data.numpy()
#tensor2array size[3, 260, 194]

  可以看出, 如果用torch.from_numpy()的方法, 转换的tensor和ndarray是相同的shape, (height, width, channel)的shape进, 仍然变成(height, width, channel)的shape
  但是, 如果是用ToTensor()的方式, 那就是 (height, width, channel)的shape进, (channel, height, width)的shape出
  不同于numpy->tensor有两种做法, 从tensor->numpy却只有一种, 就是tensor.numpy(), 而这种做法的shape前后也是不会变化的, 所以我们看到如果按照ToTensor() -> tensor.numpy()的方式将np转成tensor再转为np, 那shape和一开始的np是不同的, 就是(height, width, channel)会变成(channel, height, width)

  下面我们举一个实际的读图转换的例子

# PIL -> np -> tensor -> PIL
PIL_img = Image.open('test_pic.jpeg')
#PIL_img size [194, 260, 3], range [0,255]
np_img = np.asarray(PIL_img)
# np_img size [260, 194, 3], range [0,255]
tensor_from_np = ToTensor()(np_img)
# tensor_img size [3, 260, 194], range [0,1]
tensor_from_PIL = ToTensor()(PIL_img)
# tensor_img size [3, 260, 194], range [0,1]
PIL_from_tensor = ToPILImage()(tensor_from_np)
# PIL_from_tensor size [194, 260, 3], range[0,255]
PIL_from_tensor.save('img_from_tensor.bmp')

# tensor -> numpy -> PIL
np_from_tensor = tensor_from_np.numpy()
# np_from_tensor size [3, 260, 194], range [0, 1]
np_from_tensor *= 255
# np_from_tensor size [3, 260, 194], range [0, 255]
np_from_tensor = np.transpose(np_from_tensor, (1, 2, 0))
# np_from_tensor size [260, 194, 3], range [0, 255]
PIL_from_np = Image.fromarray(np.uint8(np_from_tensor))
# PIL_from_np size [194, 260, 3], range [0, 255]
PIL_from_np.save('img_from_np.bmp')

  为了说明PIL/np/tensor相互转换之间产生的shape和range的变化, 我们这个例子稍微复杂了一点, 关键就是三点

#before np_from_tensor
tensor_from_np2 = tensor_from_np.clone()
...
...
...
np_from_tensor2 = tensor_from_np2.numpy()
np_from_tensor2 *= 255
np_from_tensor2 = np.transpose(np_from_tensor2, (1, 2, 0))
PIL_from_np2 = ToPILImage()(np.uint8(np_from_tensor2))
PIL_from_np2.save('img_from_np2.bmp')

Note:
  这个np.transpose()函数很有用, opencv的图像shape和np也不一样, 也需要用这个函数来转换维度
  上面提到.numpy()的做法是让tensor和np.ndarray()共享内存, 所以如果我们要用tensor原来的数据, 那就要在对np_from_tensor处理之前, 先用.clone()的方式复制出一个副本来

1.2 Resize

torchvision.transforms.Resize(size, interpolation=2)
  这个resize的函数很简单, 用的就是PIL图像处理的内核, 要注意的是, 这个size的格式是(height, width), 也就是说加入要用这个函数2倍downsample一个输入PIL Image图像, 应该是这样

input_image = Image.open('image path')
Resize((input_image.size[1], input_image.size[0]))(input_image)
#or
Resize((input_image.height, input_image.width))(input_image)

  推荐用第二种形式, 比较清楚地体现PIL Image和tensor的维度差别

1.3 Crop

  torchvision.transforms里有很多crop的方法, 选几个用的多的说一下

Crop Description
CenterCrop(size) 将给定的PIL.Image进行中心切割,得到给定的sizesize可以是tuple(target_height, target_width)size也可以是一个Integer,在这种情况下,切出来的图片的形状是正方形。
RandomCrop(szie, padding=0) 切割中心点的位置随机选取。size可以是tuple也可以是Integer
FiveCrop(size) 把图像裁剪为四个角和一个中心, 1张图生成5张图
TenCrop(size, vertical_flip=False) FiveCrop的基础上,再将输入图像进行水平或竖直翻转,然后再进行FiveCrop操作,这样一张输入图像就能得到10张crop结果
RandomSizedCrop(size, interpolation=2) 先将给定的PIL.Image随机切,然后再resize成给定的size大小

1.4 Normalize

1.5 Compose

  transforms.Compose()就是把以上提到的多个步骤整合到一起, 按顺序执行

transforms.Compose([
transforms.CenterCrop(10),
transforms.ToTensor(),
])
上一篇 下一篇

猜你喜欢

热点阅读