基于 Docker + FreeSurfer 6.0 的 T1 结构像预处理流程文档
一、流程目的本流程用于将本地 T1 结构像数据通过 Docker 环境中的 FreeSurfer 6.0 进行结构像预处理生成后续 braincharts 常模分析所需的皮层厚度和皮层下体积指标。整体流程如下Windows 本地 T1 数据 → Docker 挂载数据目录 → FreeSurfer 6.0 recon-all → 生成 subjects/sub-xxx 结果目录 → 提取 aparc.a2009s 皮层厚度 → 提取 aseg 皮层下体积 → 整理为后续 braincharts 常模输入表二、本地文件夹结构建议在 Windows 本地构建如下目录E:\freesurfer\ │ ├── license.txt │ ├── data\ │ ├── 001.nii │ ├── 002.nii │ ├── 003.nii │ └── ... │ ├── subjects\ │ └── scripts\各文件夹含义如下license.txt FreeSurfer 官方授权文件 data 存放原始 T1 NIfTI 文件建议只读挂载 subjects 存放 FreeSurfer 输出结果可写挂载 scripts 存放 PowerShell 批处理脚本建议原始图像文件名尽量简单避免中文、空格和特殊符号。例如001.nii 002.nii 003.nii也可以使用 BIDS 风格命名sub-001_T1w.nii sub-002_T1w.nii sub-003_T1w.nii三、Docker 与 FreeSurfer 镜像准备1. 检查 Docker 是否可用在 Windows PowerShell 中运行docker --version测试 Dockerdocker run hello-world如果能正常输出测试信息说明 Docker Desktop 可以正常使用。2. 拉取 FreeSurfer 6.0 镜像由于 Rutherford et al. 2022 braincharts 常模使用 FreeSurfer 6.0 输出指标建议使用 FreeSurfer 6.0 镜像docker pull freesurfer/freesurfer:6.0查看镜像是否存在docker images应能看到freesurfer/freesurfer 6.0四、FreeSurfer license 挂载方式FreeSurfer 6.0 容器中部分程序会默认查找/opt/freesurfer/license.txt因此推荐直接将 Windows 本地 license 挂载到该位置-v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro不推荐只挂载到/license.txt因为 FreeSurfer 6.0 中的mri_convert可能仍然去查找/opt/freesurfer/license.txt从而报错ERROR: FreeSurfer license file /opt/freesurfer/license.txt not found.五、进入容器进行环境检查在 PowerShell 中运行docker run --rm -it -v E:\freesurfer\data:/data:ro -v E:\freesurfer\subjects:/subjects -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects freesurfer/freesurfer:6.0 bash进入容器后终端提示符类似rootxxxx:/#在容器内检查文件是否挂载成功ls /data ls -l /opt/freesurfer/license.txt echo $SUBJECTS_DIR recon-all -version正常情况下应看到/data 中存在 001.nii /opt/freesurfer/license.txt 存在 SUBJECTS_DIR/subjects FreeSurfer 版本为 6.0.0退出容器exit注意docker run命令必须在 Windows PowerShell 中运行不能在容器内部运行。容器内部只运行ls、recon-all、aparcstats2table等 Linux/FreeSurfer 命令。六、单个被试的 FreeSurfer 预处理1. 直接运行单个被试假设原始 T1 文件为E:\freesurfer\data\001.nii对应容器内路径为/data/001.nii输出被试名设为sub-001在 PowerShell 中运行docker run --rm -it -v E:\freesurfer\data:/data:ro -v E:\freesurfer\subjects:/subjects -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects freesurfer/freesurfer:6.0 recon-all -i /data/001.nii -s sub-001 -all -openmp 4参数说明-v E:\freesurfer\data:/data:ro 将原始 T1 数据目录挂载到容器 /data并设置为只读。 -v E:\freesurfer\subjects:/subjects 将 FreeSurfer 输出目录挂载到容器 /subjects。 -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro 将 license 文件挂载到 FreeSurfer 默认查找位置。 -e SUBJECTS_DIR/subjects 设置 FreeSurfer 输出目录。 recon-all -i /data/001.nii -s sub-001 -all -openmp 4 对 001.nii 运行完整 FreeSurfer 结构像处理流程输出被试名为 sub-001使用 4 个线程。2. 运行时间单个 T1 的完整recon-all -all通常需要较长时间高性能服务器约 3–8 小时 普通笔记本或 Windows Docker/WSL2约 6–15 小时 硬盘较慢或内存较低可能超过 15 小时运行过程中终端会持续输出迭代信息例如rms... blurring input image with Gaussian... setting smoothness coefficient...这属于正常运行信息不是报错。七、FreeSurfer 运行过程中生成的文件运行开始后会在 Windows 本地生成E:\freesurfer\subjects\sub-001\典型结构如下E:\freesurfer\subjects\sub-001\ │ ├── label\ ├── mri\ ├── scripts\ ├── stats\ ├── surf\ ├── tmp\ ├── touch\ └── trash\其中比较重要的目录包括mri 存放体积图像、中间分割结果和归一化结果 surf 存放皮层表面重建结果 stats 存放统计指标是后续提表最重要的目录 scripts 存放运行日志和命令记录运行日志文件为E:\freesurfer\subjects\sub-001\scripts\recon-all.log可以在 VS Code 中直接打开查看也可以另开 PowerShell 实时查看Get-Content E:\freesurfer\subjects\sub-001\scripts\recon-all.log -Tail 30 -Wait八、运行完成后的关键文件当recon-all成功结束后应出现以下关键文件E:\freesurfer\subjects\sub-001\stats\aseg.stats E:\freesurfer\subjects\sub-001\stats\lh.aparc.a2009s.stats E:\freesurfer\subjects\sub-001\stats\rh.aparc.a2009s.stats这些文件分别对应aseg.stats 皮层下结构体积统计如丘脑、尾状核、壳核、海马、杏仁核、脑室等。 lh.aparc.a2009s.stats 左半球 Destrieux atlas 皮层分区统计。 rh.aparc.a2009s.stats 右半球 Destrieux atlas 皮层分区统计。后续 braincharts 常模所需的主要指标来自这些文件。九、文件转换说明1. .nii 与 .nii.gz原始数据为.nii格式可以直接输入 FreeSurferrecon-all -i /data/001.nii -s sub-001 -all不需要强制转换为.nii.gz。.nii.gz只是 gzip 压缩后的 NIfTI 文件图像内容与.nii一致。不要直接通过重命名把.nii改成.nii.gz。错误做法Rename-Item 001.nii 001.nii.gz正确压缩方式gzip -k 001.nii或者在 FreeSurfer 容器内使用mri_convert /data/001.nii /subjects/001_T1w.nii.gz但对于当前流程原始.nii可以直接使用不需要额外转换。2. FreeSurfer 内部转换运行recon-all后FreeSurfer 会自动将输入 NIfTI 转换为内部 MGZ 格式例如/subjects/sub-001/mri/orig/001.mgz对应 Windows 路径为E:\freesurfer\subjects\sub-001\mri\orig\001.mgz这一步由 FreeSurfer 自动完成不需要手动操作。十、失败重跑的处理方式如果第一次运行由于 license、路径或其他错误失败可能已经生成不完整目录E:\freesurfer\subjects\sub-001此时再次运行recon-all -i /data/001.nii -s sub-001 -all可能报错ERROR: You are trying to re-run an existing subject with new input data (-i).如果确认之前结果是不完整的应先删除该 subject 目录Remove-Item -Recurse -Force E:\freesurfer\subjects\sub-001然后重新运行docker run --rm -it -v E:\freesurfer\data:/data:ro -v E:\freesurfer\subjects:/subjects -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects freesurfer/freesurfer:6.0 recon-all -i /data/001.nii -s sub-001 -all -openmp 4如果只是中途中断且希望继续同一个 subject不应再加-i可以尝试docker run --rm -it -v E:\freesurfer\data:/data:ro -v E:\freesurfer\subjects:/subjects -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects freesurfer/freesurfer:6.0 recon-all -s sub-001 -all -openmp 4但如果是 license 或路径错误导致早期失败建议删除后重跑更稳妥。十一、单被试运行脚本建议在E:\freesurfer\scripts\中新建脚本run_sub001.ps1内容如下docker run --rm -it -v E:\freesurfer\data:/data:ro -v E:\freesurfer\subjects:/subjects -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects freesurfer/freesurfer:6.0 recon-all -i /data/001.nii -s sub-001 -all -openmp 4运行方式cd E:\freesurfer\scripts .\run_sub001.ps1如果 PowerShell 不允许运行脚本可以使用powershell -ExecutionPolicy Bypass -File .\run_sub001.ps1十二、批量处理脚本1. 输入文件命名规则假设E:\freesurfer\data中有001.nii 002.nii 003.nii 004.nii希望输出为sub-001 sub-002 sub-003 sub-0042. 批量运行 recon-all 脚本在E:\freesurfer\scripts\中新建run_batch.ps1写入以下内容$DataDir E:\freesurfer\data $SubjectsDir E:\freesurfer\subjects $License E:\freesurfer\license.txt $Image freesurfer/freesurfer:6.0 $Threads 4 $files Get-ChildItem $DataDir -Filter *.nii foreach ($file in $files) { $base [System.IO.Path]::GetFileNameWithoutExtension($file.Name) $subject sub-$base $outDir Join-Path $SubjectsDir $subject $doneFile Join-Path $outDir scripts\recon-all.done Write-Host Write-Host Processing file: $($file.Name) Write-Host Subject ID: $subject Write-Host Output dir: $outDir Write-Host if (Test-Path $doneFile) { Write-Host Skip $subject : recon-all.done already exists. continue } docker run --rm -it -v ${DataDir}:/data:ro -v ${SubjectsDir}:/subjects -v ${License}:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects $Image recon-all -i /data/$($file.Name) -s $subject -all -openmp $Threads }运行方式cd E:\freesurfer\scripts .\run_batch.ps1如果执行策略受限powershell -ExecutionPolicy Bypass -File .\run_batch.ps13. 批处理逻辑说明该脚本会自动1. 扫描 E:\freesurfer\data 下所有 .nii 文件 2. 对每个文件生成 subject ID 例如 001.nii → sub-001 3. 检查是否已经存在 recon-all.done 4. 如果已经完成则跳过 5. 如果未完成则启动 FreeSurfer 6.0 容器运行 recon-all 6. 输出结果写入 E:\freesurfer\subjects十三、提取 FreeSurfer 统计表格当所有被试都完成recon-all后需要从 FreeSurfer 输出目录中提取表格。1. 进入 FreeSurfer 容器在 PowerShell 中运行docker run --rm -it -v E:\freesurfer\subjects:/subjects -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects freesurfer/freesurfer:6.0 bash进入容器后cd /subjects ls -d sub-* subjects.txt2. 提取左半球 Destrieux 皮层厚度aparcstats2table \ --subjectsfile subjects.txt \ --hemi lh \ --parc aparc.a2009s \ --meas thickness \ --tablefile lh.aparc.a2009s.thickness.tsv3. 提取右半球 Destrieux 皮层厚度aparcstats2table \ --subjectsfile subjects.txt \ --hemi rh \ --parc aparc.a2009s \ --meas thickness \ --tablefile rh.aparc.a2009s.thickness.tsv4. 提取皮层下体积asegstats2table \ --subjectsfile subjects.txt \ --meas volume \ --tablefile aseg.volume.tsv5. 输出文件位置提取完成后Windows 本地会生成E:\freesurfer\subjects\subjects.txt E:\freesurfer\subjects\lh.aparc.a2009s.thickness.tsv E:\freesurfer\subjects\rh.aparc.a2009s.thickness.tsv E:\freesurfer\subjects\aseg.volume.tsv这些表格后续可用于整理成 braincharts 常模输入格式。十四、自动提取统计表格脚本可以在E:\freesurfer\scripts\中新建extract_stats.ps1内容如下$SubjectsDir E:\freesurfer\subjects $License E:\freesurfer\license.txt $Image freesurfer/freesurfer:6.0 docker run --rm -it -v ${SubjectsDir}:/subjects -v ${License}:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects $Image bash -c cd /subjects \ ls -d sub-* subjects.txt \ aparcstats2table --subjectsfile subjects.txt --hemi lh --parc aparc.a2009s --meas thickness --tablefile lh.aparc.a2009s.thickness.tsv \ aparcstats2table --subjectsfile subjects.txt --hemi rh --parc aparc.a2009s --meas thickness --tablefile rh.aparc.a2009s.thickness.tsv \ asegstats2table --subjectsfile subjects.txt --meas volume --tablefile aseg.volume.tsv运行cd E:\freesurfer\scripts .\extract_stats.ps1或powershell -ExecutionPolicy Bypass -File .\extract_stats.ps1十五、质量控制建议FreeSurfer 结果不能只看是否生成文件还需要做质量控制。建议至少检查1. 原始 T1 是否存在明显运动伪影、截断、强度不均匀。 2. FreeSurfer brainmask 是否正确。 3. white surface 是否沿白质边界。 4. pial surface 是否贴合脑表面是否跑到脑外。 5. 颞叶、眶额叶、脑底部是否有明显错误。 6. stats 文件是否完整生成。主要日志文件E:\freesurfer\subjects\sub-001\scripts\recon-all.log成功完成标志通常类似recon-all -s sub-001 finished without error十六、常见错误与处理1. 在容器内部运行 docker run错误提示bash: docker: command not found bash: -v: command not found原因当前已经在容器内部不能再运行 docker run。解决exit回到 Windows PowerShell 后再运行docker run。2. license 找不到错误提示ERROR: FreeSurfer license file /opt/freesurfer/license.txt not found.解决使用以下挂载方式-v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro3. 重复运行已有 subject错误提示ERROR: You are trying to re-run an existing subject with new input data (-i).如果之前是失败的半成品删除后重跑Remove-Item -Recurse -Force E:\freesurfer\subjects\sub-001如果只是继续中断任务不要加-idocker run --rm -it -v E:\freesurfer\data:/data:ro -v E:\freesurfer\subjects:/subjects -v E:\freesurfer\license.txt:/opt/freesurfer/license.txt:ro -e SUBJECTS_DIR/subjects freesurfer/freesurfer:6.0 recon-all -s sub-001 -all -openmp 44. VS Code 无法远程进入 FreeSurfer 容器错误提示Missing GLIBCXX 3.4.25 Missing GLIBC 2.28原因FreeSurfer 6.0 容器基于较老的 CentOS6 环境不能满足 VS Code Server 要求。处理方式不要使用 VS Code Remote Attach Container。 只用 VS Code 打开 Windows 本地目录 E:\freesurfer 然后在 VS Code 终端中运行 docker run 命令。十七、后续 braincharts 常模分析前需要准备的文件完成 FreeSurfer 后至少应准备1. lh.aparc.a2009s.thickness.tsv 2. rh.aparc.a2009s.thickness.tsv 3. aseg.volume.tsv 4. 人口学表subject_id, age, sex, site人口学表示例subject_id,age,sex,site sub-001,23.5,1,site01 sub-002,31.2,0,site01 sub-003,45.8,1,site01后续需将 FreeSurfer 提取的结构指标与人口学表合并并根据 braincharts 官方模型要求调整 ROI 列名最终计算每个被试、每个脑区的 deviation Z-score。十八、推荐执行顺序完整执行顺序如下1. 建立 E:\freesurfer 文件夹结构 2. 放入 license.txt 3. 将 T1 .nii 文件放入 data 4. 拉取 freesurfer/freesurfer:6.0 镜像 5. 运行单个被试测试 6. 检查 stats 和 recon-all.log 7. 单例成功后运行 run_batch.ps1 8. 所有被试完成后运行 extract_stats.ps1 9. 检查输出 TSV 表格 10. 整理人口学表 11. 进入 braincharts 常模分析