(转载)Pytorch中的仿射变换(affine_grid)
轉載于:Pytorch中的仿射變換(affine_grid)
參考:詳細解讀Spatial Transformer Networks (STN)
假設我們有這么一張圖片:
下面我們將通過分別通過手動編碼和pytorch方式對該圖片進行平移、旋轉、轉置、縮放等操作,這些操作的數學原理在本文中不會詳細講解。
實現載入圖片(注意,下面的代碼都是在 jupyter 中進行):
1 from torchvision import transforms 2 from PIL import Image 3 import matplotlib.pyplot as plt 4 5 %matplotlib inline 6 7 img_path = "圖片文件路徑" 8 img_torch = transforms.ToTensor()(Image.open(img_path)) 9 10 plt.imshow(img_torch.numpy().transpose(1,2,0)) 11 plt.show()
平移操作
普通方式
例如我們需要向右平移50px,向下平移100px。
1 import numpy as np 2 import torch 3 4 theta = np.array([ 5 [1,0,50], 6 [0,1,100] 7 ]) 8 # 變換1:可以實現縮放/旋轉,這里為 [[1,0],[0,1]] 保存圖片不變 9 t1 = theta[:,[0,1]] 10 # 變換2:可以實現平移 11 t2 = theta[:,[2]] 12 13 _, h, w = img_torch.size() 14 new_img_torch = torch.zeros_like(img_torch, dtype=torch.float) 15 for x in range(w): 16 for y in range(h): 17 pos = np.array([[x], [y]]) 18 npos = t1@pos+t2 19 nx, ny = npos[0][0], npos[1][0] 20 if 0<=nx<w and 0<=ny<h: 21 new_img_torch[:,ny,nx] = img_torch[:,y,x] 22 plt.imshow(new_img_torch.numpy().transpose(1,2,0)) 23 plt.show()
圖片變為:
圖片平移-1
pytorch 方式
向右移動0.2,向下移動0.4:
1 from torch.nn import functional as F 2 3 theta = torch.tensor([ 4 [1,0,-0.2], 5 [0,1,-0.4] 6 ], dtype=torch.float) 7 grid = F.affine_grid(theta.unsqueeze(0), img_torch.unsqueeze(0).size()) 8 output = F.grid_sample(img_torch.unsqueeze(0), grid) 9 new_img_torch = output[0] 10 plt.imshow(new_img_torch.numpy().transpose(1,2,0)) 11 plt.show()
得到的圖片為:
圖片平移-2
總結:
要使用 pytorch 的平移操作,只需要兩步:theta 的第三列為平移比例,向右為負,向下為負;
創建 grid:grid = torch.nn.functional.affine_grid(theta, size),其實我們可以通過調節 size 設置所得到的圖像的大小(相當于resize);
grid_sample 進行重采樣:outputs = torch.nn.functional.grid_sample(inputs, grid, mode='bilinear')
theta 的第三列為平移比例,向右為負,向下為負;
我們通過設置 size 可以將圖像resize:
1 from torch.nn import functional as F 2 3 theta = torch.tensor([ 4 [1,0,-0.2], 5 [0,1,-0.4] 6 ], dtype=torch.float) 7 # 修改size 8 N, C, W, H = img_torch.unsqueeze(0).size() 9 size = torch.Size((N, C, W//2, H//3)) 10 grid = F.affine_grid(theta.unsqueeze(0), size) 11 output = F.grid_sample(img_torch.unsqueeze(0), grid) 12 new_img_torch = output[0] 13 plt.imshow(new_img_torch.numpy().transpose(1,2,0)) 14 plt.show()
修改size的效果
縮放操作
普通方式
放大1倍:
1 import numpy as np 2 import torch 3 4 theta = np.array([ 5 [2,0,0], 6 [0,2,0] 7 ]) 8 t1 = theta[:,[0,1]] 9 t2 = theta[:,[2]] 10 11 _, h, w = img_torch.size() 12 new_img_torch = torch.zeros_like(img_torch, dtype=torch.float) 13 for x in range(w): 14 for y in range(h): 15 pos = np.array([[x], [y]]) 16 npos = t1@pos+t2 17 nx, ny = npos[0][0], npos[1][0] 18 if 0<=nx<w and 0<=ny<h: 19 new_img_torch[:,ny,nx] = img_torch[:,y,x] 20 plt.imshow(new_img_torch.numpy().transpose(1,2,0)) 21 plt.show()
結果為:
放大操作-1
由于沒有使用插值算法,所以中間有很多部分是黑色的。
pytorch 方式
1 from torch.nn import functional as F 2 3 theta = torch.tensor([ 4 [0.5, 0 , 0], 5 [0 , 0.5, 0] 6 ], dtype=torch.float) 7 grid = F.affine_grid(theta.unsqueeze(0), img_torch.unsqueeze(0).size()) 8 output = F.grid_sample(img_torch.unsqueeze(0), grid) 9 new_img_torch = output[0] 10 plt.imshow(new_img_torch.numpy().transpose(1,2,0)) 11 plt.show()
結果為:
放大操作-2
結論:可以看到,affine_grid的放大操作是以圖片中心為原點的。
旋轉操作
普通操作
將圖片旋轉30度:
import numpy as np
import torch
import math
angle = 30*math.pi/180
theta = np.array([
[math.cos(angle),math.sin(-angle),0],
[math.sin(angle),math.cos(angle) ,0]
])
t1 = theta[:,[0,1]]
t2 = theta[:,[2]]
_, h, w = img_torch.size()
new_img_torch = torch.zeros_like(img_torch, dtype=torch.float)
for x in range(w):
for y in range(h):
pos = np.array([[x], [y]])
npos = t1@pos+t2
nx, ny = int(npos[0][0]), int(npos[1][0])
if 0<=nx<w and 0<=ny<h:
new_img_torch[:,ny,nx] = img_torch[:,y,x]
plt.imshow(new_img_torch.numpy().transpose(1,2,0))
plt.show()
結果為:
旋轉操作-1
pytorch 操作
from torch.nn import functional as F
import math
angle = -30*math.pi/180
theta = torch.tensor([
[math.cos(angle),math.sin(-angle),0],
[math.sin(angle),math.cos(angle) ,0]
], dtype=torch.float)
grid = F.affine_grid(theta.unsqueeze(0), img_torch.unsqueeze(0).size())
output = F.grid_sample(img_torch.unsqueeze(0), grid)
new_img_torch = output[0]
plt.imshow(new_img_torch.numpy().transpose(1,2,0))
plt.show()
結果為:
旋轉操作-2
pytorch 以圖片中心為原點進行旋轉,并且在旋轉過程中會發生圖片縮放,如果選擇角度變為 90°,圖片為:
旋轉 90° 結果
轉置操作
普通操作
1 import numpy as np 2 import torch 3 4 theta = np.array([ 5 [0,1,0], 6 [1,0,0] 7 ]) 8 t1 = theta[:,[0,1]] 9 t2 = theta[:,[2]] 10 11 _, h, w = img_torch.size() 12 new_img_torch = torch.zeros_like(img_torch, dtype=torch.float) 13 for x in range(w): 14 for y in range(h): 15 pos = np.array([[x], [y]]) 16 npos = t1@pos+t2 17 nx, ny = npos[0][0], npos[1][0] 18 if 0<=nx<w and 0<=ny<h: 19 new_img_torch[:,ny,nx] = img_torch[:,y,x] 20 plt.imshow(new_img_torch.numpy().transpose(1,2,0)) 21 plt.show()
結果為:
圖片轉置-1
pytorch 操作
我們可以通過size大小,保存圖片不被壓縮:
1 from torch.nn import functional as F 2 3 theta = torch.tensor([ 4 [0, 1, 0], 5 [1, 0, 0] 6 ], dtype=torch.float) 7 N, C, H, W = img_torch.unsqueeze(0).size() 8 grid = F.affine_grid(theta.unsqueeze(0), torch.Size((N, C, W, H))) 9 output = F.grid_sample(img_torch.unsqueeze(0), grid) 10 new_img_torch = output[0] 11 plt.imshow(new_img_torch.numpy().transpose(1,2,0)) 12 plt.show()
結果為:
圖片轉置-2
總結
以上是生活随笔為你收集整理的(转载)Pytorch中的仿射变换(affine_grid)的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: win7+ubuntu20.04双系统+
- 下一篇: charles SSL证书安装