医学图像处理 利用pytorch实现的可用于反传的Radon变换和逆变换

news2024/11/17 20:44:10

医学图像处理 利用pytorch实现的可用于反传的Radon变换和逆变换

  • 前言
  • 代码
  • 实现思路
  • 实验结果

前言

Computed Tomography(CT,计算机断层成像)技术作为如今医学中重要的辅助诊断手段,也是医学图像研究的重要主题。如今,随着深度学习对CT重建、CT分割的研究逐渐深入,论文开始越来越多的利用CT的每一个环节,来扩充Feature或构造损失函数。

但是每到这个时候,一个问题就出现了,如果我要构造损失函数,我势必要保证这个运算中梯度不会断掉,否则起不到优化效果。而Radon变换目前好像没有人直接用其当作损失函数的一部分,很奇怪,故在此实现pytorch版本的Radon变换,已经验证可以反传(但是反传的对不对不敢保证,只保证能计算出反传的值)。希望能帮到需要的同学。

参考了这两篇博文,在此十分感谢这位前辈。
Python实现离散Radon变换
Python实现逆Radon变换——直接反投影和滤波反投影

代码

from typing import Optional
import numpy as np
import matplotlib.pyplot as plt
import math
import torch as th
import torch.nn as nn
import torch.nn.functional as F
import SimpleITK as sitk


#两种滤波器的实现
def RLFilter(N, d):
    filterRL = np.zeros((N,))
    for i in range(N):
        filterRL[i] = - 1.0 / np.power((i - N / 2) * np.pi * d, 2.0)
        if np.mod(i - N / 2, 2) == 0:
            filterRL[i] = 0
    filterRL[int(N/2)] = 1 / (4 * np.power(d, 2.0))
    return filterRL

def SLFilter(N, d):
    filterSL = np.zeros((N,))
    for i in range(N):
        filterSL[i] = - 2 / (np.pi**2.0 * d**2.0 * (4 * (i - N / 2)**2.0 - 1))
    return filterSL

def IRandonTransform(image:'th.Tensor|np.array', steps:Optional[int]=None):
    '''
    Inverse Radon Transform(with Filter, FBP)

    Parameters:
        image: (B, C, W, H)
    '''
    # 定义用于存储重建后的图像的数组
    channels = image.shape[-1]
    B, C, W, H = image.shape
    if steps == None:
        steps = channels
    origin = th.zeros((B, C, steps, channels, channels), dtype=th.float32)
    filter_kernal = th.tensor(SLFilter(channels, 1)).unsqueeze(0).unsqueeze(0).float()
    Filter = nn.Conv1d(C, C, (channels), padding='same',bias=False)
    Filter.weight = nn.Parameter(filter_kernal) 

    for i in range(steps):
    	# 传入的图像中的每一列都对应于一个角度的投影值
    	# 这里用的图像是上篇博文里得到的Radon变换后的图像裁剪后得到的
        projectionValue = image[:, :, :, i]
        projectionValue = Filter(projectionValue)
        # 这里利用维度扩展和重复投影值数组来模拟反向均匀回抹过程
        projectionValueExpandDim = projectionValue.unsqueeze(2)
        projectionValueRepeat = projectionValueExpandDim.repeat((1, 1, channels, 1))
        origin[:,:, i] = rotate(projectionValueRepeat, (i / steps) * math.pi)
    #各个投影角度的投影值已经都保存在origin数组中,只需要将它们相加即可
    iradon = th.sum(origin, axis=2)
    return iradon


def rotate(image:th.Tensor, angle):
    '''
    Rotate the image in any angles(include negtive).
    angle should be pi = 180
    '''
    B= image.shape[0]
    transform_matrix = th.tensor([
            [math.cos(angle),math.sin(-angle),0],
            [math.sin(angle),math.cos(angle),0]], dtype=th.float32).unsqueeze(0).repeat(B,1,1)
    grid = F.affine_grid(transform_matrix, # 旋转变换矩阵
                            image.shape).float()	# 变换后的tensor的shape(与输入tensor相同)
    rotation = F.grid_sample(image, # 输入tensor,shape为[B,C,W,H]
                            grid, # 上一步输出的gird,shape为[B,C,W,H]
                            mode='nearest') # 一些图像填充方法,这里我用的是最近邻
    return rotation


def DiscreteRadonTransform(image:'th.Tensor|np.array', steps:Optional[int]=None):
    '''
    Radon Transform

    Parameters:
        image : (B, C, W, H)
    '''
    channels = image.shape[-1] # img_size
    B, C, W, H = image.shape
    res = th.zeros((B, channels, channels), dtype=th.float32)
    if steps == None:
        steps = channels
    for s in range(steps):
        angle = (s / steps) * math.pi
        rotation = rotate(image, -angle)
        res[:, :,s] = th.sum(rotation, dim=2)
    return res.unsqueeze(1)
    
if __name__ == '__main__':

    origin = sitk.ReadImage('/hy-tmp/data/LIDC/CT/0001.nii.gz')
    t_origin = sitk.GetArrayFromImage(origin)
    t_origin = th.tensor(t_origin)
    t_origin = t_origin[40].unsqueeze(0).unsqueeze(0)
    a = nn.Parameter(th.ones_like(t_origin))
    t_origin = t_origin * a
    ret = DiscreteRadonTransform(t_origin) # (B, 1, H, W)
    b = th.ones_like(ret)
    lf = nn.MSELoss()
    loss = lf(b, ret)
    loss.backward() # pytorch不会报错,并能返回grad
    rec = IRandonTransform(ret)
    ret = ret.squeeze(0)
    rec = rec.squeeze(0)
    plt.imsave('test.png', (t_origin.squeeze(0).squeeze(0)).data.numpy(), cmap='gray')
    plt.imsave('test2.png', (ret.squeeze(0)).data.numpy(), cmap='gray')
    plt.imsave('test3.png', (rec.squeeze(0)).data.numpy(), cmap='gray')

实现思路

这份代码实际上是参考前文提到的前辈的代码修改而来,具体而言就是把各种numpy实现的地方修改为pytorch的对应实现,其中pytorch没有对应的API来实现矩阵的Rotate,因此还参考了网上其它人实现的手写旋转的pytorch版本。并将其写作Rotate函数,在其它任务中也可以调用,这里需要注意,调用时,矩阵需要是方阵,否则会出现旋转后偏移中心的问题。

实验结果

原始图像:
请添加图片描述
Radon变换的结果:
请添加图片描述
重建结果:
请添加图片描述
这些图像可以下载下来,自己试试。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1574564.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

前端三剑客 —— JavaScript (第一节)

目录 回顾内容 1.弹性布局 2.网格布局 JavaScript 概述 发展 浏览器 什么是Javascript JavaScript 能干什么 JavaScript需要的环境 JavaScript初体验 基本数据 JS书写方式 行内JS 页面JS 外部JS 1)创建外部JS文件 2)编写页面 对话框 警…

[C语言][数据结构][动态内存空间的开辟]顺序表的实现!

目录 零.必备知识 a.顺序表的底层是数组. b.数组在内存中是连续存放的. c.动态内存空间的开辟(malloc,calloc,realloc). 一.顺序表的定义与实现 1.1 顺序表的定义 1.2 顺序表的初始化 1.3 顺序表的销毁 1.4 顺序表容量的检查与调整(最关键的部分) 1.5 顺序表的尾插 1.…

【Flutter】Getx设计模式及Provider、Repository、Controller、View等

本文基于Getx 4,x 本本 1、引入 再次接触到Flutter项目,社区俨然很完善和活跃。pubs.dev 寻找状态管理的时候看到很熟悉的Getx时间,俨然发现Getx的版本已到是4.x版本,看到Getx的功能已经非常强大了,庞大的API俨然成为一种开发框架…

通俗易懂的理解 ADC(2)

理解什么是ADC 文章目录 1、通俗理解什么是ADC 2、什么是ADC 3、ADC的采样率 4、采样位数 5、采样精度 ADC实际没有这么的简单,深入了解需要去学各种寄存器之间如何协作,信号如何走通。这些概念在后面会有讲解。 1、通俗理解…

[mmu/cache]-MMU的地址翻译(Address translation)指令介绍

快速链接: 【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈 Address translation system instructions AT指令的语法格式: 有了上面的语法格式后,就非常好理解armv8的MMU提供了14条AT指令了: MMU的地址…

[mmu/cache]-ARMV8的cache的维护指令介绍

快速链接: 【精选】ARMv8/ARMv9架构入门到精通-[目录] 👈👈👈 Armv8里定义的Cache的管理的操作有三种: 无效(Invalidate) 整个高速缓存或者某个高速缓存行。高速缓存上的数据会被丢弃。清除(Cl…

#{} 和 ${}区别

1、参数是Integer类型时候没区别(#是预编译SQL,$是即时SQL) 2、当参数是String类型时,就会出错了 (1)这是$的报错信息,因为我们的参数admin并没有加引号所以不满足字符串条件 (2)正确的SQL &am…

FJSP:美洲狮优化算法(Puma Optimizar Algorithm ,POA)求解柔性作业车间调度问题(FJSP),提供MATLAB代码

一、柔性作业车间调度问题 柔性作业车间调度问题(Flexible Job Shop Scheduling Problem,FJSP),是一种经典的组合优化问题。在FJSP问题中,有多个作业需要在多个机器上进行加工,每个作业由一系列工序组成&a…

用可视化案例讲Rust编程5.用泛型和特性实现自适配绘制和颜色设置

上一节我们讲了用泛型实现返回结果,这一节我们来讲讲在函数签名里面使用泛型来对输入参数进行自适配。 先看UML设计图: 好吧,看起来有点复杂,我们一个个来解释。 首先定义的是一个生成绘图元素需要的参数结构,并且定义个特性&am…

LeetCode-1483. 树节点的第 K 个祖先【树 深度优先搜索 广度优先搜索 设计 二分查找 动态规划】

LeetCode-1483. 树节点的第 K 个祖先【树 深度优先搜索 广度优先搜索 设计 二分查找 动态规划】 题目描述:解题思路一:暴力解法会超时!【一级一级往上跳,效率太低】解题思路二:倍增,利用二进制运算&#xf…

Python可视化之pandas

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档 文章目录 1.解决坐标轴刻度负号乱码2.解决中文乱码问题3.折线图Series.plot()&DataFrame.plot()4.条形图5.箱线图6.区域面积图(堆积折线图)7.散点…

UNITY实战进阶-BatchRendererGroup+Jobs+Burst+RVO2+GPUAnimation 实现万人团战(一)

研究思路:GPUAnimation把动画放入GPU中处理,BatchRendererGroup进行动态批量渲染处理,JobsBurst进行多线程处理逻辑(移动、攻击等),RVO2采用Jobs的寻路导航。 准备工作: Editor > Project S…

注意!今明两天广东等地仍有较强降雨

中央气象台监测显示 进入4月以来 我国江南、华南北部强降雨 接连而至 湖南、江西、浙江中南部 福建大部、广东中北部等地降雨量 较常年同期偏多1倍以上 上述地区部分国家观测站 日雨量突破4月历史极值 截至4月7日早晨 广东广州、惠州、清远 韶关、河源等地部分地区 …

填字母游戏【蓝桥杯】/博弈+dfs

填字母游戏 博弈dfs #include<iostream> #include<map> using namespace std; //要用map存储已经处理过的字符串不然会超时 map<string,int> m; //dfs返回的就是结果 int dfs(string s) {//剪枝if(m.find(s)!m.end()) return m[s];//找到LOL代表输了if(s.fi…

浅谈Redis和一些指令

浅浅谈一谈Redis的客户端 Redis客户端 Redis也是一个客户端/服务端结构的程序。 MySQL也是一个客户端/服务端结构的程序。 Redis的客户端也有多种形态 1.自带命令行客户端 redis-cli 2.图形化界面的客户端&#xff08;桌面程序&#xff0c;web程序&#xff09; 像这样的图形…

随机森林、AdaBoost 和 XGBoost 三者之间的主要区别

&#x1f349; CSDN 叶庭云&#xff1a;https://yetingyun.blog.csdn.net/ 集成学习是一种强大的机器学习范式&#xff0c;它通过构建并结合多个学习器来提高预测性能。其中&#xff0c;随机森林、AdaBoost 和 XGBoost 是集成学习领域中著名且广泛应用的方法。尽管这些方法共享…

C++ | Leetcode C++题解之第12题整数转罗马数字

题目&#xff1a; 题解&#xff1a; const string thousands[] {"", "M", "MM", "MMM"}; const string hundreds[] {"", "C", "CC", "CCC", "CD", "D", "DC&qu…

绕过断言的LFI-Assertion101

总结 getwebshell : 发现疑似LFI的地方 → 测试..过滤 → 尝试断言绕过 → 远程加载反弹shell → getwebshell 提 权 思 路 : suid文件发现 → aria2c远程下载ssh私钥覆盖/root/.ssh → ssh公钥登录提权 准备工作 启动VPN 获取攻击机IP → 192.168.45.218 启动靶机 获取目标…

邮件服务器:Postfix

文章目录 邮件服务器的功能与工作原理电子邮件的问题Mail server与DNS 之间的关系邮件传输所需要的组件(MTA、MUA、MDA)以及相关协议用户收信时服务器端所提供的相关协议&#xff1a;MRA电子邮件的数据内容 使用Postfix与Dovecot部署邮件系统部署基础的电子邮件系统配置Postfix…

山海鲸智慧农业可视化:开启农业现代化高效管理新时代

随着科技的不断进步&#xff0c;农业现代化已成为当今社会发展的重要趋势。在这一背景下&#xff0c;山海鲸智慧农业可视化解决方案应运而生&#xff0c;为农业生产带来了革命性的变革。它通过创新的可视化技术&#xff0c;将农业生产过程中的各个环节进行高效整合&#xff0c;…