def upsample_mask_tissues(in_file): """ To upsample the 1,2,3 compartment segmented volume in SPM Args: in_file: a list containing the three compartments Returns: """ import os from nipype.interfaces.freesurfer.preprocess import MRIConvert out_file = [] if isinstance(in_file, basestring): # just one compartment out_mask = os.path.basename(in_file).split('.nii.gz')[0] + '_upsample.nii.gz' mc = MRIConvert() mc.inputs.in_file = in_file mc.inputs.out_file = out_mask mc.inputs.vox_size = (1, 1, 1) mc.run() out_file.append(os.path.abspath(os.path.join(os.getcwd(), out_mask))) else: # more than one compartment for tissue in in_file: out_mask = os.path.basename(tissue).split('.nii.gz')[0] + '_upsample.nii.gz' mc = MRIConvert() mc.inputs.in_file = tissue mc.inputs.out_file = out_mask mc.inputs.vox_size = (1, 1, 1) mc.run() out_file.append(os.path.abspath(os.path.join(os.getcwd(), out_mask))) return out_file
def mgh2nii(filename, path_output, out_type="nii"): """ This function converts a volume file from freesurfer mgh to nifti format. Inputs: *filename: full path of the input file. *path_outupt: path where output is written. *out_type: target type of file. created by Daniel Haenelt Date created: 06-01-2020 Last modified: 24-07-2020 """ import os from nipype.interfaces.freesurfer.preprocess import MRIConvert from lib.io.get_filename import get_filename # get filename path, name, ext = get_filename(filename) # convert volume to nifti format mc = MRIConvert() mc.inputs.in_file = filename mc.inputs.out_file = os.path.join(path_output, name + "." + out_type) mc.inputs.in_type = ext.replace('.', '') mc.inputs.out_type = out_type mc.run()
def get_flash2orig(file_flash, file_inv2, file_orig, path_output, cleanup=False): """ This function computes the deformation field for the registration between a partial coverage GRE image and the freesurfer orig file. The following steps are performed: (1) set output folder structure, (2) get scanner transform GRE <-> inv2 and inv2 -> orig, (3) generate flash cmap, (4) apply scanner transform inv2 -> GRE, (5) get flirt registration GRE -> inv2, (6) apply flirt to GRE cmap, (7) apply scanner transform to GRE cmap, (8) apply final deformation to GRE. The function needs the FSL environment set. Inputs: *file_flash: input path for GRE image. *file_inv2: input path for MP2RAGE INV2 image. *file_orig: input path for freesurfer orig image. *path_output: path where output is saved. *cleanup: delete intermediate files (boolean). created by Daniel Haenelt Date created: 18-04-2019 Last modified: 16-05-2019 """ import os import shutil as sh from nipype.interfaces.fsl import FLIRT from nipype.interfaces.fsl.preprocess import ApplyXFM from nipype.interfaces.freesurfer.preprocess import MRIConvert from nighres.registration import apply_coordinate_mappings from lib.cmap import generate_coordinate_mapping from lib.registration.get_scanner_transform import get_scanner_transform """ set folder structure """ path_temp = os.path.join(path_output, "temp") if not os.path.exists(path_output): os.makedirs(path_output) if not os.path.exists(path_temp): os.makedirs(path_temp) # copy input files sh.copyfile(file_inv2, os.path.join(path_temp, "inv2.nii")) sh.copyfile(file_flash, os.path.join(path_temp, "flash.nii")) """ convert orig to nifti """ mc = MRIConvert() mc.inputs.in_file = file_orig mc.inputs.out_file = os.path.join(path_temp, "orig.nii") mc.inputs.in_type = "mgz" mc.inputs.out_type = "nii" mc.run() """ scanner transformation """ get_scanner_transform(os.path.join(path_temp, "inv2.nii"), os.path.join(path_temp, "flash.nii"), path_temp, False) get_scanner_transform(os.path.join(path_temp, "flash.nii"), os.path.join(path_temp, "inv2.nii"), path_temp, False) get_scanner_transform(os.path.join(path_temp, "inv2.nii"), os.path.join(path_temp, "orig.nii"), path_temp, False) """ generate coordinate mapping """ generate_coordinate_mapping(os.path.join(path_temp, "flash.nii"), 0, path_temp, "flash", False, True) """ scanner transform inv2 to flash """ apply_coordinate_mappings( os.path.join(path_temp, "inv2.nii"), # input os.path.join(path_temp, "inv2_2_flash_scanner.nii"), # cmap interpolation="linear", # nearest or linear padding="zero", # closest, zero or max save_data=True, # save output data to file (boolean) overwrite=True, # overwrite existing results (boolean) output_dir=path_temp, # output directory file_name= "inv2_apply_scanner" # base name with file extension for output ) """ flirt flash to inv2 """ os.chdir(path_temp) flirt = FLIRT() flirt.inputs.cost_func = "mutualinfo" flirt.inputs.dof = 6 flirt.inputs.interp = "trilinear" # trilinear, nearestneighbour, sinc or spline flirt.inputs.in_file = os.path.join(path_temp, "flash.nii") flirt.inputs.reference = os.path.join(path_temp, "inv2_apply_scanner_def-img.nii.gz") flirt.inputs.output_type = "NIFTI_GZ" flirt.inputs.out_file = os.path.join(path_temp, "flash_apply_flirt_def-img.nii.gz") flirt.inputs.out_matrix_file = os.path.join(path_temp, "flirt_matrix.txt") flirt.run() """ apply flirt to flash cmap """ applyxfm = ApplyXFM() applyxfm.inputs.in_file = os.path.join(path_temp, "cmap_flash.nii") applyxfm.inputs.reference = os.path.join(path_temp, "flash.nii") applyxfm.inputs.in_matrix_file = os.path.join(path_temp, "flirt_matrix.txt") applyxfm.inputs.interp = "trilinear" applyxfm.inputs.padding_size = 0 applyxfm.inputs.output_type = "NIFTI_GZ" applyxfm.inputs.out_file = os.path.join(path_temp, "cmap_apply_flirt_def-img.nii.gz") applyxfm.inputs.apply_xfm = True applyxfm.run() """ apply scanner transform to flash cmap """ apply_coordinate_mappings( os.path.join(path_temp, "cmap_apply_flirt_def-img.nii.gz"), os.path.join(path_temp, "flash_2_inv2_scanner.nii"), # cmap 1 os.path.join(path_temp, "inv2_2_orig_scanner.nii"), # cmap 2 interpolation="linear", # nearest or linear padding="zero", # closest, zero or max save_data=True, # save output data to file (boolean) overwrite=True, # overwrite existing results (boolean) output_dir=path_temp, # output directory file_name= "cmap_apply_scanner" # base name with file extension for output ) """ apply deformation to source image """ apply_coordinate_mappings( os.path.join(path_temp, "flash.nii"), # input os.path.join(path_temp, "cmap_apply_scanner_def-img.nii.gz"), interpolation="linear", # nearest or linear padding="zero", # closest, zero or max save_data=True, # save output data to file (boolean) overwrite=True, # overwrite existing results (boolean) output_dir=path_temp, # output directory file_name= "flash_apply_deformation" # base name with file extension for output ) # rename final deformation examples os.rename(os.path.join(path_temp, "cmap_apply_scanner_def-img.nii.gz"), os.path.join(path_output, "flash2orig.nii.gz")) os.rename( os.path.join(path_temp, "flash_apply_deformation_def-img.nii.gz"), os.path.join(path_output, "flash2orig_example.nii.gz")) # clean intermediate files if cleanup: sh.rmtree(path_temp, ignore_errors=True)
def get_nuisance_mask(input, pathSPM, deformation, path_output, nerode_white=1, nerode_csf=1, segmentation=True, cleanup=True): """ This function calculates WM and CSF masks in space of the functional time series. It uses SPM to compute WM and CSF probability maps. These maps are masked with a skullstrip mask and transformed to native epi space. Inputs: *input: input anatomy (orig.mgz). *pathSPM: path to spm toolbox. *deformation: coordinate mapping for ana to epi transformation. *path_output: path where output is saved. *nerode_white: number of wm mask eroding steps. *nerode_csf: number of csf mask eroding steps. *segmentation: do not calculate new masks to not rerun everything. *cleanup: delete intermediate files. created by Daniel Haenelt Date created: 01-03-2019 Last modified: 01-03-2019 """ import os import shutil as sh import nibabel as nb from scipy.ndimage.morphology import binary_erosion from nipype.interfaces.fsl import BET from nipype.interfaces.freesurfer.preprocess import MRIConvert from nighres.registration import apply_coordinate_mappings from lib.skullstrip.skullstrip_spm12 import skullstrip_spm12 # make output folder if not os.path.exists(path_output): os.mkdir(path_output) # get filename without file extension of input file file = os.path.splitext(os.path.basename(input))[0] # convert to nifti format mc = MRIConvert() mc.inputs.in_file = input mc.inputs.out_file = os.path.join(path_output, file + ".nii") mc.inputs.out_type = "nii" mc.run() # bet skullstrip mask btr = BET() btr.inputs.in_file = os.path.join(path_output, file + ".nii") btr.inputs.frac = 0.5 btr.inputs.mask = True btr.inputs.no_output = True btr.inputs.out_file = os.path.join(path_output, "bet") btr.inputs.output_type = "NIFTI" btr.run() # segmentation if segmentation: skullstrip_spm12(os.path.join(path_output, file + ".nii"), pathSPM, path_output) # load tissue maps wm_array = nb.load(os.path.join(path_output, "skull", "c2" + file + ".nii")).get_fdata() csf_array = nb.load( os.path.join(path_output, "skull", "c3" + file + ".nii")).get_fdata() mask_array = nb.load(os.path.join(path_output, "bet_mask.nii")).get_fdata() # binarize wm_array[wm_array > 0] = 1 csf_array[csf_array > 0] = 1 # apply brain mask wm_array = wm_array * mask_array csf_array = csf_array * mask_array # erode wm wm_array = binary_erosion( wm_array, structure=None, iterations=nerode_white, mask=None, output=None, border_value=0, origin=0, brute_force=False, ) # erode csf csf_array = binary_erosion( csf_array, structure=None, iterations=nerode_csf, mask=None, output=None, border_value=0, origin=0, brute_force=False, ) # write wm and csf mask data_img = nb.load(input) wm_out = nb.Nifti1Image(wm_array, data_img.affine, data_img.header) nb.save(wm_out, os.path.join(path_output, "wm_mask_orig.nii")) csf_out = nb.Nifti1Image(csf_array, data_img.affine, data_img.header) nb.save(csf_out, os.path.join(path_output, "csf_mask_orig.nii")) # apply deformation to mask apply_coordinate_mappings( os.path.join(path_output, "wm_mask_orig.nii"), # input deformation, # cmap interpolation="nearest", # nearest or linear padding="zero", # closest, zero or max save_data=True, # save output data to file (boolean) overwrite=True, # overwrite existing results (boolean) output_dir=path_output, # output directory file_name="wm_mask" # base name with file extension for output ) apply_coordinate_mappings( os.path.join(path_output, "csf_mask_orig.nii"), # input deformation, # cmap interpolation="nearest", # nearest or linear padding="zero", # closest, zero or max save_data=True, # save output data to file (boolean) overwrite=True, # overwrite existing results (boolean) output_dir=path_output, # output directory file_name="csf_mask" # base name with file extension for output ) # rename transformed masks os.rename(os.path.join(path_output, "wm_mask_def-img.nii.gz"), os.path.join(path_output, "wm_mask.nii.gz")) os.rename(os.path.join(path_output, "csf_mask_def-img.nii.gz"), os.path.join(path_output, "csf_mask.nii.gz")) # cleanup if cleanup: os.remove(os.path.join(path_output, "bet_mask.nii")) os.remove(os.path.join(path_output, "csf_mask_orig.nii")) os.remove(os.path.join(path_output, "wm_mask_orig.nii")) os.remove(os.path.join(path_output, "orig.nii")) sh.rmtree(os.path.join(path_output, "skull"), ignore_errors=True)
def map2surface(input_surf, input_vol, hemi, path_output, input_white=None, input_ind=None, cleanup=True): """ This function samples data from the input volume to the input surface and optionally maps those values to a target surface if an index file is given. Inputs: *input_surf: surface mesh onto which volume data is sampled. *input_vol: volume from which data is sampled. *hemi: hemisphere. *path_output: path where to save output. *input_white: white surface in target surface space (only necessary if index file is given). *input_ind: textfile with mapping of vertex indices to target space. *cleanup: remove intermediate files. created by Daniel Haenelt Date created: 06-02-2019 Last modified: 03-08-2020 """ import os import numpy as np import nibabel as nb import shutil as sh from nibabel.freesurfer.io import read_geometry from nipype.interfaces.freesurfer import SampleToSurface from nipype.interfaces.freesurfer.preprocess import MRIConvert # set freesurfer path environment os.environ["SUBJECTS_DIR"] = path_output # freesurfer subject tmp = np.random.randint(0, 10, 5) tmp_string = ''.join(str(i) for i in tmp) sub = "tmp_" + tmp_string # make output folder if not os.path.exists(path_output): os.makedirs(path_output) # mimic freesurfer folder structure (with some additional folder for intermediate files) path_sub = os.path.join(path_output, sub) path_mri = os.path.join(path_sub, "mri") path_surf = os.path.join(path_sub, "surf") os.makedirs(path_sub) os.makedirs(path_mri) os.makedirs(path_surf) # copy input volume as orig.mgz to mimicked freesurfer folder if os.path.splitext(os.path.basename(input_vol))[1] is not ".mgz": mc = MRIConvert() mc.inputs.in_file = input_vol mc.inputs.out_file = os.path.join(path_mri, "orig.mgz") mc.inputs.out_type = 'mgz' mc.run() else: sh.copyfile(input_vol, os.path.join(path_mri, "orig.mgz")) # copy input surface to mimicked freesurfer folder sh.copyfile(input_surf, os.path.join(path_surf, hemi + ".source")) # input volume file name if os.path.splitext(os.path.basename(input_vol))[1] == ".gz": name_vol = os.path.splitext( os.path.splitext(os.path.basename(input_vol))[0])[0] else: name_vol = os.path.splitext(os.path.basename(input_vol))[0] name_surf = os.path.basename(input_surf).split('.')[1] # mri_vol2surf sampler = SampleToSurface() sampler.inputs.subject_id = sub sampler.inputs.reg_header = True sampler.inputs.hemi = hemi sampler.inputs.source_file = input_vol sampler.inputs.surface = "source" sampler.inputs.sampling_method = "point" sampler.inputs.sampling_range = 0 sampler.inputs.sampling_units = "mm" sampler.inputs.interp_method = "nearest" # or trilinear sampler.inputs.out_type = "mgh" sampler.inputs.out_file = os.path.join(path_surf, hemi + "." + "sampled.mgh") sampler.run() if input_ind: # read ind ind_orig = np.loadtxt(input_ind, dtype=int) # read white vtx_orig, _ = read_geometry(input_white) # read sampled morph data vals_img = nb.load(os.path.join(path_surf, hemi + "." + "sampled.mgh")) vals_array = vals_img.get_fdata() # get anzahl der vertices als Nullen in white vals_orig = np.zeros([len(vtx_orig[:, 0]), 1, 1]) # setze sampled data da rein vals_orig[ind_orig] = vals_array # write sampled data in anatomical space vals_img.header["dims"][0] = len(vals_orig[:, 0]) vals_img.header["Mdc"] = np.eye(3) res_img = nb.Nifti1Image(vals_orig, vals_img.affine, vals_img.header) nb.save( res_img, os.path.join( path_output, hemi + "." + name_vol + "_" + name_surf + "_def_trans.mgh")) else: # write sampled data in epi space sh.copyfile( os.path.join(path_surf, hemi + "." + "sampled.mgh"), os.path.join(path_output, hemi + "." + name_vol + "_" + name_surf + "_def.mgh")) # delete intermediate files if cleanup: sh.rmtree(path_sub, ignore_errors=True)
sh.copyfile(file_orig, os.path.join(path_orig, "orig.mgz")) sh.copyfile(file_mean_epi, os.path.join(path_epi, "epi.nii")) sh.copyfile(file_t1, os.path.join(path_t1, "T1.nii")) """ mask preparation """ # convert to nifti if os.path.splitext(file_mask)[1] == ".mgh": sh.copyfile(file_mask, os.path.join(path_t1, "mask.mgh")) mc = MRIConvert() mc.inputs.in_file = os.path.join(path_t1, "mask.mgh") mc.inputs.out_file = os.path.join(path_t1, "mask.nii") mc.inputs.in_type = "mgh" mc.inputs.out_type = "nii" mc.run() elif os.path.splitext(file_mask)[1] == ".mgz": sh.copyfile(file_mask, os.path.join(path_t1, "mask.mgz")) mc = MRIConvert() mc.inputs.in_file = os.path.join(path_t1, "mask.mgz") mc.inputs.out_file = os.path.join(path_t1, "mask.nii") mc.inputs.in_type = "mgz" mc.inputs.out_type = "nii" mc.run() elif os.path.splitext(file_mask)[1] == ".gz": sh.copyfile(file_mask, os.path.join(path_t1, "mask.nii.gz")) gunzip(os.path.join(path_t1, "mask.nii.gz")) elif os.path.splitext(file_mask)[1] == ".nii": sh.copyfile(file_mask, os.path.join(path_t1, "mask.nii")) else: print("File extension of mask could not be identified!")