計算機視覺任務中,對影像的變換(Image Transform)往往是必不可少的操作,例如在遷移學習中,需要對影像尺寸進行變換以使用預訓練網路的輸入層,又如對資料進行增強以豐富訓練資料。
作為深度學習領域的主流框架,pytorch中提供了豐富的影像變換API。本文將對pytorch中torchvision.transforms提供的豐富多樣的影像變換API進行整理介紹。
為方便下文展示各種影像變換API的效果,我們藉助matplotlib定義一個名為show_image
函式來展示圖片,如下所示:
import torch
import numpy as np
from torchvision import transforms
from torchvision.io import read_image
import matplotlib as mpl
import matplotlib.pyplot as plt
mpl.rcParams['font.sans-serif'] = ['SimHei'] # 中文字型支援
def show_image(img_lst, **imshow_kwargs):
"""
img_lst: 儲存影像和標題的list,形如:[(image1, title1),(image2, title2)]。image可以使Pillow.Image物件,也可以是torch.Tensor。
imshow_kwargs: 需要傳遞給plt.imshow的引數
"""
fig, axs =plt.subplots(1,len(img_lst), constrained_layout=True, figsize=(2*len(img_lst),2), squeeze=False)
for i, (img, title) in enumerate(img_lst):
if isinstance(img, torch.Tensor): # 如果是torch.Tensor型別,就必須轉換成Pillow.Image型別,才能進行展示
img = transforms.ToPILImage()(img)
axs[0, i].imshow(np.asarray(img), **imshow_kwargs)
# axs[0, i].set(xticklabels=[], yticklabels=[], xticks=[], yticks=[])
axs[0, i].set_title(title)
plt.show()
1 載入圖片¶
1.1 PIL庫¶
對於儲存在磁碟中的圖片檔案,使用Pillow庫提供的Image類物件進行開啟是一種十分常用的方法,如果你還沒有安裝,你可以透過以下命令方便下文進行:
pip install Pillow
from PIL import Image
我們透過Pillow中提供的方法,開啟一張圖片,並透過show_image()
方法進行展示,下文中各種影像變換,我們都將以此圖片為例,進行演示:
raw_img = (Image.open('fruit.jpeg'), '原始圖片')
show_image([raw_img])
1.2 pytorch中提供的影像載入方法¶
pytorch的torchvision.io模組本身也提供有載入影像資料的方法:read_image。該方法直接將圖片載入為Tensor型別資料。
from torchvision.io import read_image
raw_img2 = read_image('fruit.jpeg')
raw_img2.shape
torch.Size([3, 448, 596])
type(raw_img2)
torch.Tensor
我們也透過之前定義的show_image()
方法進行展示,注意,show_image()
方法之所以能展示Tensor型別資料為影像,是因為show_image()
方法內將Tensor轉為PIL影像了。
show_image([(raw_img2, 'read_image()')])
2 transforms¶
2.1 Compose¶
在介紹transforms前,有必要先說說Compose。
我們做影像變換時,一般都不會單獨使用一個影像變換API,而是順序使用多個API。對於多個API,transforms模組中提供Compose類,對多個API進行打包。Compose關鍵程式碼如下所示:
class Compose:
def __init__(self, transforms):
self.transforms = transforms
def __call__(self, img):
for t in self.transforms:
img = t(img)
return img
可見,在例項化Compose時,我們需要將用到的的API,按順序存入列表(也可以是其他可迭代物件)中,傳遞給Compose。Compose內部機制,將會首先將影像傳給第一個API,然後將經變換後的影像依次往後需API傳遞。如下所示,我們使用Compose對多個API進行組合:
preprocess = transforms.Compose([
transforms.Resize(350), # 變換尺寸
transforms.CenterCrop(300), # 裁切中心180畫素
transforms.ToTensor(), # 轉為Tensor型別
transforms.Normalize( # 標準化
mean=[0.485, 0.456, 0.406],
std=[0.229, 0.224, 0.225]
)
])
raw_img = Image.open('fruit.jpeg')
x = preprocess(raw_img)
x.shape
torch.Size([3, 300, 300])
我們對邊變換前後的影像:
show_image([(raw_img, '原始影像'),(x, '變換後')])
2.2 自定義影像變換¶
transforms是pytorch中torchvision包提供的影像變換模組,提供了各式各樣的影像變換API,這些API都是透過可呼叫物件,可以是函式、也可以是類,如果是類,就必須實現__call__()
方法,至於返回的資料型別,並沒有嚴格限制,只要後續的影像變換API能夠接收就好,但就一般而言,最後一個API的都是Tensor型別資料。所以,如果自定義影像變換API,遵循這些規則去定義可呼叫物件就好。
最簡單的,我們使用lambda定義可呼叫物件:
times_2_plus_1 = transforms.Compose([
lambda x: x * 2,
lambda x: x + 1,
])
times_2_plus_1(2)
5
當然,這並沒有什麼意義,只是實現將一個數字進行平方再加1的變換,這裡只是演示函式方式實現變換器。接下來,我們試試類方式對影像進行變換,例如影像旋轉:
class RandomRotation:
def __init__(self, angle):
self.angle = angle
def __call__(self, img):
return F.rotate(img, self.angle)
raw_img = Image.open('fruit.jpeg')
tran_img = transforms.RandomRotation(60)(raw_img)
show_image([(raw_img, '原始影像'),(tran_img, '旋轉變換後')])
在transforms模組中,pytorch對於多數變換都同時提供有類方式和函式方式的實現,但相較於函式,我更加推薦使用類的方式去實現變換,因為這種方式能夠在例項化物件時,透過傳遞引數實現更加個性化的定製,例如進行尺寸變換,可以在構造方法中指定變換尺寸,這是函式方式無法做到的。函式方式更多是用在定義影像變換類使用使用,另外在功能固定、單一,使用函式方式實現也是不錯的選擇。
3 pytorch中開箱即用的影像變換API¶
記憶體中的影像資料一般分為兩種,一種是PIL的Image物件,一種是torch.Tensor(更嚴謹的說,應該是torch.*Tensor,因為也可以是Tensor的子類),不要槓,我這裡說的是建模過程中的圖片形式,Python當然也可以用其他庫來開啟圖片。相對應的,pytorch中的影像變換API也分為針對PIL.Image物件的API和針對Tensor資料的API以及能同時用於兩種影像形式的API(姑且將這類API稱為通用型影像變換API)。
**注意,即使是通用型API,也可能存在API內某些引數或引數值只適用於Tensor或PIL.Image**
我們先整理通用型的API。
3.1 通用型影像變換API¶
(1)CenterCrop(size)¶
CenterCrop的作用是從影像的中心位置裁剪指定大小的影像。例如一些神經網路的輸入影像大小為300$\times$300,而我們上述展示的原始影像的大小為448$\times$596,此時就需要對訓練影像進行裁剪。
CenterCrop只有一個引數:
- size:裁切保留中央多少個畫素
示例程式碼及結果如下:
raw_img2.shape
torch.Size([3, 448, 596])
raw_img = Image.open('fruit.jpeg')
raw_img2 = read_image('fruit.jpeg')
size = (300, 300)
transform = transforms.CenterCrop(size)
tran_img1 = transform(raw_img)
tran_img2 = transform(raw_img2)
print(f'PIL.Image型別資料裁切後輸出型別為:{type(tran_img1)}')
print(f'torch.Tensor型別資料裁切後輸出型別為:{type(tran_img2)}')
show_image([
(raw_img, '原始影像'),
(tran_img1, 'PIL.Image'), # 對PIL.Image型別圖片進行裁切
(tran_img2, 'torch.Tensor') # 對torch.Tensor型別圖片進行裁切
])
PIL.Image型別資料裁切後輸出型別為:<class 'PIL.Image.Image'> torch.Tensor型別資料裁切後輸出型別為:<class 'torch.Tensor'>
上述示例中,對PIL.Image型別和torch.Tensor型別資料進行了裁切,證明了CenterCrop這類通用型API並不會改變資料型別,輸入什麼型別的影像,輸出還是什麼型別的影像,另外從影像展示結果上看,對兩種型別的影像變換的效果是一樣的。</b>
raw_img = read_image('fruit.jpeg')
size = (300, 300)
transform1 = transforms.Resize(size=300)
transform2 = transforms.Resize(size=(300, 300))
tran_img1 = transform1(raw_img)
tran_img2 = transform2(raw_img)
print(f'size=300,縮放後影像寬高為:{tran_img1.shape}')
print(f'size=(300, 300),縮放後影像寬高為:{tran_img2.shape}')
show_image([
(raw_img, '原始影像'),
(tran_img1, 'size=300'), # 對PIL.Image型別圖片進行裁切
(tran_img2, 'size=(300, 300)') # 對torch.Tensor型別圖片進行裁切
])
size=300,縮放後影像寬高為:torch.Size([3, 300, 399]) size=(300, 300),縮放後影像寬高為:torch.Size([3, 300, 300])
(3)Pad(padding, fill=0, padding_mode='constant')¶
對影像邊框進行填充,主要引數如下:
- padding:指定填充畫素
- 如果是整型,表示對4個邊框都填充padding個畫素值
- 如果是長度為2的序列,例如,padding=(5, 10),表示對左右邊框填充5個畫素值,上下邊框填充10個畫素值。
- 如果是長度為4的序列,例如,padding=(5, 10, 15, 20),表示對左、上、右、下分別填充5、10、15、20個畫素值。
-
fill:填充的內容,預設值為0。**注意,fill的值僅當padding_mode值為'constant'時有效。當輸入影像為Tensor時,fill為int型才有效;當輸入影像為PIL.Image時,fill既可以為int,也可以為序列**。
- 當file是長度為3的序列是,分別用於填充R、G、B通道。
-
padding_mode:填充模式,即以什麼內容填充。預設為值'constant'
- constant:常量填充,填充的內容由fill引數指定。
- edge:用原始影像的最後一個畫素值填充。
- reflect:在邊緣上不重複最後一個值的情況下,使用影像反射進行填充。例如,影像某一行畫素為[1,2,3,4],左右兩邊充填兩個畫素,因為不重複邊界畫素,左側的畫素值1和右側的畫素值4不進行反射,左側就法則2和3,發射後成了3和2,填充到影像左側,右側反射2和3,反射後成了3和2,填充到影像右側,最終這一行畫素值變成[3,2,1,2,4,3,2]。
- symmetric:就是reflect方式填充,只不過重複邊界畫素值。[1,2,3,4]使用這種方式填充後為[2, 1, 1, 2, 3, 4, 4, 3]。
raw_img = Image.open('fruit.jpeg')
show_image([
(
transforms.Pad(padding=20, fill=0, padding_mode='constant')(raw_img),
"padding=20, \n fill=0, \n padding_mode='constant'"
),
(
transforms.Pad(padding=20, fill=(0, 0, 255), padding_mode='constant')(raw_img),
"padding=20, \n fill=(0, 0, 255), \n padding_mode='constant'"
),
(
transforms.Pad(padding=200, padding_mode='edge')(raw_img),
"padding=200, \n padding_mode='edge'"
),
(
transforms.Pad(padding=200, padding_mode='reflect')(raw_img),
"padding=200, \n padding_mode='reflect'"
),
(
transforms.Pad(padding=200, padding_mode='symmetric')(raw_img),
"padding=200, \n padding_mode='reflect'"
),
])
(4)ColorJitter(brightness=0, contrast=0, saturation=0, hue=0)¶
ColorJitter的作用是隨機修改圖片的亮度、對比度、飽和度、色調,常用來進行資料增強,尤其是訓練影像類別不均衡或影像數量較少時。**注意,如果輸入影像為PIL.Image物件,那麼,如果開啟模式為“1”, “I”, “F”或者影像透明,將會產生異常。**常用引數如下:
- brightness:亮度變換範圍,預設值為0,即不變換亮度
- 值為float時, 亮度將在[max(0, 1 - brightness), 1 + brightness] 範圍變化。
- 值為(min, max)時,亮度將在[min, max]範圍內變化。不能為負數。
- contrast:對比度,預設值為0,即不變換對比度
- 值為float時, 對比度將在[max(0, 1 - brightness), 1 + brightness] 範圍變化。
- 值為(min, max)時,對比度將在[min, max]範圍內變化。不能為負數。
- saturation:飽和度,預設值為0,即不變換飽和度
- 值為float時, 飽和度將在[max(0, 1 - brightness), 1 + brightness] 範圍變化。
- 值為(min, max)時,飽和度將在[min, max]範圍內變化。不能為負數。
- hue:色調,預設值為0,即不變換色調
- 值為float時, 色調將在[-hue, hue] 範圍變化。
- 值為(min, max)時,色調將在[min, max]範圍內變化。取值建議:0<=hue<=0.5或-0.5<=min<=max<=0.5。
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.ColorJitter(brightness=(1, 10))(raw_img),
"隨機變換亮度\nbrightness=(1, 10)"
),
(
transforms.ColorJitter(contrast=(1, 10))(raw_img),
"隨機變換對比度\ncontrast=(1, 10)"
),
(
transforms.ColorJitter(saturation=(1, 10))(raw_img),
"隨機變換飽和度\nsaturation=(1, 10)"
),
(
transforms.ColorJitter(hue=(0.2, 0.4))(raw_img),
"隨機變換色調\nhue=(0.2, 0.4)"
),
(
transforms.ColorJitter(brightness=(1, 10), contrast=(1, 10), saturation=(1, 10), hue=(0.2, 0.4))(raw_img),
"padding=20, \n fill=0, \n padding_mode='constant'"
)
])
(5)RandomRotation(degrees[, interpolation, ...])¶
指定角度範圍隨機旋轉影像。
- degrees:旋轉角度範圍
- 當值為(min, max)時,表示在(min, max)範圍內隨機選取一角度對影像進行旋轉
- 當值為數值時,等同於(-degrees, +degrees)
- interpolation:插值方式
- expand:是否對影像進行擴充套件,以展示整個旋轉後影像。
- center:值為(a, b), 圍繞影像中哪個點進行旋轉, 預設圍繞中心點旋轉
- fill: 填充旋轉後影像外的內容
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomRotation(degrees=(20, 60))(raw_img),
"degrees=(20, 60)"
),
(
transforms.RandomRotation(degrees=60, expand=True)(raw_img),
"degrees=60, \nexpand=True"
),
(
transforms.RandomRotation(degrees=60, center=(0, 0))(raw_img),
"degrees=60, \ncenter=(0, 0)"
),
(
transforms.RandomRotation(degrees=60, fill=(0, 0, 255))(raw_img),
"degrees=60, \nfill=(0, 0, 255)"
)
])
(6)GaussianBlur(kernel_size[, sigma])¶
高斯模糊。
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.GaussianBlur(kernel_size =11)(raw_img),
"kernel_size =11"
),
(
transforms.GaussianBlur(kernel_size=(5, 9), sigma=(0.1, 10))(raw_img),
"kernel_size=(5, 9), \nsigma=(0.1, 10)"
),
(
transforms.GaussianBlur(kernel_size =99,sigma=5)(raw_img),
"kernel_size =99,\nsigma=5"
)
])
(7)FiveCrop(size)與TenCrop(size, vertical_flip=False)¶
分別從影像的四個角以及中心進行五次裁剪,最終將返回一個包含5張裁切後圖片的tuple。
- size:裁切尺寸
- 當值為(h, w)時,在原始影像四個角以及中心各採取一張h $\times$w的影像
- 當值為int時,等同於(size, size)
raw_img = Image.open('fruit.jpeg')
trans = transforms.FiveCrop((200, 200))
trans_imgs = trans(raw_img)
print(f'轉換後輸出變數型別為:{type(trans_imgs)}, 輸出變數長度為:{len(trans_imgs)}')
show_image([
(raw_img, '原始影像'),
(trans_imgs[0], '左上角'),
(trans_imgs[1], '右上角'),
(trans_imgs[2], '左下角'),
(trans_imgs[3], '右下角'),
(trans_imgs[4], '中心'),
])
轉換後輸出變數型別為:<class 'tuple'>, 輸出變數長度為:5
再來說TenCrop(size, vertical_flip=False)。
TenCrop(size, vertical_flip=False)就是在FiveCrop(size)的基礎上,對原始影像進行水平或者垂直翻轉,然後在從翻轉後影像的四個角以及中心進行五次裁剪,所以一共獲取了10張影像返回。引數vertical_flip預設值為False,表示進行水平翻轉,值為True時,表示進行垂直翻轉在裁剪。
(8)Grayscale(num_output_channels=1)與RandomGrayscale(p=0.1)¶
將影像轉換為灰度影像,預設通道數為1,通道數為3時,RGB三個通道的值相等。
- num_output_channels :指定最終輸出影像的通道數,值為1時,最終輸出只有一個通道的灰度影像,值為3時,輸出三個通到值相等的灰度影像。預設值為1。
raw_img = read_image('fruit.jpeg')
transform1 = transforms.Grayscale(num_output_channels=1)
transform2 = transforms.Grayscale(num_output_channels=3)
tran_img1 = transform1(raw_img)
tran_img2 = transform2(raw_img)
print(f'num_output_channels=1時,輸出為:{tran_img1.shape}')
print(f'num_output_channels=3時,輸出為:{tran_img2.shape}')
show_image([
(tran_img1, 'num_output_channels=1'),
(tran_img2, 'num_output_channels=3')
], cmap='gray')
num_output_channels=1時,輸出為:torch.Size([1, 448, 596]) num_output_channels=3時,輸出為:torch.Size([3, 448, 596])
RandomGrayscale以一定的機率將影像變為灰度影像。實際上就是以一定的機率執行torchvision.transforms.Grayscale。引數只有一個機率值p,預設值為0.1。這裡不再演示。
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomSolarize(threshold=60, p=1)(raw_img),
"threshold=60, p=1"
),
(
transforms.RandomSolarize(threshold=150, p=1)(raw_img),
"threshold=150, p=1"
),
(
transforms.RandomSolarize(threshold=200, p=1)(raw_img),
"threshold=200, p=1"
)
])
(10)RandomAffine(degrees, translate=None, scale=None, shear=None, resample=False, fillcolor=0)¶
RandomAffine的作用是保持影像中心不變的情況下對影像進行隨機的仿射變換。
- degrees:度數範圍。
- 值為(min,max)時,表示在(min,max)之間隨機變換角度
- 值為int時,等同於(-degrees,degrees)
- translate:位移距離。值為tuple型別,例如translate=(a,b),則在範圍[-影像寬度 $\times$ a, 影像寬度 $\times$ a]中隨機取樣水平移位,在範圍[-影像高度 $\times$ b, 影像高度 $\times$ b]中隨機取樣垂直移位。預設值為0,表示不進行位移。
- scale:縮放。值為tuple型別,例如translate=(a,b),表示在[a, b]範圍內隨機取樣進行縮放,預設情況下將保持原始比例。
- shear:可從中選擇的度數範圍。仿射變換的角度。
- interpolation:插值的方法。
- fill:填充畫素的值。預設為0.
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomAffine(degrees=60)(raw_img),
"degrees=60"
),
(
transforms.RandomAffine(degrees=0, translate=(0.2, 0.6))(raw_img),
"translate=(0.2, 0.6)"
),
(
transforms.RandomAffine(degrees=0, scale=(0.4, 0.8))(raw_img),
"scale=(0.4, 0.8)"
),
(
transforms.RandomAffine(degrees=0, shear=60)(raw_img),
"shear=60"
),
(
transforms.RandomAffine(degrees=0, shear=(30, 80))(raw_img),
"shear=(30, 80)"
),
(
transforms.RandomAffine(degrees=80, fill=(0, 255, 255))(raw_img),
"degrees=80,\nfill=(0, 255, 255)"
),
])
(11)RandomCrop(size, padding=None, pad_if_needed=False, fill=0, padding_mode='constant')¶
在一個隨機位置上對影像進行裁剪。
- size:裁切保留多少個畫素
- 值為tuple,例如(h, w),表示裁切尺寸為(h, w)
- 值為int,等同於(size, size)
- padding:填充邊框畫素值
- 如果是整型,表示對4個邊框都填充padding個畫素值
- 如果是長度為2的序列,例如,padding=(5, 10),表示對左右邊框填充5個畫素值,上下邊框填充10個畫素值。
- 如果是長度為4的序列,例如,padding=(5, 10, 15, 20),表示對左、上、右、下分別填充5、10、15、20個畫素值。
- pad_if_needed:如果影像小於所需大小,它將先填充影像然後進行裁切以避免引發異常。由於裁剪是在填充之後完成的,所以填充似乎是以隨機偏移量完成的。
- fill:填充的內容,預設值為0
- padding_mode:填充模式,即以什麼內容填充。預設為值'constant'
- constant:常量填充,填充的內容由fill引數指定。
- edge:用原始影像的最後一個畫素值填充。
- reflect:在邊緣上不重複最後一個值的情況下,使用影像反射進行填充。例如,影像某一行畫素為[1,2,3,4],左右兩邊充填兩個畫素,因為不重複邊界畫素,左側的畫素值1和右側的畫素值4不進行反射,左側就法則2和3,發射後成了3和2,填充到影像左側,右側反射2和3,反射後成了3和2,填充到影像右側,最終這一行畫素值變成[3,2,1,2,4,3,2]。
- symmetric:就是reflect方式填充,只不過重複邊界畫素值。[1,2,3,4]使用這種方式填充後為[2, 1, 1, 2, 3, 4, 4, 3]。
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomCrop(size=200)(raw_img),
"size=200"
),
(
transforms.RandomCrop(size=500,padding=200)(raw_img),
"size=500,padding=200"
)
])
(12)RandomHorizontalFlip(p=0.5)與RandomVerticalFlip(p=0.5)¶
以一定的機率將影像水平翻轉。引數只有一個機率值p,預設值為0.5。
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomHorizontalFlip(p=1)(raw_img),
"水平翻轉"
)
])
有水平翻轉,就有垂直翻轉,即RandomVerticalFlip(p=0.5),用法與RandomHorizontalFlip(p=0.5)完全一致,這裡不再介紹。
(13)RandomPerspective(distortion_scale=0.5, p=0.5, interpolation=3, fill=0)¶
以一定的機率對影像進行隨機的透視變換。
- distortion_scale:扭曲的角度,取值在[0, 1]之間,預設值為0.5.
- p:執行變換的機率。
- interpolation:插值的方法。
- fill:填充的內容,預設值為0。
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomPerspective(distortion_scale=0.5)(raw_img),
"distortion_scale=0.5"
)
])
raw_img = Image.open('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomEqualize(p=1)(raw_img),
"threshold=60, p=1"
)
])
raw_img = Image.open('fruit.jpeg')
trans = transforms.RandomChoice([
transforms.Resize(350),
transforms.RandomEqualize(p=1),
transforms.RandomAffine(degrees=60)
])
show_image([
(
raw_img, '原始影像'
),
(
trans(raw_img), '隨機一次變換'
),
(
trans(raw_img), '隨機一次變換'
)
])
從功能上說,這兩個API都不是專門針對PIL.Image,我不知道官方文件上為什麼這麼分類。
3.3 專用於torch.*Tensor的影像變換API¶
(1) LinearTransformation(transformation_matrix, ...)¶
使用變換矩陣和離線計算的均值向量對影像張量進行變換,可以用在白化變換中,白化變換用來去除輸入資料的冗餘資訊。常用在資料預處理中。
(2)Normalize(mean, std, inplace=False)¶
逐channel的對影像進行標準化(均值變為0,標準差變為1),可以加快模型的收斂
(3)RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3)¶
隨機選擇影像中的一塊區域,擦除其畫素,主要用來進行資料增強。
- p: 執行擦除的機率。
- scale:擦除區域相對於輸入影像的比例範圍。
- ratio:擦除區域的縱橫比範圍。
- value:擦除區域的填充內容。
- inplace:是否原地修改,預設為False。
raw_img = read_image('fruit.jpeg')
show_image([
(
raw_img, '原始影像'
),
(
transforms.RandomErasing(p=1, scale=(0.2, 0.3),ratio=(0.5, 1.0),value=(0, 0, 255))(raw_img),
"隨機擦除"
)
])
(4)RandomErasing(p=0.5, scale=(0.02, 0.33), ratio=(0.3, 3.3)¶
對影像中各畫素資料型別進行轉換。
- dtype : 輸出影像中各個畫素的資料型別
raw_img = read_image('fruit.jpeg')
print(f'轉換前資料型別為:{raw_img.dtype}')
轉換前資料型別為:torch.uint8
img = transforms.ConvertImageDtype(dtype=torch.float32)(raw_img)
print(f'轉換前資料型別後:{img.dtype}')
轉換前資料型別後:torch.float32
raw_img = read_image('fruit.jpeg')
print(f'轉換前影像型別為:{type(raw_img)}')
img = transforms.ToPILImage()(raw_img)
print(f'轉換後影像型別為:{type(img)}')
轉換前影像型別為:<class 'torch.Tensor'> 轉換後影像型別為:<class 'PIL.Image.Image'>
(2)ToTensor()¶
將PIL.Image或numpy.ndarray型別影像轉為torch.Tensor型別影像。
raw_img = Image.open('fruit.jpeg')
print(f'轉換前影像型別為:{type(raw_img)}')
img = transforms.ToTensor()(raw_img)
print(f'轉換後影像型別為:{type(img)}')
轉換前影像型別為:<class 'PIL.JpegImagePlugin.JpegImageFile'> 轉換後影像型別為:<class 'torch.Tensor'>
(3)PILToTensor()¶
將PIL.Image(shape為:(H x W x C))型別影像轉為torch.Tensor(shape為: (C x H x W))。
raw_img = Image.open('fruit.jpeg')
print(f'轉換前影像型別為:{type(raw_img)},')
img = transforms.ToTensor()(raw_img)
print(f'轉換後影像型別為:{type(img)}')
轉換前影像型別為:<class 'PIL.JpegImagePlugin.JpegImageFile'>, 轉換後影像型別為:<class 'torch.Tensor'>