def test_bet2(self, mock_setenv): """ Test the FSL 'bet2' command wrapping. """ expected_files = ("/my/path/mock_output.nii.gz", "/my/path/mock_output_mask.nii.gz", "/my/path/mock_output_mesh.vtk", None, "/my/path/mock_output_inskull_mask.nii.gz", "/my/path/mock_output_inskull_mesh.nii.gz", "/my/path/mock_output_outskull_mask.nii.gz", "/my/path/mock_output_outskull_mesh.nii.gz", "/my/path/mock_output_outskin_mask.nii.gz", "/my/path/mock_output_outskin_mesh.nii.gz", "/my/path/mock_output_skull_mask.nii.gz") mock_setenv.return_value = self.mock_fslenv mock_input = "/my/path/mock_input.nii.gz" mock_output = "/my/path/mock_output" output_files = bet2(mock_input, mock_output, f=0.5, m=True, shfile="mock.sh", s=True, e=True) self.assertTrue(self.mock_popen.called) self.assertTrue(output_files == expected_files)
def test_bet2(self, mock_setenv): """ Test the FSL 'bet2' command wrapping. """ expected_files = ( "/my/path/mock_output.nii.gz", "/my/path/mock_output_mask.nii.gz", "/my/path/mock_output_mesh.vtk", None, "/my/path/mock_output_inskull_mask.nii.gz", "/my/path/mock_output_inskull_mesh.nii.gz", "/my/path/mock_output_outskull_mask.nii.gz", "/my/path/mock_output_outskull_mesh.nii.gz", "/my/path/mock_output_outskin_mask.nii.gz", "/my/path/mock_output_outskin_mesh.nii.gz", "/my/path/mock_output_skull_mask.nii.gz", ) mock_setenv.return_value = self.mock_fslenv mock_input = "/my/path/mock_input.nii.gz" mock_output = "/my/path/mock_output" output_files = bet2(mock_input, mock_output, f=0.5, m=True, shfile="mock.sh", s=True, e=True) self.assertTrue(self.mock_popen.called) self.assertTrue(output_files == expected_files)
# create a pdf snap of the b0 image if args.graphics: snap_file = os.path.join(qcdir, "nodif.pdf") plot_image(b0_file, snap_file=snap_file, name="nodif") # generate a brain mask on the corrected b0 data b0_brain_file = os.path.join(subjdir, "nodif_brain") bet_files = glob.glob(b0_brain_file + "*") if len(bet_files) == 0: (output, mask_file, mesh_file, outline_file, inskull_mask_file, inskull_mesh_file, outskull_mask_file, outskull_mesh_file, outskin_mask_file, outskin_mesh_file, skull_mask_file) = bet2( b0_file, b0_brain_file, m=True, f=0.25, shfile=args.fslconfig) else: mask_file = sorted(bet_files)[0] if not os.path.isfile(mask_file): raise IOError("FileDoesNotExist: '{0}'.".format(mask_file)) # create a pdf snap of the brain mask if args.graphics: snap_file = os.path.join(qcdir, "bet.pdf") plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet") """ Generating PDFs
def bet2_nodif_brain(outdir, dwi, bval, subdir="bet2_nodif_brain", qc=True): """ Extract brain from b0 volume, i.e. in DW data for a volume where bvalue=0. Parameters ---------- outdir: Str, path to directory where to output. dwi: Str, path to DW data in which at least one volume was acquired with bvalue=0. bval: Str, path to .bval file associated to the DW data. subdir: Str, if you want the result files to be written in a subdirectory, specify the name, by default "bet2_nodif_brain". Return ------ nodif_brain: Str, path to the brain only volume. nodif_brain_mask: Str, path to the brain-only binary mask. <unit> <output name="nodif_brain" type="File" /> <output name="nodif_brain_mask" type="File" /> <input name="outdir" type="Directory" /> <input name="dwi" type="File" /> <input name="bval" type="File" /> <input name="subdir" type="Str" /> <input name="qc" type="Bool" /> </unit> """ if subdir: outdir = os.path.join(outdir, subdir) # Create outdir if it does not exist if not os.path.isdir(outdir): os.makedirs(outdir) # Get a/the volume with bvalue=0. nodif_volume = extract_nodif_volume(outdir, dwi, bval) # Set output path with desired prefix name output_prefix = os.path.join(outdir, "nodif_brain") # Run FSL bet2 bet2(nodif_volume, output_prefix, f=0.25, m=True) # Output paths nodif_brain = output_prefix + ".nii.gz" nodif_brain_mask = output_prefix + "_mask.nii.gz" # Check existence of resulting files if not (os.path.isfile(nodif_brain) and os.path.isfile(nodif_brain_mask)): raise Exception("bet2: output file(s) missing: %s or/and %s ." % (nodif_brain, nodif_brain_mask)) # If Quality Check, generate a PNG snapshot if qc: # Snap shot of brain-only contour on T2 image brain_contour_png = os.path.join(outdir, "nodif_brain_mask.png") plot_image(nodif_volume, contour_file=nodif_brain_mask, snap_file=brain_contour_png, name="nodif_brain_mask") return nodif_brain, nodif_brain_mask
bvals = numpy.loadtxt(bvals_file).tolist() b0_index = bvals.index(0) b0_file = os.path.join(outdir, "nodif.nii.gz") if not os.path.isfile(b0_file): extract_image(diffusion_file, index=b0_index, out_file=b0_file) snap_file = os.path.join(qcdir, "nodif.pdf") plot_image(b0_file, snap_file=snap_file, name="nodif") b0_brain_file = os.path.join(outdir, "nodif_brain") bet_files = glob.glob(b0_brain_file + "*") if len(bet_files) == 0: (output, mask_file, mesh_file, outline_file, inskull_mask_file, inskull_mesh_file, outskull_mask_file, outskull_mesh_file, outskin_mask_file, outskin_mesh_file, skull_mask_file) = bet2(b0_file, b0_brain_file, m=True, f=0.25) else: mask_file = sorted(bet_files)[0] if not os.path.isfile(mask_file): raise IOError("FileDoesNotExist: '{0}'.".format(mask_file)) snap_file = os.path.join(qcdir, "bet.pdf") plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet") """ Generating the FA image ----------------------- There are much better ways to create an FA image than this method, but we're only using this image for registration purposes. It is probably not a good idear to use this image in a whole-brain FA analysis. """
index=b0_index, out_file=b0_file) snap_file = os.path.join(qcdir, "nodif.pdf") plot_image(b0_file, snap_file=snap_file, name="nodif") b0_brain_file = os.path.join(outdir, "nodif_brain") bet_files = glob.glob(b0_brain_file + "*") if len(bet_files) == 0: (output, mask_file, mesh_file, outline_file, inskull_mask_file, inskull_mesh_file, outskull_mask_file, outskull_mesh_file, outskin_mask_file, outskin_mesh_file, skull_mask_file) = bet2( b0_file, b0_brain_file, m=True, f=0.25) else: mask_file = sorted(bet_files)[0] if not os.path.isfile(mask_file): raise IOError("FileDoesNotExist: '{0}'.".format(mask_file)) snap_file = os.path.join(qcdir, "bet.pdf") plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet") """ Generating the FA image ----------------------- There are much better ways to create an FA image than this method, but we're
def brainsuite_susceptibility_correction(outdir, dwi, bval, bvec, subject_id, phase_enc_dir, subjects_dir=None, qc_dir=None, bdp_nthread=4): """ Assuming the beginning of the preprocessing was done with Connectomist up to Eddy current and motion correction, we now want to make susceptbility distortion correction using Brainsuite. Parameters ---------- outdir: str Path to directory where to output. dwi: str Path to the preprocessed diffusion-weighted Nifti. bval: str Path to the bval file associated to the Nifti. bvec: str Path to the bvec file associated to the Nifti. subject_id: str Subject identifier used in Freesurfer. phase_enc_dir: str In plane phase encoding direction, "y", "y-", "x" or "x-". subjects_dir: str, default None If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to bypass it, pass the path. qc_dir: str, default None Path to directory where to output snapshots for QC. By default in outdir. bdp_nthread: int, default 4 Number of threads for bdp (see bdp.sh --thread flag) """ # Freesurfer 'subjects_dir' has to be passed or set as environment variable subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir) # Check in plane phase encoding direction # The sign of the phase encoding direction has no impact in this strategy # e.g. for "+y" or "-y" use "y" possible_phase_enc_dirs = {"y", "x"} if phase_enc_dir not in possible_phase_enc_dirs: raise ValueError( "Bad argument 'phase_enc_dir': {}, should be in {}.".format( phase_enc_dir, possible_phase_enc_dirs)) # Set and check path to T1 brain-only volume from Freesurfer (mgz format) t1_brain_mgz = os.path.join(subjects_dir, subject_id, "mri/brain.mgz") if not os.path.isfile(t1_brain_mgz): raise Exception("Missing file: {}".format(t1_brain_mgz)) # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the # same orientation as the diffusion data) t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz") cmd = [ "mri_convert", t1_brain_mgz, t1_brain_RAS_nii, "--out_orientation", "RAS" ] run_freesurfer_cmd(cmd, subjects_dir=subjects_dir) # Run bfc (bias correction: required by BrainSuite) t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz") cmd = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc] subprocess.check_call(cmd) # Extract brain from the nodif volume with FSL bet2 nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz") bet2(dwi, nodif_brain, f=0.25, m=False) # Run bdp.sh: registration + diffusion model cmd = [ "bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec, "--dwi-mask", nodif_brain, "--dir=%s" % phase_enc_dir, "--threads=%i" % bdp_nthread ] subprocess.check_call(cmd) # Path to files of interest, created by BrainSuite bdp.sh dwi_wo_susceptibility = os.path.join(outdir, "t1_brain.dwi.RAS.correct.nii.gz") ############### # Quality check: create snapshots to visually assert the registration # quality if qc_dir is None: qc_dir = outdir # The snapshots won't contain all slices, half of them nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2] # Path to registered T1 t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz") # First png: T1 registered in diffusion with nodif edges t1_with_nodif_edges_png = os.path.join(qc_dir, "t1_with_nodif_edges.png") plot_image(t1_to_dif, edge_file=nodif_brain, snap_file=t1_with_nodif_edges_png, name="T1 in diffusion + edges of nodif", cut_coords=nb_slices_in_z - 2) # Second png: nodif with edges of T1 registered in diffusion nodif_with_t1_edges_png = os.path.join(qc_dir, "nodif_with_t1_edges.png") plot_image(nodif_brain, edge_file=t1_to_dif, snap_file=nodif_with_t1_edges_png, name="nodif + edges of registered T1", cut_coords=nb_slices_in_z - 2) return dwi_wo_susceptibility, bval, bvec
def complete_preproc_wo_fieldmap(outdir, dwi, bval, bvec, phase_enc_dir, subject_id, subjects_dir=None, invertX=True, invertY=False, invertZ=False, delete_steps=False): """ Function that runs all preprocessing steps using Connectomist but with BrainSuite for the correction of susceptibility distortions. Parameters ---------- outdir: str Path to directory where all the preprocessing will be done. dwi: str path to input diffusion-weighted Nifti data. bval: str Path to the Nifti's associated .bval file. bvec: str Ppath to Nifti's associated .bval file. phase_enc_dir: str In plane phase encoding direction, "y", "y-", "x" or "x-". subject_id: str Subject identifier used in Freesurfer. subjects_dir: Str, default None If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to bypass it, pass the path. invertX: bool, default True If True invert x-axis in diffusion model. invertY: bool, default False Same as invertX but for y-axis. invertZ: bool, default False Same as invertX but for z-axis. delete_steps: bool If True remove all intermediate files and directories at the end of preprocessing, to keep only selected files: - preprocessed Nifti + bval + bvec + outliers.py + nodif_brain*.nii.gz Returns ------- outdir: str, Path to directory with the preprocessed files. <unit> <output name="preproc_dwi" type="File" /> <output name="preproc_bval" type="File" /> <output name="preproc_bvec" type="File" /> <input name="outdir" type="Directory" /> <input name="dwi" type="File" /> <input name="bval" type="File" /> <input name="bvec" type="File" /> <input name="phase_enc_dir" type="Str" /> <input name="subject_id" type="Str" /> <input name="subjects_dir" type="Str" /> <input name="invertX" type="Bool" /> <input name="invertY" type="Bool" /> <input name="invertZ" type="Bool" /> <input name="delete_steps" type="Bool" /> </unit> """ # Step 0 - Initialization # Freesurfer 'subjects_dir' has to be passed or set as environment variable subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir) # Raise an Exception if BrainsuiteCheck is not installed check_brainsuite_installation() # Create the preprocessing output directory if not existing if not os.path.isdir(outdir): os.makedirs(outdir) # Step 1 - Import files to Connectomist and choose q-space model raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model") # The manufacturer option is unused (use brainsuite for susceptibility # correction) but required dwi_data_import_and_qspace_sampling(raw_dwi_dir, dwi=dwi, bval=bval, bvec=bvec, manufacturer="Siemens", invertX=invertX, invertY=invertY, invertZ=invertZ, subject_id=subject_id) # Step 2 - Create a brain mask rough_mask_dir = os.path.join(outdir, "02-Rough_mask") dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir) # Step 3 - Detect and correct outlying diffusion slices outliers_dir = os.path.join(outdir, "03-Outliers") dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir) # Export outliers.py path_outliers_py = os.path.join(outliers_dir, "outliers.py") shutil.copy(path_outliers_py, outdir) # Step 4 - Eddy current and motion correction eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion") dwi_eddy_current_and_motion_correction(eddy_motion_dir, raw_dwi_dir, rough_mask_dir, outliers_dir) # Step 5 - Convert Connectomist result to Nifti with bval/bvec dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir, filename="dwi_ecc") # Step 6 - Susceptibility correction using BrainSuite brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite") if not os.path.isdir(brainsuite_dir): os.mkdir(brainsuite_dir) dwi_wo_susceptibility, bval, bvec = \ brainsuite_susceptibility_correction(outdir=brainsuite_dir, dwi=dwi, bval=bval, bvec=bvec, phase_enc_dir=phase_enc_dir, subject_id=subject_id, subjects_dir=subjects_dir, qc_dir=outdir) # Step 7 - move corrected diffusion to outdir dwi_preproc = os.path.join(outdir, "dwi.nii.gz") bval_preproc = os.path.join(outdir, "dwi.bval") bvec_preproc = os.path.join(outdir, "dwi.bvec") shutil.copyfile(dwi_wo_susceptibility, dwi_preproc) shutil.copyfile(bval, bval_preproc) shutil.copyfile(bvec, bvec_preproc) # Step 8 - Create a T2 brain mask of preprocessed DWI data bet2_prefix = os.path.join(outdir, "nodif_brain") nodif_brain = os.path.join(bet2_prefix + ".nii.gz") nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz") bet2(dwi, bet2_prefix, f=0.25, m=True) # Step 9 - clean intermediate directories if requested if delete_steps: intermediate_directories = [ raw_dwi_dir, rough_mask_dir, outliers_dir, eddy_motion_dir, brainsuite_dir ] for directory in intermediate_directories: shutil.rmtree(directory) return (outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain, nodif_brain_mask)
b0_brain_file = os.path.join(subjdir, "nodif_brain") bet_files = glob.glob(b0_brain_file + "*") if len(bet_files) == 0: ( output, mask_file, mesh_file, outline_file, inskull_mask_file, inskull_mesh_file, outskull_mask_file, outskull_mesh_file, outskin_mask_file, outskin_mesh_file, skull_mask_file, ) = bet2(b0_file, b0_brain_file, m=True, f=args.thresh, shfile=args.fslconfig) else: mask_file = sorted(bet_files)[0] if not os.path.isfile(mask_file): raise IOError("FileDoesNotExist: '{0}'.".format(mask_file)) # create a pdf snap of the brain mask if args.graphics: snap_file = os.path.join(qcdir, "bet.pdf") plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet") """ Generating PDFs ---------------
# create a pdf snap of the b0 image if args.graphics: snap_file = os.path.join(qcdir, "nodif.pdf") plot_image(b0_file, snap_file=snap_file, name="nodif") # generate a brain mask on the corrected b0 data b0_brain_file = os.path.join(subjdir, "nodif_brain") bet_files = glob.glob(b0_brain_file + "*") if len(bet_files) == 0: (output, mask_file, mesh_file, outline_file, inskull_mask_file, inskull_mesh_file, outskull_mask_file, outskull_mesh_file, outskin_mask_file, outskin_mesh_file, skull_mask_file) = bet2(b0_file, b0_brain_file, m=True, f=args.thresh, shfile=args.fslconfig) else: mask_file = sorted(bet_files)[0] if not os.path.isfile(mask_file): raise IOError("FileDoesNotExist: '{0}'.".format(mask_file)) # create a pdf snap of the brain mask if args.graphics: snap_file = os.path.join(qcdir, "bet.pdf") plot_image(b0_file, contour_file=mask_file, snap_file=snap_file, name="bet") """
def brainsuite_susceptibility_correction(outdir, dwi, bval, bvec, subject_id, fs_subjects_dir = None, qc_dir = None, bdp_nthread = 8): """ Assuming the beginning of the preprocessing was done with Connectomist up to Eddy current and motion correction, we now want to make susceptbility distortion correction using Brainsuite. Parameters ---------- outdir: Str, path to directory where to output. dwi bval bvec subject_id: Str, subject identifier used in Freesurfer. fs_subjects_dir: If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to bypass it, pass the path. qc_dir: Str, path to directory where to output snapshots for QC. bdp_nthread: Int, nb of threads for bdp (see bdp.sh --thread flag) """ # If Freesurfer SUBJECTS_DIR is not passed, it should be set as environment variable if fs_subjects_dir is None: if "SUBJECTS_DIR" in os.environ: fs_subjects_dir = os.environ["SUBJECTS_DIR"] else: raise ValueError("Missing <SUBJECTS_DIR>: set the $SUBJECTS_DIR " "environment variable for Freesurfer or pass it " "as an argument.") # Set and check path to T1 brain-only volume from Freesurfer (mgz format) t1_brain_mgz = os.path.join(fs_subjects_dir, subject_id, "mri/brain.mgz") if not os.path.isfile(t1_brain_mgz): raise Exception("Missing file: {}".format(t1_brain_mgz)) # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the # same orientation as the diffusion data) t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz") cmd = ["mri_convert", t1_brain_mgz, t1_brain_RAS_nii, "--out_orientation", "RAS"] fsprocess = FSWrapper(cmd) fsprocess() # Run if fsprocess.exitcode != 0: raise FreeSurferRuntimeError(cmd[0], " ".join(cmd[1:])) # Run bfc (bias correction: required by BrainSuite) t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz") cmd = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc] subprocess.check_call(cmd) # Extract brain from the nodif volume with FSL bet2 nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz") bet2(dwi, nodif_brain, f=0.25, m=False) # Run bdp.sh: registration + diffusion model cmd = ["bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec, "--dwi-mask", nodif_brain, "--threads=%i" % bdp_nthread] subprocess.check_call(cmd) # Path to files of interest, created by BrainSuite bdp.sh dwi_wo_susceptibility = os.path.join(outdir, "t1_brain.dwi.RAS.correct.nii.gz") ############### # Quality check: create snapshots to visually assert the registration quality if qc_dir is None: qc_dir = outdir # The snapshots won't contain all slices, half of them nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2] # Path to registered T1 t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz") # First png: T1 registered in diffusion with nodif edges t1_with_nodif_edges_png = os.path.join(qc_dir, "t1_with_nodif_edges.png") plot_image(t1_to_dif, edge_file = nodif_brain, snap_file = t1_with_nodif_edges_png, name = "T1 in diffusion + edges of nodif", cut_coords = nb_slices_in_z/2) # Second png: nodif with edges of T1 registered in diffusion nodif_with_t1_edges_png = os.path.join(qc_dir, "nodif_with_t1_edges.png") plot_image(nodif_brain, edge_file = t1_to_dif, snap_file = nodif_with_t1_edges_png, name = "nodif + edges of registered T1", cut_coords = nb_slices_in_z/2) return dwi_wo_susceptibility, bval, bvec
def complete_preproc_wo_fieldmap(outdir, dwi, bval, bvec, subject_id, fs_subjects_dir = None, invertX = True, invertY = False, invertZ = False, delete_steps = False): """ Function that runs all preprocessing steps using Connectomist but with BrainSuite for the correction of susceptibility distortions. Parameters ---------- outdir: Str, path to folder where all the preprocessing will be done. dwi Str, path to input Nifti DW data. bval: Str, path to Nifti's associated .bval file. bvec: Str, path to Nifti's associated .bval file. subject_id: Str, subject identifier used in Freesurfer. fs_subjects_dir: If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to bypass it, pass the path. invertX: Bool, if True invert x-axis in diffusion model. invertY: Bool, same as invertX but for y-axis. invertZ: Bool, same as invertX but for z-axis. delete_steps: Bool, if True remove all intermediate files and directories at the end of preprocessing, to keep only selected files: preprocessed Nifti + bval + bvec + outliers.py + nodif_brain.nii.gz Returns ------- outdir: Directory with the preprocessed files. <unit> <output name="preproc_dwi" type="File" /> <output name="preproc_bval" type="File" /> <output name="preproc_bvec" type="File" /> <input name="outdir" type="Directory" /> <input name="dwi" type="File" /> <input name="bval" type="File" /> <input name="bvec" type="File" /> <input name="subject_id" type="Str" /> <input name="fs_subjects_dir" type="Str" /> <input name="invertX" type="Bool" /> <input name="invertY" type="Bool" /> <input name="invertZ" type="Bool" /> <input name="delete_steps" type="Bool" /> </unit> """ ### Step 0 - Initialization # If Freesurfer SUBJECTS_DIR is not passed, it should be set as environment variable if fs_subjects_dir is None: if "SUBJECTS_DIR" in os.environ: fs_subjects_dir = os.environ["SUBJECTS_DIR"] else: raise ValueError("Missing <SUBJECTS_DIR>: set the $SUBJECTS_DIR " "environment variable for Freesurfer or pass it " "as an argument.") # Raise an Exception if BrainsuiteCheck is not installed check_brainsuite_installation() # Create the preprocessing output directory if not existing if not os.path.isdir(outdir): os.makedirs(outdir) ### Step 1 - Import files to Connectomist and choose q-space model raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model") dwi_data_import_and_qspace_sampling(raw_dwi_dir, dwi = dwi, bval = bval, bvec = bvec, manufacturer = "Siemens", # unused but required invertX = invertX, invertY = invertY, invertZ = invertZ, subject_id = subject_id) ### Step 2 --- Create a brain mask rough_mask_dir = os.path.join(outdir, "02-Rough_mask") dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir) ### Step 3 - Detect and correct outlying diffusion slices outliers_dir = os.path.join(outdir, "03-Outliers") dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir) # Export outliers.py path_outliers_py = os.path.join(outliers_dir, "outliers.py") shutil.copy(path_outliers_py, outdir) ### Step 4 - Eddy current and motion correction eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion") dwi_eddy_current_and_motion_correction(eddy_motion_dir, raw_dwi_dir, rough_mask_dir, outliers_dir) ### Step 5 - Convert Connectomist result to Nifti with bval/bvec dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir, filename = "dwi_ecc") ### Step 6 - Susceptibility correction using BrainSuite brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite") if not os.path.isdir(brainsuite_dir): os.mkdir(brainsuite_dir) dwi_wo_susceptibility, bval, bvec = \ brainsuite_susceptibility_correction(outdir = brainsuite_dir, dwi = dwi, bval = bval, bvec = bvec, subject_id = subject_id, fs_subjects_dir = fs_subjects_dir, qc_dir = outdir) ### Step 7 - move corrected diffusion to outdir dwi_preproc = os.path.join(outdir, "dwi.nii.gz") bval_preproc = os.path.join(outdir, "dwi.bval") bvec_preproc = os.path.join(outdir, "dwi.bvec") shutil.copyfile(dwi_wo_susceptibility, dwi_preproc) shutil.copyfile(bval, bval_preproc) shutil.copyfile(bvec, bvec_preproc) ### Step 8 - Create a T2 brain mask of preprocessed DWI data bet2_prefix = os.path.join(outdir, "nodif_brain") nodif_brain = os.path.join(bet2_prefix + ".nii.gz") nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz") bet2(dwi, bet2_prefix, f=0.25, m=True) ### Step 9 - clean intermediate directories if requested if delete_steps: intermediate_directories = [raw_dwi_dir, rough_mask_dir, outliers_dir, eddy_motion_dir, brainsuite_dir] for directory in intermediate_directories: shutil.rmtree(directory) return outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain, nodif_brain_mask
def brainsuite_susceptibility_correction(outdir, dwi, bval, bvec, subject_id, phase_enc_dir, subjects_dir=None, qc_dir=None, bdp_nthread=4): """ Assuming the beginning of the preprocessing was done with Connectomist up to Eddy current and motion correction, we now want to make susceptbility distortion correction using Brainsuite. Parameters ---------- outdir: str Path to directory where to output. dwi: str Path to the preprocessed diffusion-weighted Nifti. bval: str Path to the bval file associated to the Nifti. bvec: str Path to the bvec file associated to the Nifti. subject_id: str Subject identifier used in Freesurfer. phase_enc_dir: str In plane phase encoding direction, "y", "y-", "x" or "x-". subjects_dir: str, default None If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to bypass it, pass the path. qc_dir: str, default None Path to directory where to output snapshots for QC. By default in outdir. bdp_nthread: int, default 4 Number of threads for bdp (see bdp.sh --thread flag) """ # Freesurfer 'subjects_dir' has to be passed or set as environment variable subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir) # Check in plane phase encoding direction # The sign of the phase encoding direction has no impact in this strategy # e.g. for "+y" or "-y" use "y" possible_phase_enc_dirs = {"y", "x"} if phase_enc_dir not in possible_phase_enc_dirs: raise ValueError("Bad argument 'phase_enc_dir': {}, should be in {}." .format(phase_enc_dir, possible_phase_enc_dirs)) # Set and check path to T1 brain-only volume from Freesurfer (mgz format) t1_brain_mgz = os.path.join(subjects_dir, subject_id, "mri/brain.mgz") if not os.path.isfile(t1_brain_mgz): raise Exception("Missing file: {}".format(t1_brain_mgz)) # Convert Freesurfer T1 to Nifti with reorientation to RAS (to be in the # same orientation as the diffusion data) t1_brain_RAS_nii = os.path.join(outdir, "t1_brain.nii.gz") cmd = ["mri_convert", t1_brain_mgz, t1_brain_RAS_nii, "--out_orientation", "RAS"] run_freesurfer_cmd(cmd, subjects_dir=subjects_dir) # Run bfc (bias correction: required by BrainSuite) t1_bfc = os.path.join(outdir, "t1_brain.bfc.nii.gz") cmd = ["bfc", "-i", t1_brain_RAS_nii, "-o", t1_bfc] subprocess.check_call(cmd) # Extract brain from the nodif volume with FSL bet2 nodif_brain = os.path.join(outdir, "nodif_brain.nii.gz") bet2(dwi, nodif_brain, f=0.25, m=False) # Run bdp.sh: registration + diffusion model cmd = ["bdp.sh", t1_bfc, "--nii", dwi, "--bval", bval, "--bvec", bvec, "--dwi-mask", nodif_brain, "--dir=%s" % phase_enc_dir, "--threads=%i" % bdp_nthread] subprocess.check_call(cmd) # Path to files of interest, created by BrainSuite bdp.sh dwi_wo_susceptibility = os.path.join( outdir, "t1_brain.dwi.RAS.correct.nii.gz") ############### # Quality check: create snapshots to visually assert the registration # quality if qc_dir is None: qc_dir = outdir # The snapshots won't contain all slices, half of them nb_slices_in_z = nibabel.load(nodif_brain).get_shape()[2] # Path to registered T1 t1_to_dif = os.path.join(outdir, "t1_brain.D_coord.nii.gz") # First png: T1 registered in diffusion with nodif edges t1_with_nodif_edges_png = os.path.join(qc_dir, "t1_with_nodif_edges.png") plot_image(t1_to_dif, edge_file=nodif_brain, snap_file=t1_with_nodif_edges_png, name="T1 in diffusion + edges of nodif", cut_coords=nb_slices_in_z - 2) # Second png: nodif with edges of T1 registered in diffusion nodif_with_t1_edges_png = os.path.join(qc_dir, "nodif_with_t1_edges.png") plot_image(nodif_brain, edge_file=t1_to_dif, snap_file=nodif_with_t1_edges_png, name="nodif + edges of registered T1", cut_coords=nb_slices_in_z - 2) return dwi_wo_susceptibility, bval, bvec
def complete_preproc_wo_fieldmap(outdir, dwi, bval, bvec, phase_enc_dir, subject_id, subjects_dir=None, invertX=True, invertY=False, invertZ=False, delete_steps=False): """ Function that runs all preprocessing steps using Connectomist but with BrainSuite for the correction of susceptibility distortions. Parameters ---------- outdir: str Path to directory where all the preprocessing will be done. dwi: str path to input diffusion-weighted Nifti data. bval: str Path to the Nifti's associated .bval file. bvec: str Ppath to Nifti's associated .bval file. phase_enc_dir: str In plane phase encoding direction, "y", "y-", "x" or "x-". subject_id: str Subject identifier used in Freesurfer. subjects_dir: Str, default None If the Freesurfer $SUBJECTS_DIR environment variable is not set, or to bypass it, pass the path. invertX: bool, default True If True invert x-axis in diffusion model. invertY: bool, default False Same as invertX but for y-axis. invertZ: bool, default False Same as invertX but for z-axis. delete_steps: bool If True remove all intermediate files and directories at the end of preprocessing, to keep only selected files: - preprocessed Nifti + bval + bvec + outliers.py + nodif_brain*.nii.gz Returns ------- outdir: str, Path to directory with the preprocessed files. <unit> <output name="preproc_dwi" type="File" /> <output name="preproc_bval" type="File" /> <output name="preproc_bvec" type="File" /> <input name="outdir" type="Directory" /> <input name="dwi" type="File" /> <input name="bval" type="File" /> <input name="bvec" type="File" /> <input name="phase_enc_dir" type="Str" /> <input name="subject_id" type="Str" /> <input name="subjects_dir" type="Str" /> <input name="invertX" type="Bool" /> <input name="invertY" type="Bool" /> <input name="invertZ" type="Bool" /> <input name="delete_steps" type="Bool" /> </unit> """ # Step 0 - Initialization # Freesurfer 'subjects_dir' has to be passed or set as environment variable subjects_dir = get_or_check_freesurfer_subjects_dir(subjects_dir) # Raise an Exception if BrainsuiteCheck is not installed check_brainsuite_installation() # Create the preprocessing output directory if not existing if not os.path.isdir(outdir): os.makedirs(outdir) # Step 1 - Import files to Connectomist and choose q-space model raw_dwi_dir = os.path.join(outdir, "01-Import_and_qspace_model") # The manufacturer option is unused (use brainsuite for susceptibility # correction) but required dwi_data_import_and_qspace_sampling(raw_dwi_dir, dwi=dwi, bval=bval, bvec=bvec, manufacturer="Siemens", invertX=invertX, invertY=invertY, invertZ=invertZ, subject_id=subject_id) # Step 2 - Create a brain mask rough_mask_dir = os.path.join(outdir, "02-Rough_mask") dwi_rough_mask_extraction(rough_mask_dir, raw_dwi_dir) # Step 3 - Detect and correct outlying diffusion slices outliers_dir = os.path.join(outdir, "03-Outliers") dwi_outlier_detection(outliers_dir, raw_dwi_dir, rough_mask_dir) # Export outliers.py path_outliers_py = os.path.join(outliers_dir, "outliers.py") shutil.copy(path_outliers_py, outdir) # Step 4 - Eddy current and motion correction eddy_motion_dir = os.path.join(outdir, "04-Eddy_current_and_motion") dwi_eddy_current_and_motion_correction(eddy_motion_dir, raw_dwi_dir, rough_mask_dir, outliers_dir) # Step 5 - Convert Connectomist result to Nifti with bval/bvec dwi, bval, bvec = export_eddy_motion_results_to_nifti(eddy_motion_dir, filename="dwi_ecc") # Step 6 - Susceptibility correction using BrainSuite brainsuite_dir = os.path.join(outdir, "05-Suceptibility_BrainSuite") if not os.path.isdir(brainsuite_dir): os.mkdir(brainsuite_dir) dwi_wo_susceptibility, bval, bvec = \ brainsuite_susceptibility_correction(outdir=brainsuite_dir, dwi=dwi, bval=bval, bvec=bvec, phase_enc_dir=phase_enc_dir, subject_id=subject_id, subjects_dir=subjects_dir, qc_dir=outdir) # Step 7 - move corrected diffusion to outdir dwi_preproc = os.path.join(outdir, "dwi.nii.gz") bval_preproc = os.path.join(outdir, "dwi.bval") bvec_preproc = os.path.join(outdir, "dwi.bvec") shutil.copyfile(dwi_wo_susceptibility, dwi_preproc) shutil.copyfile(bval, bval_preproc) shutil.copyfile(bvec, bvec_preproc) # Step 8 - Create a T2 brain mask of preprocessed DWI data bet2_prefix = os.path.join(outdir, "nodif_brain") nodif_brain = os.path.join(bet2_prefix + ".nii.gz") nodif_brain_mask = os.path.join(bet2_prefix + "_mask.nii.gz") bet2(dwi, bet2_prefix, f=0.25, m=True) # Step 9 - clean intermediate directories if requested if delete_steps: intermediate_directories = [raw_dwi_dir, rough_mask_dir, outliers_dir, eddy_motion_dir, brainsuite_dir] for directory in intermediate_directories: shutil.rmtree(directory) return (outdir, dwi_preproc, bval_preproc, bvec_preproc, nodif_brain, nodif_brain_mask)