首先要理解为什么要进行空间变换?因为我们要将M图像向F图像靠近,不可能一次直接得到变换结果因此需要不断的训练,来得到他们之间的差距,以便进行优化运算。网上有许多介绍空间变换数学模型的博客可以学习一下。
本文主要看Voxelmorph的空间变换函数,原型是3D的,个人原因要做成2D的,原理应该一样,望知晓!
先看一下源代码:


class SpatialTransformer(nn.Module):"""N-D Spatial Transformer"""def __init__(self, size, mode='bilinear'):    #size = [128,128]super().__init__()self.mode = mode# create sampling gridvectors = [torch.arange(0, s) for s in size]grids = torch.meshgrid(vectors)grid = torch.stack(grids)grid = torch.unsqueeze(grid, 0)grid = grid.type(torch.FloatTensor)self.register_buffer('grid', grid)def forward(self, src, flow):new_locs = self.grid + flowshape = flow.shape[2:]for i in range(len(shape)):new_locs[:, i, ...] = 2 * (new_locs[:, i, ...] / (shape[i] - 1) - 0.5)# move channels dim to last position# also not sure why, but the channels need to be reversedif len(shape) == 2:new_locs = new_locs.permute(0, 2, 3, 1)new_locs = new_locs[..., [1, 0]]elif len(shape) == 3:new_locs = new_locs.permute(0, 2, 3, 4, 1)new_locs = new_locs[..., [2, 1, 0]]return nnf.grid_sample(src, new_locs, align_corners=True, mode=self.mode)

初始化构建网格

首先第一行命令

vectors = [torch.arange(0, s) for s in size]
#结果
#[tensor([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
#         14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
#         28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
#         42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,
#         56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
#         70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
#         84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,
#         98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
#        112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
#        126, 127]), tensor([  0,   1,   2,   3,   4,   5,   6,   7,   8,   9,  10,  11,  12,  13,
#         14,  15,  16,  17,  18,  19,  20,  21,  22,  23,  24,  25,  26,  27,
#         28,  29,  30,  31,  32,  33,  34,  35,  36,  37,  38,  39,  40,  41,
#         42,  43,  44,  45,  46,  47,  48,  49,  50,  51,  52,  53,  54,  55,
#         56,  57,  58,  59,  60,  61,  62,  63,  64,  65,  66,  67,  68,  69,
#         70,  71,  72,  73,  74,  75,  76,  77,  78,  79,  80,  81,  82,  83,
#         84,  85,  86,  87,  88,  89,  90,  91,  92,  93,  94,  95,  96,  97,
#         98,  99, 100, 101, 102, 103, 104, 105, 106, 107, 108, 109, 110, 111,
#        112, 113, 114, 115, 116, 117, 118, 119, 120, 121, 122, 123, 124, 125,
#        126, 127])]

创建一个二维的每个维度长128的张量[[0,…,127],[0,…,127]]

第二行命令

 grids = torch.meshgrid(vectors)
#结果
#(tensor([[  0,   0,   0,  ...,   0,   0,   0],
#        [  1,   1,   1,  ...,   1,   1,   1],
#        [  2,   2,   2,  ...,   2,   2,   2],
#        ...,
#        [125, 125, 125,  ..., 125, 125, 125],
#        [126, 126, 126,  ..., 126, 126, 126],
#        [127, 127, 127,  ..., 127, 127, 127]]), tensor([[  0,   1,   2,  ..., 125, 126, 127],
#        [  0,   1,   2,  ..., 125, 126, 127],
#        [  0,   1,   2,  ..., 125, 126, 127],
#        ...,
#        [  0,   1,   2,  ..., 125, 126, 127],
#        [  0,   1,   2,  ..., 125, 126, 127],
#        [  0,   1,   2,  ..., 125, 126, 127]]))

我理解的是这就相当于生成了一个二维的坐标系(一个元组,包含两个二维张量128×128大小)以便获取图像对应位置的坐标,这两个张量分别是横向和纵向的(一个是纵向0-127,另一个是横向0-127),刚好对应我们熟悉的x,y轴的坐标定位。因此可以认为这行命令生成了一个127×127大小的网格,有128×128个顶点,每个顶点对应图像上一个像素坐标,这也有利于理解插值。torch.meshgrid

第三行命令

grid = torch.stack(grids)   #          torch.Size([2, 128, 128])
#结果
#tensor([[[  0,   0,   0,  ...,   0,   0,   0],
#         [  1,   1,   1,  ...,   1,   1,   1],
#         [  2,   2,   2,  ...,   2,   2,   2],
#         ...,
#         [125, 125, 125,  ..., 125, 125, 125],
#         [126, 126, 126,  ..., 126, 126, 126],
#         [127, 127, 127,  ..., 127, 127, 127]],
#
#        [[  0,   1,   2,  ..., 125, 126, 127],
#         [  0,   1,   2,  ..., 125, 126, 127],
#         [  0,   1,   2,  ..., 125, 126, 127],
#         ...,
#         [  0,   1,   2,  ..., 125, 126, 127],
#         [  0,   1,   2,  ..., 125, 126, 127],
#         [  0,   1,   2,  ..., 125, 126, 127]]])

对上述的元组扩张(我认为可以理解为将元组变换为张量),生成一个三维的张量(注意上面是两个张量)2×128×128大小,其中2代表的是元组中的两个张量,128×128是张量的尺寸。torch.stack

第四行命令

grid = torch.unsqueeze(grid, 0)    #torch.Size([1, 2, 128, 128])   B,C,H,W
#结果
#tensor([[[[  0,   0,   0,  ...,   0,   0,   0],
#          [  1,   1,   1,  ...,   1,   1,   1],
#          [  2,   2,   2,  ...,   2,   2,   2],
#          ...,
#          [125, 125, 125,  ..., 125, 125, 125],
#          [126, 126, 126,  ..., 126, 126, 126],
#          [127, 127, 127,  ..., 127, 127, 127]],#         [[  0,   1,   2,  ..., 125, 126, 127],
#          [  0,   1,   2,  ..., 125, 126, 127],
#          [  0,   1,   2,  ..., 125, 126, 127],
#          ...,
#          [  0,   1,   2,  ..., 125, 126, 127],
#          [  0,   1,   2,  ..., 125, 126, 127],
#          [  0,   1,   2,  ..., 125, 126, 127]]]])

生成一个四维的张量方便对数据进行处理(输入2D图像是四维的张量)。torch.unsqueeze

第五行命令

grid = grid.type(torch.FloatTensor)

将网格数据变换为浮点型。

第六行命令

self.register_buffer('grid', grid)

将grid写入内存且不随优化器优化而改变(他是刚性变换,优化的是非刚性变换)。register_buffer

前向传播 forward

第一行命令

new_locs = self.grid + flow

是将初始化生成的网格与经过训练得到的形变场叠加得到最终的形变场。

第二行命令

shape = flow.shape[2:]

获取当前执行的配准图像维度

第三行命令(if命令)

for i in range(len(shape)):new_locs[:, i, ...] = 2 * (new_locs[:, i, ...] / (shape[i] - 1) - 0.5)
#这是源代码,处理的是三维的图像,我是二维的图像,直接使用源码得到的结果只是前两列像素有像素值,经过探索,我将他修改为
#        for i in range(128):   #我处理的图像大小为(128,128),我把每一列像素都限定在[-1,1]之间
#            new_locs[..., i, ...] = 2 * (new_locs[..., i, ...] / 127 - 0.5)

本if语句的意义是,将网格值标准化为 [-1, 1] 以进行重采样。

第四行命令(if命令)

 if len(shape) == 2:new_locs = new_locs.permute(0, 2, 3, 1)new_locs = new_locs[..., [1, 0]]

修改网格张量的顺序,第二行是对网格进行旋转,这是我实验得到的结果,如果把这一行注释掉,得到的结果是顺时针旋转90度的图像。torch.permute
最后一行命令

return nnf.grid_sample(src, new_locs, align_corners=True, mode=self.mode)

将M图像和形变场网格输入,返回最终配准的图像。grid_sample

================================================================

文中所引用的内容如有侵权,告删!!!

voxelmorph中的STN网络相关推荐

  1. otn与stn网络_ASON网络中的DCN-通信/网络-与非网

    1 引言 ASON网络是现在世界上光传送网络研究的热点,它是原有光传送网络的一次重大演进,具有许多原有光传送网络不可比拟的优点.目前ASON网络设备在国际上的现网中已经进入了规模应用,并将逐步部署在我 ...

  2. 基于TPS(Thin Plate Spines)的STN网络的PyTorch实现

    基于TPS(Thin Plate Spines)的STN网络是OCR领域CVPR论文<Robust Scene Text Recognition with Automatic Rectifica ...

  3. 网络复现之基于TPS的STN网络

    基于TPS(Thin Plate Spines)的STN网络是OCR领域CVPR论文<Robust Scene Text Recognition with Automatic Rectifica ...

  4. 深度学习中的卷积网络简介

    卷积网络(convolutional network)也叫做卷积神经网络(convolutional neural network, CNN),是一种专门用来处理具有类似网格结构的数据的神经网络.例如 ...

  5. 在 Virt-manager 图形界面中使用桥接网络

    在 Virt-manager 图形界面中使用桥接网络(bridged networking) 2012-09-03 15:40:23 标签:virt manager.bridge 使用 virt-ma ...

  6. VMware中安装CentOS7网络配置静态IP地址,常用配置和工具安装

    VMware中安装CentOS7网络配置静态IP地址,常用配置和工具安装 在阿里云开源镜像地址下载镜像 Index of /centos/7.2.1511/isos/x86_64/ http://mi ...

  7. 浅析网络营销外包中如何实现网络营销外包中的图片推广?

    随着时代的发展互联网中网站建设的要求也日趋严格,在搜索引擎算法的更新迭代中各行各业之间的企业网站竞争性也在逐渐增强,不过一些站长认为网站优化效果若想好更应该从图片素材中下功夫,可殊不知大量使用图片素材 ...

  8. 网络推广外包中如何让网络推广外包专员充分运用网站的市场价值?

    随着信息时代发展互联网技术研发愈演愈烈,众多企业都开始着手网站营销推广,综合线上线下双重营销推广方式为企业获取更多利益.但是想要让企业充分运营好网站营销推广的市场价值还需要专业人员的全身心投入,那么站 ...

  9. Cloud Foundry中warden的网络设计实现——iptable规则配置

    在Cloud Foundry v2版本号中,该平台使用warden技术来实现用户应用实例执行的资源控制与隔离. 简要的介绍下warden,就是dea_ng假设须要执行用户应用实例(本文暂不考虑ward ...

最新文章

  1. redis学习之——Redis事务(transactions)
  2. android view clip,Android 自定义View Clip
  3. 原核表达常见问题解答
  4. Ubuntu 14.04 安装flash插件;安装Cairo-Dock; 美化为Mac
  5. scorm课件学习状态
  6. 八千字长文深度解读,迁移学习在强化学习中的应用及最新进展
  7. 坚果手机产品经理朱海舟:售后服务和系统维护会正常继续
  8. Python数据挖掘 环境搭建
  9. C语言中怎么将变量名转换为字符串 -转
  10. [原]tornado 源码分析系列目录
  11. rotate list java_Rotate List | Java最短代码实现
  12. 苹方字体 for linux,苹果苹方字体/苹方黑体全套完整版下载(ttf版)
  13. 华为手机解锁码计算工具_华为高通全系列手机解锁工具
  14. 红外遥控接收发射原理及ESP8266实现
  15. 舞蹈模特欣欣(六)棚拍私房 大家看看像小龙女(李若彤)吗?
  16. Vue 按enter键实现登陆 过程
  17. 比较火的NFT数字艺术品交易平台
  18. POI实现 Excel插入图片
  19. 一、RabbitMQ初使用(Consumer)
  20. 基于 AVOS Cloud 的 Android 应用程序快速开发简介

热门文章

  1. 摄像头的像素与分辨率之间的关系
  2. 【XSY3904】直线(分块)
  3. 【XSY2498】贪吃蛇(bfs/dfs)
  4. 【论文学习】Future Person Localization in First-Person Videos
  5. C#学习笔记之匿名方法
  6. python:split()函数
  7. VS Code 网易云音乐插件 没有声音 无法播放的解决办法
  8. 编码理解 | 卷积的实现和卷积神经网络
  9. 牧场物语gb模拟器JAVA_3DS GBC模拟器+GB/GBC游戏合集下载
  10. 一个用interproscan做基因注释的简易教程