pytorch transform/tensor 基本操作

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

1 .transform

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

  • Resize, 把给定的图片resize到target size
  • Normalize, Normalized an tensor image with mean and standard deviation
  • ToTensor, convert a PIL image to tensor (H, W, C) in range [0,255] to a torch.Tensor(C, H, W) in the range [0.0, 1.0]
  • ToPILImage, convert a tensor to PIL image
  • CenterCrop, 在图片的中间区域进行crop
  • RandomCrop, 在一个随机位置进行crop
  • FiveCrop, 把图像裁剪为四个角和一个中心
  • TenCrop, five crop+flip 1->10

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的变化, 我们这个例子稍微复杂了一点, 关键就是三点

  • 用ToTensor()转换, 不管input的是PIL还是np, 只要是uint8格式的, 都会直接转成[0,1]的float32格式, 所以我们看到的tensor_from_np和tensor_from_PIL是一样的, 而ToPILImage是将tensor转为PIL Image, 自动又会把float32的[0,1]转回uint8
  • 如果是先把tensor转为np, 再转为PIL Image, 那就有上面我们提到的np_img和tensor_from_np.numpy()的shape和range都是不同的, 因为.numpy()的过程就是把tensor格式的数据复制到np格式的数据, 重要的是, np_from_tensor和tensor_from_np共享了同一段内存, 所以我们可以看到在更改np_from_tensor的值的时候, tensor_from_np也在变, 所以要进行[0,1]->[0,255] + transpose更改shape + float32->uint8的过程改为和np_img的shape和range都一样, 这个时候再用Image.fromarray()才能还原成和PIL_img相同的图像
  • ToPILImage除了可以做tensor->PIL, 还可以做np->PIL, 就是将shape为(C,H,W)的Tensor或shape为(H,W,C)的numpy.ndarray转换成PIL.Image, 但注意, 输入是np的话它不会把[0,1]float32自动转成uint8, 所以用法就变成和Image.fromarray()一样了
#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的方法, 选几个用的多的说一下

  • CenterCrop, 在图片的中间区域进行crop
  • RandomCrop, 在一个随机位置进行crop
  • FiveCrop, 把图像裁剪为四个角和一个中心
  • TenCrop, 在FiveCrop的基础上,再将输入图像进行水平或竖直翻转,然后再进行FiveCrop操作,这样一张输入图像就能得到10张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(),
])
最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 211,042评论 6 490
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 89,996评论 2 384
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 156,674评论 0 345
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,340评论 1 283
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,404评论 5 384
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,749评论 1 289
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,902评论 3 405
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,662评论 0 266
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,110评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,451评论 2 325
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,577评论 1 340
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,258评论 4 328
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,848评论 3 312
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,726评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,952评论 1 264
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,271评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,452评论 2 348

推荐阅读更多精彩内容