(转载)Pytorch中的仿射变换(affine_grid)
转载于:Pytorch中的仿射变换(affine_grid)
参考:详细解读Spatial Transformer Networks (STN)
假设我们有这么一张图片:

下面我们将通过分别通过手动编码和pytorch方式对该图片进行平移、旋转、转置、缩放等操作,这些操作的数学原理在本文中不会详细讲解。
实现载入图片(注意,下面的代码都是在 jupyter 中进行):
from torchvision import transforms
from PIL import Image
import matplotlib.pyplot as plt %matplotlib inline img_path = "图片文件路径"
img_torch = transforms.ToTensor()(Image.open(img_path)) plt.imshow(img_torch.numpy().transpose(1,2,0))
plt.show()
平移操作
普通方式
例如我们需要向右平移50px,向下平移100px。
import numpy as np
import torch theta = np.array([
[1,0,50],
[0,1,100]
])
# 变换1:可以实现缩放/旋转,这里为 [[1,0],[0,1]] 保存图片不变
t1 = theta[:,[0,1]]
# 变换2:可以实现平移
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 = npos[0][0], 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()
图片变为:

pytorch 方式
向右移动0.2,向下移动0.4:
from torch.nn import functional as F theta = torch.tensor([
[1,0,-0.2],
[0,1,-0.4]
], 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()
得到的图片为:

总结:
- 要使用 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')
- 创建 grid:
- theta 的第三列为平移比例,向右为负,向下为负;
我们通过设置 size
可以将图像resize:
from torch.nn import functional as F theta = torch.tensor([
[1,0,-0.2],
[0,1,-0.4]
], dtype=torch.float)
# 修改size
N, C, W, H = img_torch.unsqueeze(0).size()
size = torch.Size((N, C, W//2, H//3))
grid = F.affine_grid(theta.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()

缩放操作
普通方式
放大1倍:
import numpy as np
import torch theta = np.array([
[2,0,0],
[0,2,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 = npos[0][0], 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()
结果为:

由于没有使用插值算法,所以中间有很多部分是黑色的。
pytorch 方式
from torch.nn import functional as F theta = torch.tensor([
[0.5, 0 , 0],
[0 , 0.5, 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()
结果为:

结论:可以看到,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()
结果为:

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()
结果为:

pytorch 以图片中心为原点进行旋转,并且在旋转过程中会发生图片缩放,如果选择角度变为 90°,图片为:

转置操作
普通操作
import numpy as np
import torch theta = np.array([
[0,1,0],
[1,0,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 = npos[0][0], 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()
结果为:

pytorch 操作
我们可以通过size大小,保存图片不被压缩:
from torch.nn import functional as F theta = torch.tensor([
[0, 1, 0],
[1, 0, 0]
], dtype=torch.float)
N, C, H, W = img_torch.unsqueeze(0).size()
grid = F.affine_grid(theta.unsqueeze(0), torch.Size((N, C, W, H)))
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()
结果为:

(转载)Pytorch中的仿射变换(affine_grid)的更多相关文章
- [转载]PyTorch中permute的用法
[转载]PyTorch中permute的用法 来源:https://blog.csdn.net/york1996/article/details/81876886 permute(dims) 将ten ...
- [转载]Pytorch中nn.Linear module的理解
[转载]Pytorch中nn.Linear module的理解 本文转载并援引全文纯粹是为了构建和分类自己的知识,方便自己未来的查找,没啥其他意思. 这个模块要实现的公式是:y=xAT+*b 来源:h ...
- 【转载】 Pytorch中的学习率调整lr_scheduler,ReduceLROnPlateau
原文地址: https://blog.csdn.net/happyday_d/article/details/85267561 ------------------------------------ ...
- (原)CNN中的卷积、1x1卷积及在pytorch中的验证
转载请注明处处: http://www.cnblogs.com/darkknightzh/p/9017854.html 参考网址: https://pytorch.org/docs/stable/nn ...
- 转pytorch中训练深度神经网络模型的关键知识点
版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_42279044/articl ...
- pytorch中tensor数据和numpy数据转换中注意的一个问题
转载自:(pytorch中tensor数据和numpy数据转换中注意的一个问题)[https://blog.csdn.net/nihate/article/details/82791277] 在pyt ...
- 详解Pytorch中的网络构造,模型save和load,.pth权重文件解析
转载:https://zhuanlan.zhihu.com/p/53927068 https://blog.csdn.net/wangdongwei0/article/details/88956527 ...
- [转载]PyTorch上的contiguous
[转载]PyTorch上的contiguous 来源:https://zhuanlan.zhihu.com/p/64551412 这篇文章写的非常好,我这里就不复制粘贴了,有兴趣的同学可以去看原文,我 ...
- [转载]Pytorch详解NLLLoss和CrossEntropyLoss
[转载]Pytorch详解NLLLoss和CrossEntropyLoss 来源:https://blog.csdn.net/qq_22210253/article/details/85229988 ...
随机推荐
- kuangbin专题专题四 MPI Maelstrom POJ - 1502
题目链接:https://vjudge.net/problem/POJ-1502 dijkstra板子题,题目提供下三角情况,不包含正对角线,因为有题意都为0,处理好输入,就是一个很水的题. #inc ...
- css 布局 flex
cursor 设置鼠标放上去后的形状 visability 设置是否可见 flex 详见这篇文章https://developer.mozilla.org/zh-CN/docs/Learn/CSS/C ...
- httprunner学习2-har2case录制生成脚本
前言 复制毁一生,录制穷三代,如果你只是因为不想写脚本,而去录制脚本,那我建议你还是别学录制了. 录制脚本,只是一个过渡,从0到1的一个过渡,如果让你直接写脚本,你会无从下手,可以将录制的脚本快速转化 ...
- CentOS7.5搭建Rsync,实现文件同步
Rsync(remote sync)是UNIX及类UNIX平台下一款神奇的数据镜像备份软件,它不像FTP或其他文件传输服务那样需要进行全备份,Rsync可以根据数据的变化进行差异备份,从而减少数据流量 ...
- 201671030106 何启芝 实验十四 团队项目评审&课程学习总结
项目 内容 这个作业属于哪个课程 >>2016级计算机科学与工程学院软件工程(西北师范大学) 这个作业的要求在哪里 >>实验十四 团队项目评审&课程学习总结 课程学习目 ...
- LOJ6070 基因
基因 给定一个长度为 \(n\) 的字符串 \(s\),有 \(q\) 组询问,每个询问给定 \(l,r\),询问 \(s[l..r]\) 中有多少本质不同的回文子串. 强制在线.\(n\leq 10 ...
- C语言中一个语句太长用什么换行?
C语言中一个语句太长用什么换行? 5 C语言中一个语句太长用什么换行?比如我有一个printf语句很长很长,问了美观,我不想写在这一行了,要换到下一行,是不是在这行结尾的时候,要用个什么标识来表 ...
- day004-python运算符与基本数据类型
一.运算符1.算术运算符:主要用于两个对象算数计算(加减乘除等运算)运算符: +:两个对象相加 -:得到负数或是一个数减去另一个数 *:两个数相乘或是返回一个被重复若干次的字符串 /:x除以y %:返 ...
- linux中的目录
Linux文件系统数如下: 在 Linux 系统中,文件系统通过目录"包含"子目录及文件的方式,来组织成一个树状结构.那么目录到底是如何"包含"其他目录及文件的 ...
- JavaScript base64 加密解密
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8&quo ...