【医学图像处理】超详细!PET图像批量预处理

news2024/9/28 9:29:10

目录

  • 一、单个PET图像预处理
    • 1、使用[MRIConvert](https://pan.baidu.com/s/1cn3kgeVRir8HvP6HHm0M0Q?pwd=5rt5)处理DCM
    • 2、MRI和PET数据预处理过程
      • 1) 打开matlab命令行输入spm pet,打开SMP12,界面如下
      • 2) Realign,只需要编辑Session,其他参数不用改,编辑好后点击左上角绿色三角形按钮:
      • 3)将mean002_s_0729的hdr数据配到PET模板上,点击Normalise(Est & Wri)
      • 4)将wmeanxxxx.hdr配准到自己的MRI图像wmxxxx.nii上,打开Coregister(Est & Res),只修改Reference Image和Source Image;
      • 5)去头颅
      • 6)最后一步进行8mm的平滑
  • 二、批量预处理
    • 1、点击Batch
    • 2、转到工作路径
    • 3、选择预处理步骤
    • 4、生成batch脚本
    • 5、修改脚本代码

最近在做PET图像的预处理,相对于SMRI,PET的预处理要更加复杂,PET的预处理需要一步一步进行,每一步都需要前一步的输出结果,因此在批量预处理上也很麻烦。不过在和实验室小伙伴的共同努力下最终是完成了PET批量预处理。
自己在网上搜索教程的时候也没有找到很符合自己需要的教程,因此,把该问题的解决方法记录下来,供大家一起参考,如果觉得有用的话麻烦点个赞谢谢。

注:本方法使用的数据是从ADNI上下载的18F-FDG图像,下载的格式是DCM格式(PET图像会有其他格式的图像,我只使用了DCM格式的图像)环境使用了MATLABR2021a SPM12

一、单个PET图像预处理

为了更好理解批量预处理,有必要了解单个PET图像是如何预处理的。只想看批量预处理的直接跳到批量预处理即可
PET预处理整个流程如下:使用MRIConvert软件将DCM格式转为hdr格式→Realign→Normalise→Coregister→ImCalc→Smooth

1、使用MRIConvert处理DCM

打开程序选择输出输入目录并且选择SPM Analyze如下图所示
在这里插入图片描述
转换完成后输出如下:

这里生成了多个hdr/img的图像,只需要选择其中最好的一个即可(我看起来都是一样的)

在这里插入图片描述
使用MRIcron打开hdr文件如下:MRIcron在我的之前的文章有介绍
在这里插入图片描述

2、MRI和PET数据预处理过程

1) 打开matlab命令行输入spm pet,打开SMP12,界面如下

在这里插入图片描述

2) Realign,只需要编辑Session,其他参数不用改,编辑好后点击左上角绿色三角形按钮:

在这里插入图片描述
在这里插入图片描述
此时在输出目录下生成如下文件:
在这里插入图片描述

3)将mean002_s_0729的hdr数据配到PET模板上,点击Normalise(Est & Wri)

在这里插入图片描述
弹出以下窗口,只需编辑Source Image, Images to Write和Template Image;其他参数不动,最后点击左上角蓝色三角形运行
在这里插入图片描述
生成如下文件:
在这里插入图片描述
点开wmeanxxxx.hdr如下:
在这里插入图片描述

4)将wmeanxxxx.hdr配准到自己的MRI图像wmxxxx.nii上,打开Coregister(Est & Res),只修改Reference Image和Source Image;

注意:如果只需要处理PET图像,MRI可以使用模板来进行配准和去头骨影像(这里是配准到同一患者的SMRI预处理后的图像 wmxxxx.nii是SMRI预处理后的图像)
在这里插入图片描述
在这里插入图片描述
生成如下文件:
在这里插入图片描述
此时的PET与MRI大小相同
在这里插入图片描述

5)去头颅

点击ImCalc
在这里插入图片描述
弹出如下界面,Input Images先选择MRI的图像,即wmxxxx.nii(也可以选MRI模板),再选rwmeanxxxx.img,Expression输入i2.*(i1>0.05),其中i1表示第一张图像,i2表示第二张,运行后会在matlab的当前路径输出结果,我这里是PETprocess\processing,所以在下面会生成output图像。
在这里插入图片描述
在这里插入图片描述
打开output图像如下:
在这里插入图片描述

6)最后一步进行8mm的平滑

在这里插入图片描述
在这里插入图片描述
最后得到的图像如下:
在这里插入图片描述
这便是PET预处理后的图像,到此整个PET预处理流程已经走完,做完后发现这也太复杂了,如果要处理几百张图像人估计都没了。。。所以接下来的才是重头戏,批量预处理。

二、批量预处理

我这里的方法是使用SPM12自带的batch工具选择需要的步骤之后生成脚本文件,然后根据实际情况修改脚本完成批量预处理!

1、点击Batch

在这里插入图片描述

2、转到工作路径

在这里插入图片描述
在这里插入图片描述

3、选择预处理步骤

在这里插入图片描述
选择后要点一下要输入数据的地方不然可能会报错,如下图双击Data然后回多出一行Session这样就不会有问题了
在这里插入图片描述
依次选择所有步骤如下一共5个步骤:
在这里插入图片描述
注意在Image Calculator的Expression输入是固定的因此可以直接在这里输入如下:

在这里插入图片描述

4、生成batch脚本

在这里插入图片描述
选择保存脚本的路径
在这里插入图片描述
点击保存后,会生成两个.m文件并且自动在matlab打开脚本文件如下:
在这里插入图片描述
在这里插入图片描述
这里生成的只是模板文件,图像的输入输出还有一些细节是需要我们手动修改实现的。

5、修改脚本代码

1、xxx.m文件代码如下(xxx是你自己的命名)

% List of open inputs
% Realign: Estimate & Reslice: Session - cfg_files
% Normalise: Estimate & Write: Image to Align - cfg_files
% Normalise: Estimate & Write: Images to Write - cfg_files
% Coregister: Estimate & Reslice: Reference Image - cfg_files
% Coregister: Estimate & Reslice: Source Image - cfg_files
% Image Calculator: Input Images - cfg_files
% Smooth: Images to smooth - cfg_files


% 设置MRI文件夹路径
mri_folder = 'E:\ADNI\PETprocess\processing\batch\SMRI';

% 设置PET文件夹路径和待处理的图像数量
pet_folder = 'E:\ADNI\PETprocess\processing\batch\PET';
% 读取PET文件夹中的图像文件名列表
pet_files = dir(fullfile(pet_folder, '*.img'));
numFiles = length(pet_files);
pet_filenames = {pet_files.name};
nrun = numFiles; % 请将X替换为实际的图像数量
jobfile = {'E:\ADNI\PETprocess\processing\xxx_job.m'}; %注意这里要对应
jobs = repmat(jobfile, 1, nrun);

% 循环处理每个PET图像
for crun = 1:nrun
    output_path = 'E:\ADNI\PETprocess\processing\batch\output\AD'; % 数据结果的目录,job文件也要添加这个路径
    subjectID = strrep(pet_filenames{crun}, '.img', ''); % 获取当前处理的图像文件名(不含扩展名)
    % Realign: Estimate & Reslice
    inputs{1, crun} = cellstr(fullfile(pet_folder, pet_filenames{crun})); % 输入待处理的PET图像
    % Normalise: Estimate & Write
    inputs{2, crun} = cellstr(fullfile(pet_folder, ['mean', subjectID, '.img'])); % 输入mean图像
    inputs{3, crun} = cellstr(fullfile(pet_folder, ['mean', subjectID, '.img'])); % 输入mean图像
    % Coregister: Estimate & Reslice
    inputs{4, crun} = cellstr(fullfile(mri_folder, [subjectID, '.nii'])); % MRI参考图像
    inputs{5, crun} = cellstr(fullfile(pet_folder, ['wmean', subjectID, '.img'])); % 输入rwmean图像
    % Image Calculator
    i1 = fullfile(mri_folder, [subjectID, '.nii']);
    i2 = fullfile(pet_folder, ['rwmean' subjectID, '.img']);
    inputs{6, crun} = [cellstr(i1); cellstr(i2)]; % 将i1和i2组合成一个cell数组,然后赋值给inputs{6, crun}
    inputs{7, crun} = [subjectID, '.nii'];
    
    % Smooth
    inputs{8, crun} = cellstr(fullfile(output_path, [subjectID, '.nii']));  % 输入文件为subjectID.nii图像
end
% 加载SPM默认设置和运行处理任务
spm('defaults', 'PET');
spm_jobman('run', jobs, inputs{:});

2、xxx_job.m文件代码如下(xxx是你自己的命名)

%-----------------------------------------------------------------------
% Job saved on 20-Nov-2023 19:01:02 by cfg_util (rev $Rev: 7345 $)
% spm SPM - SPM12 (7771)
% cfg_basicio BasicIO - Unknown
%-----------------------------------------------------------------------
matlabbatch{1}.cfg_basicio.file_dir.dir_ops.cfg_cd.dir = {'D:\matlabR2021a\matlabR2021a\bin'};
matlabbatch{2}.spm.spatial.realign.estwrite.data = {'<UNDEFINED>'};
matlabbatch{2}.spm.spatial.realign.estwrite.eoptions.quality = 0.9;
matlabbatch{2}.spm.spatial.realign.estwrite.eoptions.sep = 4;
matlabbatch{2}.spm.spatial.realign.estwrite.eoptions.fwhm = 5;
matlabbatch{2}.spm.spatial.realign.estwrite.eoptions.rtm = 1;
matlabbatch{2}.spm.spatial.realign.estwrite.eoptions.interp = 2;
matlabbatch{2}.spm.spatial.realign.estwrite.eoptions.wrap = [0 0 0];
matlabbatch{2}.spm.spatial.realign.estwrite.eoptions.weight = '';
matlabbatch{2}.spm.spatial.realign.estwrite.roptions.which = [2 1];
matlabbatch{2}.spm.spatial.realign.estwrite.roptions.interp = 4;
matlabbatch{2}.spm.spatial.realign.estwrite.roptions.wrap = [0 0 0];
matlabbatch{2}.spm.spatial.realign.estwrite.roptions.mask = 1;
matlabbatch{2}.spm.spatial.realign.estwrite.roptions.prefix = 'r';
matlabbatch{3}.spm.spatial.normalise.estwrite.subj.vol = '<UNDEFINED>';
matlabbatch{3}.spm.spatial.normalise.estwrite.subj.resample = '<UNDEFINED>';
matlabbatch{3}.spm.spatial.normalise.estwrite.eoptions.biasreg = 0.0001;
matlabbatch{3}.spm.spatial.normalise.estwrite.eoptions.biasfwhm = 60;
matlabbatch{3}.spm.spatial.normalise.estwrite.eoptions.tpm = {'D:\matlabR2021a\matlabR2021a\toolbox\spm12\spm12\tpm\TPM.nii'};
matlabbatch{3}.spm.spatial.normalise.estwrite.eoptions.affreg = 'mni';
matlabbatch{3}.spm.spatial.normalise.estwrite.eoptions.reg = [0 0.001 0.5 0.05 0.2];
matlabbatch{3}.spm.spatial.normalise.estwrite.eoptions.fwhm = 0;
matlabbatch{3}.spm.spatial.normalise.estwrite.eoptions.samp = 3;
matlabbatch{3}.spm.spatial.normalise.estwrite.woptions.bb = [-78 -112 -70
                                                             78 76 85];
matlabbatch{3}.spm.spatial.normalise.estwrite.woptions.vox = [2 2 2];
matlabbatch{3}.spm.spatial.normalise.estwrite.woptions.interp = 4;
matlabbatch{3}.spm.spatial.normalise.estwrite.woptions.prefix = 'w';
matlabbatch{4}.spm.spatial.coreg.estwrite.ref = '<UNDEFINED>';
matlabbatch{4}.spm.spatial.coreg.estwrite.source = '<UNDEFINED>';
matlabbatch{4}.spm.spatial.coreg.estwrite.other = {''};
matlabbatch{4}.spm.spatial.coreg.estwrite.eoptions.cost_fun = 'nmi';
matlabbatch{4}.spm.spatial.coreg.estwrite.eoptions.sep = [4 2];
matlabbatch{4}.spm.spatial.coreg.estwrite.eoptions.tol = [0.02 0.02 0.02 0.001 0.001 0.001 0.01 0.01 0.01 0.001 0.001 0.001];
matlabbatch{4}.spm.spatial.coreg.estwrite.eoptions.fwhm = [7 7];
matlabbatch{4}.spm.spatial.coreg.estwrite.roptions.interp = 4;
matlabbatch{4}.spm.spatial.coreg.estwrite.roptions.wrap = [0 0 0];
matlabbatch{4}.spm.spatial.coreg.estwrite.roptions.mask = 0;
matlabbatch{4}.spm.spatial.coreg.estwrite.roptions.prefix = 'r';
matlabbatch{5}.spm.util.imcalc.input = '<UNDEFINED>';
matlabbatch{5}.spm.util.imcalc.output = '<UNDEFINED>'; %这里要改
matlabbatch{5}.spm.util.imcalc.outdir = {'E:\ADNI\PETprocess\processing\batch\output\AD'}; %改成你自己的目录
matlabbatch{5}.spm.util.imcalc.expression = 'i2.*(i1>0.05)';
matlabbatch{5}.spm.util.imcalc.var = struct('name', {}, 'value', {});
matlabbatch{5}.spm.util.imcalc.options.dmtx = 0;
matlabbatch{5}.spm.util.imcalc.options.mask = 0;
matlabbatch{5}.spm.util.imcalc.options.interp = 1;
matlabbatch{5}.spm.util.imcalc.options.dtype = 4;
matlabbatch{6}.spm.spatial.smooth.data = '<UNDEFINED>';
matlabbatch{6}.spm.spatial.smooth.fwhm = [8 8 8];
matlabbatch{6}.spm.spatial.smooth.dtype = 0;
matlabbatch{6}.spm.spatial.smooth.im = 0;
matlabbatch{6}.spm.spatial.smooth.prefix = 's';

修完成后运行xxx.m即可

注:job.m大部分代码是自动生成的,如果你完全按照我的步骤运行代码后报错如下:
在这里插入图片描述
这大概率是job文件的错误,请仔细对照job文件是不是该有<UNDEFINED>地方没有<UNDEFINED>,上面步骤说要点击一下输入文件的地方就是为了防止这里不生成<UNDEFINED>。

OVER(点赞)!

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

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

相关文章

分布式锁之基于zookeeper实现分布式锁(三)

3. 基于zookeeper实现分布式锁 实现分布式锁目前有三种流行方案&#xff0c;分别为基于数据库、Redis、Zookeeper的方案。这里主要介绍基于zk怎么实现分布式锁。在实现分布式锁之前&#xff0c;先回顾zookeeper的相关知识点 3.1. 知识点回顾 3.1.1. 安装启动 安装&#xff1a…

面试送分题!“商品分类浏览”如何测试?

电商项目无论是工作中&#xff0c;还是面试中&#xff0c;都是一个高频出现的词。 面试官非常热衷提问关于电商项目的问题。例如商品分类怎么测试&#xff1f;购物车怎么测试&#xff1f;订单怎么测试&#xff1f;优惠券怎么测试&#xff1f;支付怎么测试&#xff1f;等等。 …

linux通过串口传输文件

简介 在嵌入式调试过程中&#xff0c;我们经常会使用调试串口来查看Log或者执行指令&#xff0c;其实&#xff0c;调试串口还有另一种功能&#xff0c;就是传输文件&#xff0c;本文说明使用MobaXterm串口工具来传输文件。 环境要求 嵌入式系统需要安装lsz和lrz&#xff0c;…

汲古融新,字有乾坤—字体设计商业项目实践

《字迹&#xff1a;字体设计商业项目实践》主要内容为商业字体设计&#xff0c;对于字体设计的理论知识进行透彻讲解&#xff0c;并配以详尽的设计案例。全书包含6章&#xff1a;第1章为字体设计基础知识&#xff0c;以梳理字体设计理论知识为主要内容&#xff1b;第2章为字体设…

01-详细介绍函数式接口和Lambda表达式语法

函数式接口介绍 如果在一个接口中只声明了一个抽象方法,则此接口就被称为函数式接口(该接口可以包含其他非抽象方法) 接口上使用FunctionalInterface注解可以验证该接口是否为函数式接口,javadoc生成的文档时也会保留该注解, 若接口中有多个抽象方法编译器会报错 随着Python…

一文详解Vue生命周期

Vue是一种流行的用于构建用户界面的渐进式JavaScript框架。Vue框架在开发过程中&#xff0c;特别强调对生命周期的理解和管理。通过使用生命周期钩子函数&#xff0c;开发者能够精确地控制Vue实例的创建、挂载、更新以及销毁过程。本文将对Vue的生命周期进行详细的介绍&#xf…

航天博物馆3D虚拟交互展厅让大众对科技发展有更深切的理解和感受

博物馆作为人们了解历史、文化和艺术的重要场所&#xff0c;现在可以通过VR全景技术来进行展览&#xff0c;让参观者身临其境地感受历史文化的魅力。本文将介绍博物馆VR全景的特点、优势&#xff0c;以及如何使用VR全景技术来使得博物馆的展览和教育活动更丰富。 VR数字博物馆…

2023年“福建省工业互联网+智能制造创新大赛”开启报名

11月22日&#xff0c;由福建省总工会、福建省大数据集团有限公司共同举办的2023年“福建省工业互联网智能制造创新大赛”启动报名。 大赛积极响应《福建省总工会等八部门关于广泛深入开展劳动和技能竞赛为新发展阶段新福建建设建工立业的意见》&#xff08;闽工〔2022〕70号&am…

String 真的不可变吗?

为什么 String 类不可变 final修饰符&#xff1a; String类被声明为final&#xff0c;这意味着它不能被继承。因此&#xff0c;无法创建String的子类来修改其行为。私有字符数组&#xff08;char[]&#xff09;&#xff1a; String类内部使用私有的字符数组来存储字符串的内容…

最优化理论

最优化理论 资料一optimal condition 最优性条件概念 二一维搜索逐次下降法iterative decent单峰函数二分法 dichotomous search 三 资料 B站最优化理论与算法 上交最优化方法 一 目标函数&#xff1a;需要优化的函数 决策变量&#xff0c;可以调整变化的量 约束集&#xff…

GitHub上8个强烈推荐的 Python 项目

文章目录 前言1. Manim2. DeepFaceLab3. Airflow4. GPT-25. XSStrike6. 谷歌图片下载7. Gensim8. SocialMapper总结关于Python技术储备一、Python所有方向的学习路线二、Python基础学习视频三、精品Python学习书籍四、Python工具包项目源码合集①Python工具包②Python实战案例③…

【Linux】 id命令使用

id id命令来显示用户的UID、组GID。 著者 由阿诺德罗宾斯和大卫麦肯齐撰写。 语法 id [参数] [用户名] id命令 -Linux手册页 命令选项及作用 执行令 id --help 执行命令结果 参数 -g 或 --group  显示用户所属群组的ID。-G 或 --groups  显示用户所属附加群组的ID。…

微信报名怎么做_轻松便捷的数字化报名体验

微信报名&#xff1a;轻松便捷的数字化报名体验 在这个数字化时代&#xff0c;微信已经成为我们生活中不可或缺的一部分。它不仅仅是一个社交平台&#xff0c;更是一个功能强大的综合性工具。其中&#xff0c;微信报名功能更是给我们的生活带来了极大的便利。本文将详细介绍微…

11-23 SSM4

Ajax 同步请求 &#xff1a;全局刷新的方式 -> synchronous请求 客户端发一个请求&#xff0c;服务器响应之后你客户端才能继续后续操作&#xff0c;请求二响应完之后才能发送后续的请求&#xff0c;依次类推 有点&#xff1a;服务器负载较小&#xff0c;但是由于服务器相应…

SpringBoot——启动类的原理

优质博文&#xff1a;IT-BLOG-CN SpringBoot启动类上使用SpringBootApplication注解&#xff0c;该注解是一个组合注解&#xff0c;包含多个其它注解。和类定义SpringApplication.run要揭开SpringBoot的神秘面纱&#xff0c;我们要从这两位开始就可以了。 SpringBootApplicati…

dxva2+ffmpeg硬件解码(Windows)终结发布

《dxva2超低延迟视频播放器》演示demo下载URL&#xff1a; 【免费】dxva2硬解码超低延迟网络本地播放器资源-CSDN文库 本地播放 截图&#xff1a; rtsp播放截图&#xff08;推送内容为本地桌面&#xff0c;所以是这样的&#xff09; OK&#xff0c;进入主题&#xff1a; 前前…

拼多多商品详情数据接口(Pinduoduo.item_get)

拼多多商品详情数据接口是一种程序化的接口&#xff0c;通过这个接口&#xff0c;商家或开发者可以使用自己的编程技能&#xff0c;对拼多多平台上的商品信息进行查询、获取和更新。这个接口允许商家根据自身的需求&#xff0c;获取商品的详细信息&#xff0c;例如价格、库存、…

交通管理中的利器:揭秘交通监控大屏的优势和应用场景

交通监控大屏是一种用于监控交通情况的大屏展示方式&#xff0c;能够实时展示交通状况、车流量、车速等数据&#xff0c;为交通管理提供数据支持和决策参考。本文将介绍交通监控大屏的优势、应用场景和未来发展趋势。 一、交通监控大屏的优势 交通监控大屏的主要优势包括&…

【double check 读写锁】

使用double check 读写锁 读多写少场景 记录下 //来源 jdbc 中的查询连接信息 //public abstract class ConnectionUrl implements DatabaseUrlContainer public static ConnectionUrl getConnectionUrlInstance(String connString, Properties info) {if (connString null…