基于 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
测试 Docker:
docker 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
进入容器后,终端提示符类似:
root@xxxx:/#
在容器内检查文件是否挂载成功:
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 格式可以直接输入 FreeSurfer:
recon-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-004
2. 批量运行 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.ps1
3. 批处理逻辑说明
该脚本会自动:
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.txt
2. 提取左半球 Destrieux 皮层厚度
aparcstats2table \
--subjectsfile subjects.txt \
--hemi lh \
--parc aparc.a2009s \
--meas thickness \
--tablefile lh.aparc.a2009s.thickness.tsv
3. 提取右半球 Destrieux 皮层厚度
aparcstats2table \
--subjectsfile subjects.txt \
--hemi rh \
--parc aparc.a2009s \
--meas thickness \
--tablefile rh.aparc.a2009s.thickness.tsv
4. 提取皮层下体积
asegstats2table \
--subjectsfile subjects.txt \
--meas volume \
--tablefile aseg.volume.tsv
5. 输出文件位置
提取完成后,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:ro"
3. 重复运行已有 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"
如果只是继续中断任务,不要加 -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
4. 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 常模分析
更多推荐


所有评论(0)