VBM8脑结构像预处理实战:SPM8参数、批处理与质量检查
简介这是一份面向神经影像分析初学者与脑结构研究者的 VBM8 工具包需在 MATLAB 与 SPM8 环境下运行用于将 T1 图像归一化到模板空间并分割为灰质、白质和脑脊液。压缩包共 109 个文件约 13.8MB包含 39 个 .m 脚本、12 个 .c 源文件及多种平台的 mex 二进制文件另有 nii 示例数据、txt 说明、pdf 文档和少量 sh、map、h、man 等配置或辅助文件兼顾源码阅读与直接调用。已有 1173 人学习适合需要完成脑组织分割、预处理质量检查和平滑前准备的读者参考。包内还包含 VBM8 检查数据质量相关模块与分割、配准等实现素材可帮助理解预处理参数调整、样本同质性检查及灰质图像进入统计模型前的处理流程便于搭建可复现的脑结构分析环境。1. 拿到 VBM8 工具箱先搞清楚它替你把哪三件事干了一份 T1 结构像丢进去出来的是灰质、白质、脑脊液三张概率图外加一张把个体脑子拉到模板空间的形变场——这就是 VBM8 工具箱最核心的交付。它把 T1 图像归一化到模板空间、分割成 GM/WM/CSF 这两步绑在一个批处理模块里中间还夹着偏置场校正和 cleanup。适合手里有一批结构像、想做基于体素的形态学分析但不想自己拼 SPM 各模块的人。新手能靠图形界面跑通熟手关心的是参数怎么设、失败怎么查——这份资源两头都能接住。2. 环境搭起来MATLAB、SPM8 与 VBM8 的版本咬合VBM8 是个老工具箱它的运行依赖链是死的MATLAB 提供解释器SPM8 提供图像 IO、配准和统计底层VBM8 只在 SPM8 的 Batch Editor 里挂一个工具节点。这三者版本不咬合表现出来往往不是报错而是某些选项灰掉、或者跑到一半默默吐出空文件排查起来相当磨人。2.1 MATLAB 版本与 SPM8 的兼容边界SPM8 的官方支持窗口停在比较早的 MATLAB 版本上。我一般会先用一个不干活的窗口确认三件事MATLAB 能不能正常java起来Batch Editor 是 Java 界面、spm8.m能不能无警告跑完、spm(Ver)返回的是不是SPM8。这三步过了再谈 VBM8。% 环境自检MATLAB / SPM8 / VBM8 三层是否都活着 restoredefaultpath; % 先清干净避免旧路径里的 spm5/spm12 抢戏 addpath(D:\tools\spm8); % SPM8 根目录 addpath(genpath(D:\tools\vbm8)); % VBM8 整个目录树都要挂它有自己的子函数 spm_jobman(initcfg); % 初始化批处理配置少了这句后面 spm_jobman 会报错 fprintf(MATLAB : %s\n, version); % 看版本号心里有数 fprintf(SPM : %s\n, spm(Ver)); % 期望输出 SPM8 fprintf(VBM8 : %s\n, which(vbm8)); % 期望返回 vbm8.m 的完整路径restoredefaultpath这一步别省。很多人机器上同时装过多个 SPM 版本路径一叠加spm(Ver)返回的和你想的不是一个东西Batch Editor 里看到的 VBM8 节点也可能是另一个版本残留的。addpath(genpath(...))对 VBM8 是必须的因为它把估计、写图、DARTEL、质量检查拆成了多个子目录只挂根目录会缺函数。最后那三行打印是给眼睛看的版本号不对、路径为空从这里就能发现不用等到跑数据才翻车。提示自检脚本每次都从头跑一遍别依赖 MATLAB 的路径记忆。换机器、换盘符、升级过一次工具箱之后第一件事就是重跑这一段。2.2 VBM8 目录结构与路径挂载顺序VBM8 的目录组织不算规整粗略分三类vbm8.m及批处理定义在根下组织分割和形变的核心计算在子目录里模板和先验图在tpm一类的资源目录里。挂载顺序上SPM8 必须在 VBM8 之前进路径因为 VBM8 调用的是 SPM8 的spm_*函数反过来的话同名函数可能被 VBM8 目录里的旧副本覆盖。我习惯把这段写成一个setup_vbm8.m每个新会话先跑它function setup_vbm8(spm_root, vbm_root) % 统一入口清路径 - 挂 SPM8 - 挂 VBM8 - 自检 restoredefaultpath; addpath(spm_root); % 只挂 SPM8 根目录不 genpath避免子目录里的 demo 干扰 addpath(genpath(vbm_root)); % VBM8 必须整棵树挂上 spm_jobman(initcfg); assert(~isempty(which(spm)), SPM8 未挂上检查 spm_root); assert(~isempty(which(vbm8)), VBM8 未挂上检查 vbm_root); fprintf([OK] SPM%s VBM8%s\n, spm(Ver), which(vbm8)); end函数式写法的好处是可复用批处理脚本开头调一次交互式跑也调一次行为完全一致。assert两行是给自己留的后悔药——路径没挂对的时候后面任何一步都会以一种莫名其妙的方式失败与其那时候猜不如在这里直接停。注意 SPM8 我用的是addpath而不是genpath它子目录里有不少示例脚本和旧函数全挂进来容易和别的东西打架。2.3 用批处理跑通第一个被试图形界面配置一遍、导出.m、再改成脚本这是我对所有 SPM 系工具箱的固定套路VBM8 尤其适用。原因很实在VBM8 的批处理字段名在小版本之间会动硬背字段名抄别人的脚本十有八九撞上Reference to non-existent field。流程是这样在 MATLAB 命令行敲spm_jobman(interactive)或直接spm打开界面 → Batch Editor → SPM → Tools → VBM8 → 选Estimate and Write→ 指定一个被试的 T1 → 把参数按第 3 章的表配好 → 菜单里 File → Save Batch As存成vbm8_first.m。打开这个文件里面就是一个完整的matlabbatch结构体字段名一字不差地来自你机器上的版本。把它改造成可复用脚本主要是三处把被试路径抽成变量、把spm_jobman(run, ...)补上、把输出选项按分析目的固定下来。% vbm8_first.m —— 由 Batch Editor 导出后手工整理 setup_vbm8(D:\tools\spm8, D:\tools\vbm8); matlabbatch {}; % 被试文件名带 ,1 表示取第一帧4D 文件必须带3D 文件加了也无害 matlabbatch{1}.spm.tools.vbm8.estwrite.data {D:\vbm\sub-01\T1.nii,1}; % --- 估计阶段配准与偏置场 --- matlabbatch{1}.spm.tools.vbm8.estwrite.opts.affreg eastern; % 仿射正则模板 matlabbatch{1}.spm.tools.vbm8.estwrite.opts.biasfwhm 60; % 偏置场平滑宽度 mm matlabbatch{1}.spm.tools.vbm8.estwrite.opts.biasreg 0.001; % 偏置场正则强度 matlabbatch{1}.spm.tools.vbm8.estwrite.opts.warpreg 4; % 非线性形变正则 matlabbatch{1}.spm.tools.vbm8.estwrite.opts.samp 3; % 采样步长越小越慢越准 % --- 扩展选项形变方式与预处理开关 --- matlabbatch{1}.spm.tools.vbm8.estwrite.extopts.dartelwarp normalize; % 走 DARTEL 归一化 matlabbatch{1}.spm.tools.vbm8.estwrite.extopts.cleanup 1; % 去除残留的非脑组织 matlabbatch{1}.spm.tools.vbm8.estwrite.extopts.mrf 0.15; % 马尔可夫随机场权重 matlabbatch{1}.spm.tools.vbm8.estwrite.extopts.sanlm 1; % 去噪低信噪比数据建议开 % --- 输出阶段要哪些图 --- matlabbatch{1}.spm.tools.vbm8.estwrite.output.GM.native 1; % 原生空间灰质概率图 matlabbatch{1}.spm.tools.vbm8.estwrite.output.GM.mod 1; % 调制后的灰质做 VBM 统计用 matlabbatch{1}.spm.tools.vbm8.estwrite.output.GM.dartel 0; % DARTEL 中间产物不做自建模板就关 matlabbatch{1}.spm.tools.vbm8.estwrite.output.WM.native 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.WM.mod 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.CSF.native 0; % 只算总体积可以不要省时间省盘 matlabbatch{1}.spm.tools.vbm8.estwrite.output.bias.warped 1; % 校正后的图QC 必看 matlabbatch{1}.spm.tools.vbm8.estwrite.output.warps [1 0]; % 导出形变场供后续复用 spm_jobman(run, matlabbatch);几个参数值得单独说。affreg设为eastern是针对东亚人群颅型做的仿射正则用欧洲模板去做东亚脑子配准初值容易偏后面非线性形变再努力也拉不回来。biasfwhm的 60mm 是经验值对应偏置场的空间尺度扫描仪场强高、线圈不均匀明显的图像可以往上调到 7080但别超过 100否则会把真实的组织对比也一起抹平。samp控制估计时的采样密度3 是平衡点改成 2 精度略升、时间大约翻倍被试量大时我一般不动它。output.GM.dartel 1只在你要用自己的样本建 DARTEL 模板时才需要个体分析一律关掉否则每个被试多吐几张大文件磁盘很快就满。warps [1 0]导出的是把个体空间映射到模板空间的形变场第一次跑建议开着——后面想把 ROI 或者统计结果反投回个体空间全靠这个文件事后再补跑一遍是纯浪费。3. T1 归一化与组织分割estimate 与 write 的参数怎么设VBM8 的Estimate and Write表面是一个模块内部其实是两段estimate 段估计配准参数、偏置场和组织混合比例write 段按这些参数把结果写出来。两段的参数混在同一个界面里新手最容易犯的错是把 write 段的选项当成 estimate 段的来调结果图变了、配准没变白折腾。3.1 偏置场校正与 DARTEL 配准的选型理由为什么非要先做偏置场校正T1 图像的低频强度不均匀来自射频场和接收线圈同一个被试身上额叶和颞叶的灰度可能差出 20% 以上不校正的话灰质概率图会在亮的那一侧被系统性高估。VBM8 把偏置场建模成一个平滑的低频场和配准、分割放在一个生成模型里联合优化——这是它比先单独做偏置校正、再分割更稳的地方因为分割结果会反过来约束偏置场的估计。归一化这条路有两条可走标准流程和 DARTEL。标准流程用组织概率图直接驱动非线性配准速度快但对脑室大小、皮层折叠差异大的样本形变场容易过度扭曲。DARTEL 走的是微分同胚配准把形变建模成随时间演化的速度场保证形变可逆、不折叠对灰质边界的对齐明显更好。我的选择逻辑很简单被试量在几十例以上、要做组间比较就走 DARTEL只是单例看结构、或者做临床个体评估标准流程够用且省一半时间。DARTEL 的代价是流程变长——严格来说它分两步先 estimate 出组织图再用这些组织图建模板并归一化。VBM8 的dartelwarp normalize选项把这段串起来了你只需要跑一遍Estimate and Write它内部会调用预置的 DARTEL 模板完成归一化不用自己建模板。样本量特别大、或者研究对象比较特殊比如儿童、某种特定疾病人群才值得用Create Template模块自建模板。参数常见取值什么时候改affregeastern/mni东亚人群选eastern已有自己模板可选mnibiasfwhm60 mm高场强、线圈不均明显时调到 7080biasreg0.001偏置场估计过于激进、图像出现块状伪影时调大warpreg4形变过度扭曲时调大解剖差异极大时调小samp3追求精度改 2被试量大改 4dartelwarpnormalize/no组间比较走 DARTEL单例分析可关cleanup1regular颈部、眼球残留多时用 thorough耗时增加mrf0.15分割边界毛糙时微调一般不动3.2 estimate 段的关键参数怎么定estimate 段真正影响结果的是四个affreg、biasfwhm、warpreg、samp。前面说过前三个warpreg值得再展开。它控制非线性形变的平滑程度值越大形变越保守、越接近仿射值越小形变越自由。默认 4 对大多数成人数据合适如果被试里有明显脑萎缩或者脑室扩大形变需要更自由可以降到 2反过来如果发现配准后灰质被拉薄、统计图上出现沿着脑沟的条带状假阳性说明形变过头了调到 68。cleanup参数容易被忽略但它直接影响统计。组织分割完之后脑外会有一些被误判为灰质的小碎块——眼球周围、颈部肌肉、静脉窦附近比较常见。cleanup 用一个基于组织概率的去除算法把这些残留清掉强度分几档。regular 对多数数据够用如果被试头部摆位偏、扫描范围往下带到了脖子残留会明显增多这时候上 thorough代价是每个被试多花几分钟。注意cleanup 是写在 write 阶段的改了它必须重跑 writeestimate 的结果可以复用。批量处理时想让同一批数据换 cleanup 强度不用从头估一遍。3.3 write 段modulation 与 affine 的选择write 段决定输出什么样子的图其中 modulation 是 VBM 里最容易设错、也最影响结论的一项。调制的本质是补偿归一化把不同大小的脑子都塞进同一个模板空间局部体积会被拉伸或压缩。如果你的分析目的是局部灰质体积就必须把归一化时损失的体积信息乘回去这就是 modulation。如果目的是局部灰质浓度/密度那就不做调制。两者在统计结果上的差别不是一点点同一个数据集调不调制可以得出方向相反的结论。VBM8 里对应output.GM.mod这个开关取值通常是三个不调制、只做非线性调制、做非线性加仿射调制。做个类比只做非线性调制保留的是相对于全脑大小的局部体积再加上仿射调制保留的是绝对体积。前者适合排除整体头围差异的干扰后者适合关心绝对体积变化。我一般先跑只做非线性调制的版本因为它对整体脑体积差异更稳健需要时再补跑绝对体积版本。output.warps也要顺手开。很多人第一次跑完发现没有形变场文件后面想把组水平的激活簇反投回个体空间看解剖位置只能全部重跑一遍。这个文件不大开着不心疼。3.4 平滑核的取值与统计前提平滑是 VBM 流程的最后一环但 VBM8 本身不强制在模块里做很多人是在 SPM 的Smooth模块里单独跑。平滑核的选择有个基本约束要满足高斯随机场理论对统计推断的要求核宽得和预期的效应尺度匹配。8mm FWHM 是成人 VBM 的默认答案理由不玄学——它大致对应皮层厚度变化的尺度同时把残差的自相关拉到 GRF 能处理的范围。几个偏离场景关注海马、杏仁核这类小结构用 6mm再大就把结构自身的信号抹平了关注大范围皮层萎缩模式可以用 1012mm但要注意核宽超过 12mm 之后多重比较校正会变得非常保守本来有的效应也检不出来。还有一点常被忽略平滑核必须和你的分析设计一致。如果先平滑再做分割质量筛查出问题的被试在平滑图上会更难识别因为空间混叠把异常摊薄了。所以 QC 一定要在平滑之前做这个顺序错了后面全是血泪经验。4. 批处理化把几十上百个被试一次跑完单个被试跑通了真正的工程量在批量。手工一个个点三十个被试能耗掉一下午而且中途任何一次点错都不会有人提醒你。批处理化的目标不是少点几下而是让整批数据跑在同一个参数下、失败能被记录下来、跑完能一眼看出谁没出结果。4.1 目录约定与被试清单生成在写脚本之前先把目录结构定死。我用的约定是数据根目录下每个被试一个sub-XXX文件夹里面放一个命名为T1.nii的文件。这个约定看起来死板但它让后面所有脚本都能用一行dir把整批数据抓出来不用维护一张手写的路径表。root D:\vbm\raw; % 原始数据根目录 d dir(fullfile(root, sub-*)); % 只抓 sub- 开头的条目 d d([d.isdir]); % 去掉同名的非目录条目 subj {d.name}; % 被试 ID 列表 subj sort(subj); % 排序保证每次跑的顺序一致便于比对日志 % 逐个检查 T1 是否存在、是否可读缺文件的提前剔掉 keep false(size(subj)); for i 1:numel(subj) f fullfile(root, subj{i}, T1.nii); keep(i) exist(f, file) 2; if ~keep(i) fprintf([SKIP] %s 缺少 T1.nii\n, subj{i}); end end subj subj(keep); fprintf(待处理被试数%d\n, numel(subj));dir加通配符再过滤isdir比dir(root)之后手工排除.和..干净。排序这一步别嫌多余——MATLAB 的dir返回顺序在不同文件系统上不保证一致日志和结果文件对不上号的时候你会感谢当初加了这行。存在性检查是提前失败与其让spm_jobman跑到第三个被试才报文件不存在不如一开始就把缺文件的列出来人工确认一遍再开跑。4.2 循环里跑 matlabbatch并留好日志批量脚本的核心结构是模板 循环 替换数据字段。每次循环都重新构造一个matlabbatch只把data字段换掉。不要在循环外构造一次然后反复改同一个变量——spm_jobman内部可能修改这个结构体第二次循环拿到的就不是你最初写的那份了。setup_vbm8(D:\tools\spm8, D:\tools\vbm8); logf fullfile(root, run_log.txt); diary(logf); diary on; % 整个会话的屏幕输出同时写进日志 for i 1:numel(subj) t0 tic; inFile fullfile(root, subj{i}, T1.nii); fprintf(\n [%d/%d] %s \n, i, numel(subj), subj{i}); matlabbatch {}; matlabbatch{1}.spm.tools.vbm8.estwrite.data {[inFile ,1]}; matlabbatch{1}.spm.tools.vbm8.estwrite.opts.affreg eastern; matlabbatch{1}.spm.tools.vbm8.estwrite.opts.biasfwhm 60; matlabbatch{1}.spm.tools.vbm8.estwrite.opts.biasreg 0.001; matlabbatch{1}.spm.tools.vbm8.estwrite.opts.warpreg 4; matlabbatch{1}.spm.tools.vbm8.estwrite.opts.samp 3; matlabbatch{1}.spm.tools.vbm8.estwrite.extopts.dartelwarp normalize; matlabbatch{1}.spm.tools.vbm8.estwrite.extopts.cleanup 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.GM.native 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.GM.mod 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.WM.native 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.WM.mod 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.bias.warped 1; matlabbatch{1}.spm.tools.vbm8.estwrite.output.warps [1 0]; try spm_jobman(run, matlabbatch); fprintf([DONE] %s 用时 %.1f s\n, subj{i}, toc(t0)); catch ME % 单个被试失败不能中断整批记下来继续 fprintf([FAIL] %s : %s\n, subj{i}, ME.message); end clear matlabbatch; % 每个被试结束清一次控制内存峰值 end diary off;diary是 MATLAB 自带的重定向把命令行输出原样写进文本文件比自己在每处fprintf里拼文件句柄省事得多。try/catch那段是关键VBM8 在个别数据上会因为配准不收敛、内存不足之类的理由抛出异常没有这层保护整批数据在第 17 个被试那里停下前面 16 个的结果你还得自己数一遍谁跑完了。捕获之后记录消息继续下一个跑完统一处理失败名单。clear matlabbatch看着琐碎实际有用。VBM8 一次运行会加载大量图像数据MATLAB 的垃圾回收不一定及时循环几十次之后内存曲线会一路往上最后 trig 一个 out-of-memory。每轮清掉结构体能显著压低峰值。4.3 输出命名与后续统计的对接VBM8 的输出文件名带前缀前缀就是信息。搞清楚这套前缀后面接统计才不会选错文件前缀示例含义典型用途c1*原生空间灰质概率图算灰质总体积、做个体分割质控c2*/c3*原生空间白质 / 脑脊液概率图同上或算颅内体积做协变量mwc1*调制 归一化后的灰质图组水平 VBM 统计的输入wc1*只归一化、未调制的灰质图想看灰质浓度而非体积时用w*归一化后的原图 / 校正图QC 时叠在模板上看配准对不对这里有个实操细节VBM8 默认会把输出写在输入文件所在目录。批量跑的时候结果是散落在各个sub-XXX文件夹里的做统计时得自己遍历收集。我一般会在预处理跑完之后把需要的mwc1*统一拷到一个stats目录下并重命名成带被试 ID 的形式这样 SPM 的Specify 2nd-level里一拖就能全选也不会出现两个被试文件名撞车的情况。statDir fullfile(root, stats); if ~exist(statDir, dir); mkdir(statDir); end for i 1:numel(subj) srcDir fullfile(root, subj{i}); f spm_select(FPList, srcDir, ^mwc1.*\.nii$); % 只抓调制后的灰质图 if isempty(f) fprintf([MISS] %s 没有 mwc1 输出\n, subj{i}); continue; end f deblank(f(1, :)); % 多行结果取第一行并去尾空格 [~, n, e] fileparts(f); copyfile(f, fullfile(statDir, sprintf(%s_%s%s, subj{i}, n, e))); endspm_select(FPList, ...)是 SPM 自带的文件列举函数比dir好在返回的是完整路径且支持正则过滤。deblank(f(1,:))这行是防坑spm_select返回的是字符矩阵多行时按行取末尾还带空格直接拿去copyfile会报找不到文件这个报错信息非常误导人我第一次撞上时查了半小时。重命名时把被试 ID 放前面是为了在统计结果里一眼看出异常值对应的是谁。5. 避坑与排查分割结果不对劲时先看这五处VBM8 的失败方式分两种一种直接报错好处理另一种是安静地产出错误的图统计时才发现结果不对那才叫难受。下面五条是我在实际项目里撞得最多的按现象 → 原因 → 解决写清楚照着排查能省下大量时间。5.1 灰质白质分反了或者整张图糊成一片现象打开c1和c2发现本该是灰质的位置被标成了白质或者两张图都接近均匀的灰色看不出结构。原因仿射配准初值严重偏离。最常见的是affreg用了不匹配人群的模板其次是原始图像摆位问题——头没摆正、扫描野包含了大量颈部导致初始仿射把脑子转到了一个奇怪的角度。配准初值偏了后面的组织分割就完全建立在错误的解剖假设上。解决先看w或者bias.warped那张图叠到模板上的效果如果轮廓都对不上就别指望分割了。改affreg到匹配人群的选项摆位问题严重的数据建议在预处理前做一次前连合-后连合对齐或者直接重采样到标准方向。摆位实在改不了的把warpreg调小给它更多形变自由度但这只是补救不是正解。5.2 跑到一半 MATLAB 崩了或者报内存不足现象批处理跑到第 N 个被试时 MATLAB 无响应或者弹出内存相关的错误前面跑过的结果都还在。原因VBM8 单被试的峰值内存跟图像分辨率和samp有关samp调小内存会明显上涨另外批量循环里如果不清理工作区MATLAB 的内存会随着迭代缓慢累积。图像矩阵本身很大加上 DARTEL 形变场的中间变量单次峰值不容小看。解决循环里加clear清掉批处理结构体把samp从 2 放回 3 或者 4能分两批跑就分两批。还有一条经验别在同一个 MATLAB 会话里连续跑超过四五十个被试中间重启一次解释器比什么内存优化都管用。5.3 统计时被试数量对不上现象第二层统计模型建好发现被试数比预期少了一两个但预处理日志里没看到明显报错。原因单个被试在try/catch里失败了日志里记了[FAIL]但没人看或者某个被试的mwc1输出正常但文件被写到了非预期目录收集脚本没抓到。解决跑完立刻统计stats目录里的文件数和输入被试数比对不一致就顺着日志找[FAIL]和[MISS]行。这一步我一般写成脚本自动检查不靠人眼看日志——几十行日志里漏掉一行太正常了。5.4 平滑之后组间差异全没了现象统计模型的 design 看起来没问题但校正之后一个显著簇都没有连未校正的松散簇都很少。原因几个可能叠在一起。mod选项设错用未调制图做了体积分析个体间的整体脑体积差异盖过了局部效应平滑核过大把小尺度效应抹平或者样本里混了不同扫描协议的数据分割质量参差残差方差被撑得很大。解决先做样本同质性检查下一章讲把离群被试剔掉再看确认mod和你声称测量的量一致平滑核退回到 6mm 试一次。三件事逐一排除别一次改三个参数那样即使结果变好了你也不知道是哪一项起作用。5.5 cleanup 把真正的灰质也删了现象c1图里靠近皮层边缘、脑沟深处出现成片的空洞灰质体积明显偏低。原因cleanup 强度开得太高加上原图灰白质对比不足比如 T1 参数不理想去除算法把低概率的边缘灰质一并清掉了。解决把 cleanup 从 thorough 降回 regular 或 light只重跑 write 阶段。如果降了还不行说明问题在分割本身而不在 cleanup回头检查偏置场校正是否到位——biasfwhm设得过大偏置场估计不足灰白质对比会偏弱。这类数据我一般会先看bias.warped的直方图是不是双峰清晰不清晰就别往下走了。6. 质量检查怎么判断这批分割结果能不能用预处理脚本跑完、日志里全是[DONE]这时候最危险——看起来一切正常实际上可能有两三个被试的分割已经歪了。VBM8 自带两个质控工具加上自己写几行统计二十分钟能把一批数据摸清楚。第一个是切片浏览。VBM8 的Display one slice for all images模块会把所有被试的某一张切片按顺序拼成一张大图选冠状位或者轴位一眼扫过去就能看出谁的组织边界毛糙、谁的脑室形状不对。我一般选三个位置看侧脑室体部、基底节层面、小脑正中。这三个位置的形态差异最能暴露配准问题。第二个是样本同质性检查。VBM8 的Check sample homogeneity using covariance会计算所有被试组织图两两之间的协方差画成散点或者矩阵离群被试会明显偏离主体。这个方法比肉眼看切片灵敏但需要样本量在十几个以上才有意义。再补一个自己写的指标每个被试的灰质总量。调制后的mwc1求和得到的就是归一化之后的总灰质体积理论上所有被试应该落在相近的区间里偏离均值太远的就要人工看一眼。% 灰质总量离群检测对 stats 目录下的 mwc1 逐个求和 statDir fullfile(root, stats); files cellstr(spm_select(FPList, statDir, ^.*mwc1.*\.nii$)); vol zeros(numel(files), 1); for i 1:numel(files) V spm_vol(files{i}); Y spm_read_vols(V); % 读入整个 3D 矩阵 vol(i) sum(Y(:)) * abs(det(V.mat(1:3,1:3))); % 概率和 × 体素体积 总体积 end z (vol - median(vol)) / mad(vol, 1); % 用中位数和 MAD比均值/标准差抗离群 bad find(abs(z) 3); fprintf(样本量 %d灰质体积中位数 %.1f ml\n, numel(files), median(vol)/1000); for i 1:numel(bad) fprintf([离群] %s z%.2f 体积%.1f ml\n, files{bad(i)}, z(bad(i)), vol(bad(i))/1000); end这段的关键在最后两行之前的统计量选择。用均值和标准差算 z 分数离群点自己会把均值和标准差带偏导致该被抓的抓不出来——这就是经典的掩蔽效应。换成中位数和绝对中位差MAD对离群点不敏感判据更稳。abs(det(V.mat(1:3,1:3)))算的是单个体素的实际体积归一化之后所有被试体素大小一致但在做原生空间统计时这一步不能省否则不同层厚的数据没法比。阈值 3 是个经验值样本量小的时候可以放到 2.5 更保守一点。三类检查的结论要合起来看不能只信一个检查项看什么判定切片浏览脑室形态、皮层边界明显不对称或边界糊直接剔除协方差同质性离群点在散点图上的位置偏离主体一个身位以上人工复核灰质总量 z 分数与中位数的偏离程度绝对值超 3必须看图确认有一次我图省事只跑了灰质总量检查指标全绿就往下做统计结果组水平结果里出现一个巨大的簇位置在两个被试之间反复横跳。回头一看切片图那两个被试的 cleanup 把颞叶内侧削掉了一大块总量上补不回来局部却塌了。从那以后我每跑完一批 VBM都强制走一遍切片浏览 协方差 总量三道关任何一个不过就先停下来看图不往下推进。希望帮到你。本文还有配套的精品资源点击获取