FreeSurfer当前只支持Linux系统和Mac OS。我所使用的系统是Ubuntu 16 .0.4,FreeSurfer的安装耗时较小,但是在处理时耗时较长,可能需要数个小时,甚至一天,这个取决于机器性能,但是和GPU好像没太大关系。下面先给出总的安装步骤,然后单独给出详细的安装步骤。
首先给出几个我参考的文章:
其中第2个参考文章还安装了FSL,我现在也不是很清楚这个FSL是什么,据我的安装和使用结果来看,没必要单独安装,FreeSurfer里应该集成了FSL。(2020.09.15更新,在文章的第四部分增加了FSL的安装和使用说明)
一、FreeSurfer总安装步骤
wget https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/7.1.0/freesurfer-linux-centos6_x86_64-7.1.0.tar.gz #下载安装包
tar -zxv -f freesurfer-linux-centos6_x86_64-7.1.0.tar.gz #解压缩
# 注册,得license.txt,并将license.txt拷贝到./freesurfer目录下
sudo chmod -R 777 ./freesurfer #改变freesurfer的权限
vi ~/.bashrc
# 在~/.bashrc文件中添加以下两行
export FREESURFER_HOME=/home/syzhou/zuzhiang/freesurfer
source $FREESURFER_HOME/SetUpFreeSurfer.sh
source ~/.bashrc
sudo apt-get install tcsh #安装tcsh,类似与bash,不安装运行的时候会报错
二、FreeSurfer安装分步介绍
1. 下载FreeSurfer压缩包
首先到官网下载相应的安装包,下载界面如下图所示,看好是下载Linux下的还是MacOS下的,虽然Linux下的安装包写的是CentOS,但是也支持Ubuntu。在红色框上面右击选择“复制下载连接”,然后在Linux系统下选择相应的路径,使用命令wget https://surfer.nmr.mgh.harvard.edu/pub/dist/freesurfer/7.1.0/freesurfer-linux-centos6_x86_64-7.1.0.tar.gz
下载安装包。
2. 安装
虽然说是安装,其实只需要解压就可以了,使用命令tar -zxv -f freesurfer-linux-centos6_x86_64-7.1.0.tar.gz
进行解压缩,如果你下载和我不是同一个版本,需要把压缩文件的文件名改一下,下同。解压后会在当前目录下生成一个名为freesurfer
的文件夹。
3. 注册
前往官方注册网站进行注册,过段时间后会收到一封电子邮件,附件中有名为license.txt
的文件,下载下来,放到freesurfer
文件夹下面。注册页面如下图所示。
4. 改变freesurfer文件夹权限
使用命令sudo chmod -R 777 ./freesurfer
更改文件夹权限,文件夹路径可能需要根据自己的做相应的调整。
5. 添加环境变量
使用vi ~/.bashrc
命令打开环境变量文件,在~/.bashrc
文件中添加以下两行:
export FREESURFER_HOME=/home/syzhou/zuzhiang/freesurfer
source $FREESURFER_HOME/SetUpFreeSurfer.sh
并使用source ~/.bashrc
命令使改变后的环境变量立即生效。然后会显示下图所示的信息。
6. 安装tcsh
使用sudo apt-get install tcsh
命令安装tcsh,tcsh类似与bash,不安装的话,运行的时候会报错。
7. 测试
在命令行中输入recon-al --help
命令,如果显示帮助信息则说明安装成功,如果提示命令不存在或者只显示了路径信息则说明安装有问题,前者可以通过重新安装解决,后者应该是安装的第6步有问题。
三、FreeSurfer的使用
这里主要是使用FreeSurfer来对脑部图像做头骨的去除。参考的文章是最开始提到的第四篇。
!!!
需要格外注意的是,每次进入终端使用FreeSurfer的时候需要输入命令:
export FREESURFER_HOME=/home/syzhou/zuzhiang/freesurfer
source $FREESURFER_HOME/SetUpFreeSurfer.sh
否则不能正常使用。
!!!
以下是使用FreeSurfer批量对图像进行去除头骨和仿射对齐等操作。其中path/a/b/c
变量的值需要根据实际情况来改变。代码的第19行,如果图像文件的格式名不同,需要保留的字符串长度也不同,只需要文件名(不包括扩展名)即可。
cmd
变量对应的命令中,a/b/c
是环境变量配置命令,recon-all
是颅骨去除的命令,mri_convert
是进行格式转换,从mgz转到nii.gz,只是为了方便查看,mri_convert --apply_transform
是进行仿射对齐操作。
import os
import glob
path = r"/home/syzhou/zuzhiang/Dataset/MGH10/Heads"
# 读取目录下的.img文件
images = glob.glob(os.path.join(path,"*.img"))
# 下面为freesurfer的环境配置命令
a = "export FREESURFER_HOME=/home/syzhou/zuzhiang/freesurfer;"
b = "source $FREESURFER_HOME/SetUpFreeSurfer.sh;"
# 数据所在的目录
c = "export SUBJECTS_DIR="+path+";"
#images=['/home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127.img']
for image in images:
# 将文件路径和文件名分离
filename = os.path.split(image)[1] # 将路径名和文件名分开
filename = os.path.splitext(filename)[0] #将文件名和扩展名分开,如果为.nii.gz,则认为扩展名是.gz
# freesurfer环境配置、颅骨去除、未仿射对齐mpz转nii、仿射对齐、仿射对齐mpz转nii.gz格式
#recon-all是颅骨去除的命令
# mri_convert是进行格式转换,从mgz转到nii.gz,只是为了方便查看
# --apply_transform:仿射对齐操作
# 转格式
filename=filename[:] #根据扩展名的不同,这里需要做更改,只保留文件名即可
cur_path=os.path.join(path,filename)
print("file name: ",cur_path)
cmd = a + b + c \
+ "recon-all -parallel -i " + image + " -autorecon1 -subjid " + cur_path + "&&" \
+ "mri_convert " + cur_path + "/mri/brainmask.mgz " +cur_path + "/mri/"+filename+".nii.gz;"\
+ "mri_convert " + cur_path + "/mri/brainmask.mgz --apply_transform " + cur_path + "/mri/transforms/talairach.xfm -o " + cur_path + "/mri/brainmask_affine.mgz&&" \
+ "mri_convert " + cur_path + "/mri/brainmask_affine.mgz " + cur_path + "/mri/"+filename+"_affine.nii.gz;"
#print("cmd:\n",cmd)
os.system(cmd)
为了更直观的看清楚cmd
对应的指令,下面列出了当图像文件为1127.img
时,cmd
对应的内容,为了方便查看我加入了换行。
export FREESURFER_HOME=/home/syzhou/zuzhiang/freesurfer;
source $FREESURFER_HOME/SetUpFreeSurfer.sh;
export SUBJECTS_DIR=/home/syzhou/zuzhiang/Dataset/MGH10/Heads;
recon-all -i /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127.img -autorecon1 -subjid 1127&&
mri_convert /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127/mri/brainmask.mgz /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127/mri/brainmask.nii.gz;
mri_convert /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127/mri/brainmask.mgz --apply_transform /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127/mri/transforms/talairach.xfm -o /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127/mri/brainmask_affine.mgz&&
mri_convert /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127/mri/brainmask_affine.mgz /home/syzhou/zuzhiang/Dataset/MGH10/Heads/1127/mri/brainmask_affine.nii.gz;
假设图像文件名为1127.img
,则会在path对应的目录下生成一个以图像文件名命名的文件夹,里面保存处理的结果。下图就是g6.img
对应的输出文件夹,里面的结构如下图所示,我们想要得到图片位于mri
文件夹下。
mri
文件夹下的文件如下图所示,其中brainmask.nii.gz
是去除头骨后的图像,brainmask_affine.nii.gz
是去除头骨且仿射对齐后的图像。
以下两图是处理前后的结果。
但是可以发现上述做法有两个问题,一是无法同时对图像及其对应的label进行仿射对齐,二是在去除脑壳后图像移动过了,这对后续的操作会造成障碍。这两个问题的解决请见第四、五部分。
四、FSL的安装和使用
之所以要用到FSL是因为在对图像进行仿射对齐时,无法同时对图像对应的标签进行相同的仿射对齐操作,而FSL是可以的。FSL的安装和使用同样是在Ubuntu系统下进行的。
1. FSL的安装
# 下载FSL安装包,这里下载的是压缩版
wget http://fsl.fmrib.ox.ac.uk/fsldownloads/fsl-5.0.9-centos6_64.tar.gz
# 新建一个文件夹作为FSL的安装路径,并改变其权限
sudo chmod -R 777 文件夹名
# 将下载好的安装包解压到该文件夹下
tar -zxv -f fsl-5.0.9-centos6_64.tar.gz
# 配置环境变量
vi ~/.bashrc
# 在~/.bashrc文件中追加以下三行
export FSLDIR=FSL文件夹的绝对路径
export PATH=$PATH:$FSLDIR/bin
source $FSLDIR/etc/fslconf/fsl.sh
# 使环境变量立即生效
source ~/.bashrc
# 查看是否安装成功,如果出现版本信息则说明安装成功
flirt -version
2. FSL的使用
据说FSL有界面,但是我这边的服务器使用显示器不方便,所以是用命令行进行的。这里我只使用到了FSL的仿射对齐功能以及将已有的仿射矩阵作用在其他图像上的功能,所以只对这两个命令进行介绍。详细信息见官网。
Interpolation :Tri-Linear; Nearest Neighbour
线性配准两幅图像:
flirt -in m_img.nii.gz -ref f_img.nii.gz -out m2f_img.nii.gz -omat m2f.mat -dof 12
其作用是将输入图像按照dof参数指定的方式对齐到参考图像,并保存为out参数指定的图像以及omat参数指定的变换。
其中-in
后面是输入图像的名称;-ref
后面是参考图像的名称;-out
后面是输出图像的名称;-omat
后面是变换矩阵的名称,.mat
的后缀不是强制的,也可以是别的;-dof
是Degrees of Freedom的缩写,即自由度,对于3D到3D的配准来说,12为仿射变换,9为传统变换,7为全局重缩放变换,6为刚体变换,对于2D到2D的配准来说,只有3表示刚体变化这一种。
将保存的变换(transformation)作用在另一张图像:
flirt -in m_label.nii.gz -ref f_img.nii.gz -out m2f_label.nii.gz -init m2f.mat -applyxfm -interp nearestneighbour
其中-init
参数是已经保存的变换;-applyxfm
表示将已经保存的变换作用在新图像上;-interp nearestneighbour
表示使用最近邻插值,最近邻插值可以让label的类别和原来的保持一致,默认是线性插值。
五、FreeSurfer+FSL
(2020.09.23更新)
这一部分我想将FreeSurfer的头骨去除和FSL的仿射对齐结合起来,实现既去除头骨又对图像和label进行仿射对齐,但是上面提到了在用recon-all
命令进行颅骨去除的时候图像会产生移动。所以换了一个命令,使用mri_watershed
命令,这个命令比recon-all
命令速度更快。
import os
import glob
# 使用FreeSurfer对图像进行颅骨剥离
print("FreeSurfer start......\n")
# 图像坐在的目录
#------------------------图像路径需更改------------------------#
path ="/home/syzhou/zuzhiang/Dataset/MGH10/Heads"
# 读取目录下的.img文件列表,*.img表示该目录下所有以.img结尾的文件
#-----------------------图像后缀名需更改--- -------------------#
files = glob.glob(os.path.join(path,"*.img"))
# 输出路径
#------------------------输出路径需更改------------------------#
out_path="/home/syzhou/zuzhiang/MIP/FSL_img/MGH10_results"
print("number: ",len(files))
# 下面为freesurfer的环境配置命令
a = "export FREESURFER_HOME=/home/syzhou/zuzhiang/freesurfer;"
b = "source $FREESURFER_HOME/SetUpFreeSurfer.sh;"
# 数据所在的目录
c = "export SUBJECTS_DIR="+path+";"
for file in files:
# 将文件路径和文件名分离
filename = os.path.split(file)[1] # 将路径名和文件名分开
filename = filename.split(".")[0] # 去除所有扩展名
#recon-all是颅骨去除的命令
# mri_convert是进行格式转换,从mgz转到nii.gz,只是为了方便查看
filename=filename[:] #根据扩展名的不同,这里需要做更改,只保留文件名即可
# 当前输出文件路径,以.nii.gz格式保存
cur_out_path=os.path.join(out_path,filename+".nii.gz")
print("file name: ",file)
cmd = a + b + c + "mri_watershed "+file+" "+ cur_out_path
#print(cmd,"\n")
os.system(cmd)
# 使用FSL对图像和对应的label进行仿射对齐
print("FSL start......\n")
# fixed图像的路径
#---------------去除头骨后的fixed图像名需更改-------------------#
f_path= os.path.join(out_path,"g1.nii.gz")
# moving图像的路径
m_path=out_path
# label的路径
#-----------------------label路径需更改-----------------------#
label_path="/home/syzhou/zuzhiang/Dataset/MGH10/Atlases"
files=glob.glob(os.path.join(m_path,"*.nii.gz"))
print("number: ",len(files))
for file in files:
print("file: ",file)
# 根据图像名找到对应的label名
filename=os.path.split(file)[1]
filename = filename.split(".")[0] # 去除所有扩展名
#---------------------label后缀名需更改--------------------#
label=os.path.join(label_path,filename+".img")
# 下面分别是输出图像名/转换矩阵名/label名,
out_img=os.path.join(out_path,filename+"_img.nii.gz")
out_mat=os.path.join(out_path,filename+".mat")
out_label=os.path.join(out_path,filename+"_label.nii.gz")
# 如果当前文件和fixed图像一样则只将对应label格式转换为.nii.gz
if f_path==file:
convert="mri_convert " + label +" " + out_label
os.system(convert)
print("continue.........")
continue
# 将moving图像对齐到fixed图像
flirt_img="flirt -in "+file+ " -ref "+f_path+" -out "+out_img+" -omat "+out_mat+ " -dof 12"
# 将上一步的仿射变换矩阵作用在图像对应的label上
flirt_label="flirt -in "+label+" -ref "+f_path+" -out "+out_label+" -init "+out_mat+" -applyxfm -interp nearestneighbour"
#print(flirt_img,"\n")
#print(flirt_label,"\n")
os.system(flirt_img)
os.system(flirt_label)
print("\n\nEnd")