转载于: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()

图片变为:

图片平移-1

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()

得到的图片为:

 
图片平移-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:

 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()
修改size的效果

缩放操作

普通方式

放大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()

结果为:

放大操作-1

由于没有使用插值算法,所以中间有很多部分是黑色的。

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()

结果为:

放大操作-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° 结果
 

转置操作

普通操作

 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()

结果为:

 
图片转置-1

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()

结果为:

图片转置-2

(转载)Pytorch中的仿射变换(affine_grid)的更多相关文章

  1. [转载]PyTorch中permute的用法

    [转载]PyTorch中permute的用法 来源:https://blog.csdn.net/york1996/article/details/81876886 permute(dims) 将ten ...

  2. [转载]Pytorch中nn.Linear module的理解

    [转载]Pytorch中nn.Linear module的理解 本文转载并援引全文纯粹是为了构建和分类自己的知识,方便自己未来的查找,没啥其他意思. 这个模块要实现的公式是:y=xAT+*b 来源:h ...

  3. 【转载】 Pytorch中的学习率调整lr_scheduler,ReduceLROnPlateau

    原文地址: https://blog.csdn.net/happyday_d/article/details/85267561 ------------------------------------ ...

  4. (原)CNN中的卷积、1x1卷积及在pytorch中的验证

    转载请注明处处: http://www.cnblogs.com/darkknightzh/p/9017854.html 参考网址: https://pytorch.org/docs/stable/nn ...

  5. 转pytorch中训练深度神经网络模型的关键知识点

    版权声明:本文为博主原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明. 本文链接:https://blog.csdn.net/weixin_42279044/articl ...

  6. pytorch中tensor数据和numpy数据转换中注意的一个问题

    转载自:(pytorch中tensor数据和numpy数据转换中注意的一个问题)[https://blog.csdn.net/nihate/article/details/82791277] 在pyt ...

  7. 详解Pytorch中的网络构造,模型save和load,.pth权重文件解析

    转载:https://zhuanlan.zhihu.com/p/53927068 https://blog.csdn.net/wangdongwei0/article/details/88956527 ...

  8. [转载]PyTorch上的contiguous

    [转载]PyTorch上的contiguous 来源:https://zhuanlan.zhihu.com/p/64551412 这篇文章写的非常好,我这里就不复制粘贴了,有兴趣的同学可以去看原文,我 ...

  9. [转载]Pytorch详解NLLLoss和CrossEntropyLoss

    [转载]Pytorch详解NLLLoss和CrossEntropyLoss 来源:https://blog.csdn.net/qq_22210253/article/details/85229988 ...

随机推荐

  1. Spring5.0.x SSM项目中Json转换器 的配置

    json作为前后端交互的重要手段,在springMVC中有自带的转换器可以免去平时那些繁琐的事情: pom文件添加:spring5.0以上用Jackson2.9以上的版本 <dependency ...

  2. 调用python脚本报错/usr/bin/env: python : No such file or directory

    一.调用python脚本报错 /usr/bin/env: python: No such file or directory 二.解决方法 原因是在windows上编写的脚本,使用dos2unix对脚 ...

  3. 20180606模拟赛T1——猫鼠游戏

    题目描述: 猫和老鼠在10*10的方格中运动,例如: *...*..... ......*... ...*...*.. .......... ...*.C.... *.....*... ...*... ...

  4. spark-shell操作hive

    本文是在集群已经搭建好的基础上来说的,还没有搭建好集群的小伙伴还请自行百度! 启动spark-shell之前要先启动hive metastore 和 hiveservice2 hive --servi ...

  5. jdk1.8——jvm分析与调优

    很多文章都是讲如何配置JVM各个参数的,但是生产环境里参数的值到底配置为多少,却没有一个具体的指标.文章分四个部分,分别是JVM说明.配置,GC的过程和具体配置值. 一.JVM空间说明 JDK 1.7 ...

  6. base64图片编码大小与原图文件大小之间的联系

    base64图片编码大小与原图文件大小之间的联系 有时候我们需要把canvas画布的图画转换成图片输出页面,而用canvas生成的图片就是base64编码的,它是由数字.字母等一大串的字符组成的,但是 ...

  7. RookeyFrame 整个运行流程

    准备开始整理一下这个项目的整体框架,很久没研究这个框架了,心里还是念着的,今儿乘有时间弄一下. 一丁点建议: 先自己一个一个的搬作者的类库,这样就能很好的理解作者的项目结构 每搬一个类库都运行一下哦, ...

  8. 编译lua固件NodeMcu 8266

    https://www.cnblogs.com/yangfengwu/p/10547024.html 因为我现在的Wifi的教程是lua语言编写的,但是有些功能需要自己编译lua固件才可以,这篇文章就 ...

  9. yarn和npm的对比,以及项目中使用方式

    相比npm 的优点 1.npm安装是串行,而yarn是并行,速度大大提升 2.已经下载过的包会被缓存,无需重复下载,更关键的是,支持离线安装 3.精准的版本控制,加上验证每个包的完整性,保证每次安装的 ...

  10. 二分法递归版本(c++)

    利用二分法求解在区间[0,π/2]上的根 #include<iostream> #include <cmath> using namespace std; double dic ...