def gen_tissue(self, wm_mask_existing, gm_mask_existing, overwrite): """ A function to segment and threshold tissue types from T1w. """ import time # Segment the t1w brain into probability maps if ( wm_mask_existing is not None and gm_mask_existing is not None and overwrite is False ): print("Existing segmentations detected...") gm_mask = regutils.check_orient_and_dims( gm_mask_existing, self.basedir_path, self.vox_size, overwrite=False) wm_mask = regutils.check_orient_and_dims( wm_mask_existing, self.basedir_path, self.vox_size, overwrite=False) else: try: maps = regutils.segment_t1w(self.t1w_brain, self.map_name) gm_mask = maps["gm_prob"] wm_mask = maps["wm_prob"] except RuntimeError as e: import sys print(e, "Segmentation failed. Does the input anatomical image " "still contained skull?" ) sys.exit(1) # Threshold GM to binary in func space t_img = nib.load(gm_mask) mask = math_img("img > 0.01", img=t_img) mask.to_filename(self.gm_mask_thr) self.gm_mask = regutils.apply_mask_to_image(gm_mask, self.gm_mask_thr, self.gm_mask) time.sleep(0.5) # Threshold WM to binary in dwi space t_img = nib.load(wm_mask) mask = math_img("img > 0.50", img=t_img) mask.to_filename(self.wm_mask_thr) time.sleep(0.5) self.wm_mask = regutils.apply_mask_to_image(wm_mask, self.wm_mask_thr, self.wm_mask) # Extract wm edge time.sleep(0.5) self.wm_edge = regutils.get_wm_contour(wm_mask, self.wm_mask_thr, self.wm_edge) return
def waymask2dwi_align( waymask, t1w_brain, ap_path, mni2t1w_warp, mni2t1_xfm, t1wtissue2dwi_xfm, waymask_in_t1w, waymask_in_dwi, B0_mask_tmp_path, template, simple, ): """ A function to perform alignment of a waymask from MNI space --> T1w --> dwi. """ import time from pynets.registration import reg_utils as regutils from nilearn.image import resample_to_img # Apply warp or transformer resulting from the inverse MNI->T1w created # earlier waymask_img = nib.load(waymask) template_img = nib.load(template) waymask_img_res = resample_to_img( waymask_img, template_img, ) waymask_res = f"{waymask.split('.nii')[0]}_res.nii.gz" nib.save(waymask_img_res, waymask_res) if simple is False: regutils.apply_warp(t1w_brain, waymask_res, waymask_in_t1w, warp=mni2t1w_warp) else: regutils.applyxfm(t1w_brain, waymask_res, mni2t1_xfm, waymask_in_t1w) time.sleep(0.5) # Apply transform from t1w to native dwi space regutils.applyxfm(ap_path, waymask_in_t1w, t1wtissue2dwi_xfm, waymask_in_dwi) time.sleep(0.5) waymask_in_dwi = regutils.apply_mask_to_image(waymask_in_dwi, B0_mask_tmp_path, waymask_in_dwi) return waymask_in_dwi
def gen_mask(t1w_head, t1w_brain, mask): import time import os.path as op from pynets.registration import reg_utils as regutils from nilearn.image import math_img t1w_brain_mask = f"{op.dirname(t1w_head)}/t1w_brain_mask.nii.gz" img = nib.load(t1w_head) if mask is not None and op.isfile(mask): from nilearn.image import resample_to_img print(f"Using {mask}...") mask_img = nib.load(mask) nib.save(resample_to_img(mask_img, img), t1w_brain_mask) else: # Perform skull-stripping if mask not provided. img = nib.load(t1w_head) t1w_data = img.get_fdata().astype('float32') try: t1w_brain_mask = deep_skull_strip(t1w_data, t1w_brain_mask, img) except RuntimeError: try: print('Deepbrain extraction failed...') except ValueError: import sys sys.exit(1) del t1w_data # Threshold T1w brain to binary in anat space t_img = nib.load(t1w_brain_mask) img = math_img("img > 0.0", img=t_img) img.to_filename(t1w_brain_mask) t_img.uncache() time.sleep(0.5) t1w_brain = regutils.apply_mask_to_image(t1w_head, t1w_brain_mask, t1w_brain) time.sleep(0.5) assert op.isfile(t1w_brain) assert op.isfile(t1w_brain_mask) return t1w_brain, t1w_brain_mask
def tissue2dwi_align(self): """ A function to perform alignment of ventricle ROI's from MNI space --> dwi and CSF from T1w space --> dwi. First generates and performs dwi space alignment of avoidance/waypoint masks for tractography. First creates ventricle ROI. Then creates transforms from stock MNI template to dwi space. For this to succeed, must first have called both t1w2dwi_align. """ import sys import time import os.path as op # Register Lateral Ventricles and Corpus Callosum rois to t1w if not op.isfile(self.mni_atlas): raise FileNotFoundError("FSL atlas for ventricle reference not" " found!") # Create transform to MNI atlas to T1w using flirt. This will be use to # transform the ventricles to dwi space. regutils.align( self.mni_atlas, self.input_mni_brain, xfm=self.xfm_roi2mni_init, init=None, bins=None, dof=6, cost="mutualinfo", searchrad=True, interp="spline", out=None, ) time.sleep(0.5) if sys.platform.startswith('win') is False: try: nib.load(self.mni_vent_loc) except indexed_gzip.ZranError as e: print(e, f"\nCannot load ventricle ROI. Do you have git-lfs " f"installed?") sys.exit(1) else: try: nib.load(self.mni_vent_loc) except ImportError as e: print(e, f"\nCannot load ventricle ROI. Do you have git-lfs " f"installed?") sys.exit(1) # Create transform to align roi to mni and T1w using flirt regutils.applyxfm( self.input_mni_brain, self.mni_vent_loc, self.xfm_roi2mni_init, self.vent_mask_mni, ) time.sleep(0.5) if self.simple is False: # Apply warp resulting from the inverse MNI->T1w created earlier regutils.apply_warp( self.t1w_brain, self.vent_mask_mni, self.vent_mask_t1w, warp=self.mni2t1w_warp, interp="nn", sup=True, ) time.sleep(0.5) if sys.platform.startswith('win') is False: try: nib.load(self.corpuscallosum) except indexed_gzip.ZranError as e: print(e, f"\nCannot load Corpus Callosum ROI. " f"Do you have git-lfs installed?") sys.exit(1) else: try: nib.load(self.corpuscallosum) except ImportError as e: print(e, f"\nCannot load Corpus Callosum ROI. " f"Do you have git-lfs installed?") sys.exit(1) regutils.apply_warp( self.t1w_brain, self.corpuscallosum, self.corpuscallosum_mask_t1w, warp=self.mni2t1w_warp, interp="nn", sup=True, ) else: regutils.applyxfm( self.vent_mask_mni, self.t1w_brain, self.mni2t1_xfm, self.vent_mask_t1w) time.sleep(0.5) regutils.applyxfm( self.corpuscallosum, self.t1w_brain, self.mni2t1_xfm, self.corpuscallosum_mask_t1w, ) time.sleep(0.5) # Applyxfm tissue maps to dwi space if self.t1w_brain_mask is not None: regutils.applyxfm( self.ap_path, self.t1w_brain_mask, self.t1wtissue2dwi_xfm, self.t1w_brain_mask_in_dwi, ) time.sleep(0.5) regutils.applyxfm( self.ap_path, self.vent_mask_t1w, self.t1wtissue2dwi_xfm, self.vent_mask_dwi) time.sleep(0.5) regutils.applyxfm( self.ap_path, self.csf_mask, self.t1wtissue2dwi_xfm, self.csf_mask_dwi) time.sleep(0.5) regutils.applyxfm( self.ap_path, self.gm_mask, self.t1wtissue2dwi_xfm, self.gm_in_dwi ) time.sleep(0.5) regutils.applyxfm( self.ap_path, self.wm_mask, self.t1wtissue2dwi_xfm, self.wm_in_dwi ) time.sleep(0.5) regutils.applyxfm( self.ap_path, self.corpuscallosum_mask_t1w, self.t1wtissue2dwi_xfm, self.corpuscallosum_dwi, ) time.sleep(0.5) # Threshold WM to binary in dwi space thr_img = nib.load(self.wm_in_dwi) thr_img = math_img("img > 0.10", img=thr_img) nib.save(thr_img, self.wm_in_dwi_bin) # Threshold GM to binary in dwi space thr_img = nib.load(self.gm_in_dwi) thr_img = math_img("img > 0.15", img=thr_img) nib.save(thr_img, self.gm_in_dwi_bin) # Threshold CSF to binary in dwi space thr_img = nib.load(self.csf_mask_dwi) thr_img = math_img("img > 0.95", img=thr_img) nib.save(thr_img, self.csf_mask_dwi_bin) # Threshold WM to binary in dwi space self.wm_in_dwi = regutils.apply_mask_to_image(self.wm_in_dwi, self.wm_in_dwi_bin, self.wm_in_dwi) time.sleep(0.5) # Threshold GM to binary in dwi space self.gm_in_dwi = regutils.apply_mask_to_image(self.gm_in_dwi, self.gm_in_dwi_bin, self.gm_in_dwi) time.sleep(0.5) # Threshold CSF to binary in dwi space self.csf_mask = regutils.apply_mask_to_image(self.csf_mask_dwi, self.csf_mask_dwi_bin, self.csf_mask_dwi) time.sleep(0.5) # Create ventricular CSF mask print("Creating Ventricular CSF mask...") os.system( f"fslmaths {self.vent_mask_dwi} -kernel sphere 10 -ero " f"-bin {self.vent_mask_dwi}" ) time.sleep(1) os.system( f"fslmaths {self.csf_mask_dwi} -add {self.vent_mask_dwi} " f"-bin {self.vent_csf_in_dwi}" ) time.sleep(1) print("Creating Corpus Callosum mask...") os.system( f"fslmaths {self.corpuscallosum_dwi} -mas {self.wm_in_dwi_bin} " f"-sub {self.vent_csf_in_dwi} " f"-bin {self.corpuscallosum_dwi}") time.sleep(1) # Create gm-wm interface image os.system( f"fslmaths {self.gm_in_dwi_bin} -mul {self.wm_in_dwi_bin} " f"-add {self.corpuscallosum_dwi} " f"-mas {self.B0_mask} -bin {self.wm_gm_int_in_dwi}") time.sleep(1) return
def atlas2t1w2dwi_align( uatlas, uatlas_parcels, atlas, t1w_brain, t1w_brain_mask, mni2t1w_warp, t1_aligned_mni, ap_path, t1w2dwi_bbr_xfm, mni2t1_xfm, t1w2dwi_xfm, wm_gm_int_in_dwi, aligned_atlas_t1mni, aligned_atlas_skull, dwi_aligned_atlas, dwi_aligned_atlas_wmgm_int, B0_mask, mni2dwi_xfm, simple, ): """ A function to perform atlas alignment atlas --> T1 --> dwi. Tries nonlinear registration first, and if that fails, does a linear registration instead. For this to succeed, must first have called t1w2dwi_align. """ import time from nilearn.image import resample_to_img from pynets.core.utils import checkConsecutive from pynets.registration import reg_utils as regutils from nilearn.image import math_img from nilearn.masking import intersect_masks template_img = nib.load(t1_aligned_mni) if uatlas_parcels: atlas_img_orig = nib.load(uatlas_parcels) else: atlas_img_orig = nib.load(uatlas) old_count = len(np.unique(np.asarray(atlas_img_orig.dataobj))) uatlas_res_template = resample_to_img(atlas_img_orig, template_img, interpolation="nearest") uatlas_res_template = nib.Nifti1Image( np.asarray(uatlas_res_template.dataobj).astype('uint16'), affine=uatlas_res_template.affine, header=uatlas_res_template.header, ) nib.save(uatlas_res_template, aligned_atlas_t1mni) if simple is False: try: regutils.apply_warp( t1w_brain, aligned_atlas_t1mni, aligned_atlas_skull, warp=mni2t1w_warp, interp="nn", sup=True, mask=t1w_brain_mask, ) time.sleep(0.5) # Apply linear transformation from template to dwi space regutils.applyxfm(ap_path, aligned_atlas_skull, t1w2dwi_bbr_xfm, dwi_aligned_atlas, interp="nearestneighbour") time.sleep(0.5) except BaseException: print( "Warning: Atlas is not in correct dimensions, or input is low" " quality,\nusing linear template registration.") combine_xfms(mni2t1_xfm, t1w2dwi_bbr_xfm, mni2dwi_xfm) time.sleep(0.5) regutils.applyxfm(ap_path, aligned_atlas_t1mni, mni2dwi_xfm, dwi_aligned_atlas, interp="nearestneighbour") time.sleep(0.5) else: combine_xfms(mni2t1_xfm, t1w2dwi_xfm, mni2dwi_xfm) time.sleep(0.5) regutils.applyxfm(ap_path, aligned_atlas_t1mni, mni2dwi_xfm, dwi_aligned_atlas, interp="nearestneighbour") time.sleep(0.5) atlas_img = nib.load(dwi_aligned_atlas) wm_gm_img = nib.load(wm_gm_int_in_dwi) wm_gm_mask_img = math_img("img > 0", img=wm_gm_img) atlas_mask_img = math_img("img > 0", img=atlas_img) atlas_img_corr = nib.Nifti1Image( np.asarray(atlas_img.dataobj).astype('uint16'), affine=atlas_img.affine, header=atlas_img.header, ) # Get the union of masks dwi_aligned_atlas_wmgm_int_img = intersect_masks( [wm_gm_mask_img, atlas_mask_img], threshold=0, connected=False) nib.save(atlas_img_corr, dwi_aligned_atlas) nib.save(dwi_aligned_atlas_wmgm_int_img, dwi_aligned_atlas_wmgm_int) dwi_aligned_atlas = regutils.apply_mask_to_image(dwi_aligned_atlas, B0_mask, dwi_aligned_atlas) time.sleep(0.5) dwi_aligned_atlas_wmgm_int = regutils.apply_mask_to_image( dwi_aligned_atlas_wmgm_int, B0_mask, dwi_aligned_atlas_wmgm_int) time.sleep(0.5) final_dat = atlas_img_corr.get_fdata() unique_a = sorted(set(np.array(final_dat.flatten().tolist()))) if not checkConsecutive(unique_a): print("Warning! Non-consecutive integers found in parcellation...") new_count = len(unique_a) diff = np.abs(np.int(float(new_count) - float(old_count))) print(f"Previous label count: {old_count}") print(f"New label count: {new_count}") print(f"Labels dropped: {diff}") atlas_img.uncache() atlas_img_corr.uncache() atlas_img_orig.uncache() atlas_mask_img.uncache() wm_gm_img.uncache() wm_gm_mask_img.uncache() return dwi_aligned_atlas_wmgm_int, dwi_aligned_atlas, aligned_atlas_t1mni
def atlas2t1w_align(uatlas, uatlas_parcels, atlas, t1w_brain, t1w_brain_mask, t1_aligned_mni, mni2t1w_warp, mni2t1_xfm, gm_mask, aligned_atlas_t1mni, aligned_atlas_skull, aligned_atlas_gm, simple, gm_fail_tol=5): """ A function to perform atlas alignment from atlas --> T1w. """ import time from pynets.registration import reg_utils as regutils from nilearn.image import resample_to_img # from pynets.core.utils import checkConsecutive template_img = nib.load(t1_aligned_mni) if uatlas_parcels: atlas_img_orig = nib.load(uatlas_parcels) else: atlas_img_orig = nib.load(uatlas) # old_count = len(np.unique(np.asarray(atlas_img_orig.dataobj))) uatlas_res_template = resample_to_img(atlas_img_orig, template_img, interpolation="nearest") uatlas_res_template = nib.Nifti1Image( np.asarray(uatlas_res_template.dataobj).astype('uint16'), affine=uatlas_res_template.affine, header=uatlas_res_template.header, ) nib.save(uatlas_res_template, aligned_atlas_t1mni) if simple is False: try: regutils.apply_warp( t1w_brain, aligned_atlas_t1mni, aligned_atlas_skull, warp=mni2t1w_warp, interp="nn", sup=True, mask=t1w_brain_mask, ) time.sleep(0.5) except BaseException: print( "Warning: Atlas is not in correct dimensions, or input is low " "quality,\nusing linear template registration.") regutils.applyxfm(t1w_brain, aligned_atlas_t1mni, mni2t1_xfm, aligned_atlas_skull, interp="nearestneighbour") time.sleep(0.5) else: regutils.applyxfm(t1w_brain, aligned_atlas_t1mni, mni2t1_xfm, aligned_atlas_skull, interp="nearestneighbour") time.sleep(0.5) # aligned_atlas_gm = regutils.apply_mask_to_image(aligned_atlas_skull, # gm_mask, # aligned_atlas_gm) aligned_atlas_gm = regutils.apply_mask_to_image(aligned_atlas_skull, t1w_brain_mask, aligned_atlas_gm) time.sleep(0.5) atlas_img = nib.load(aligned_atlas_gm) atlas_img_corr = nib.Nifti1Image( np.asarray(atlas_img.dataobj).astype('uint16'), affine=atlas_img.affine, header=atlas_img.header, ) nib.save(atlas_img_corr, aligned_atlas_gm) # final_dat = atlas_img_corr.get_fdata() # unique_a = sorted(set(np.array(final_dat.flatten().tolist()))) # # if not checkConsecutive(unique_a): # print("\nWarning! non-consecutive integers found in parcellation...") # new_count = len(unique_a) # diff = np.abs(np.int(float(new_count) - float(old_count))) # print(f"Previous label count: {old_count}") # print(f"New label count: {new_count}") # print(f"Labels dropped: {diff}") # if diff > gm_fail_tol: # print(f"Grey-Matter mask too restrictive >{str(gm_fail_tol)} for this " # f"parcellation. Falling back to the T1w mask...") # aligned_atlas_gm = regutils.apply_mask_to_image(aligned_atlas_skull, # t1w_brain_mask, # aligned_atlas_gm) # time.sleep(5) template_img.uncache() atlas_img_orig.uncache() atlas_img.uncache() atlas_img_corr.uncache() return aligned_atlas_gm, aligned_atlas_skull
def t1w2dwi_align(self): """ A function to perform alignment from T1w_MNI --> DWI. Uses a local optimization cost function to get the two images close, and then uses bbr to obtain a good alignment of brain boundaries. Assumes input dwi is already preprocessed and brain extracted. """ import time self.ap_path = regutils.apply_mask_to_image(self.ap_path, self.B0_mask, self.ap_path) self.fa_path = regutils.apply_mask_to_image(self.fa_path, self.B0_mask, self.fa_path) # Align T1w-->DWI regutils.align( self.ap_path, self.t1w_brain, xfm=self.t1w2dwi_xfm, bins=None, interp="spline", dof=6, cost="mutualinfo", out=None, searchrad=True, sch=None, ) time.sleep(0.5) self.dwi2t1w_xfm = regutils.invert_xfm(self.t1w2dwi_xfm, self.dwi2t1w_xfm) time.sleep(0.5) if self.simple is False: # Flirt bbr try: print("Learning a Boundary-Based Mapping from T1w-->DWI ...") regutils.align( self.fa_path, self.t1w_brain, wmseg=self.wm_edge, xfm=self.dwi2t1w_bbr_xfm, init=self.dwi2t1w_xfm, bins=256, dof=7, searchrad=True, interp="spline", out=None, cost="bbr", sch="${FSLDIR}/etc/flirtsch/bbr.sch", ) time.sleep(0.5) self.t1w2dwi_bbr_xfm = regutils.invert_xfm( self.dwi2t1w_bbr_xfm, self.t1w2dwi_bbr_xfm) time.sleep(0.5) # Apply the alignment regutils.align( self.t1w_brain, self.ap_path, init=self.t1w2dwi_bbr_xfm, xfm=self.t1wtissue2dwi_xfm, bins=None, interp="spline", dof=7, cost="mutualinfo", out=self.t1w2dwi, searchrad=True, sch=None, ) time.sleep(0.5) except BaseException: # Apply the alignment regutils.align( self.t1w_brain, self.ap_path, init=self.t1w2dwi_xfm, xfm=self.t1wtissue2dwi_xfm, bins=None, interp="spline", dof=7, cost="mutualinfo", out=self.t1w2dwi, searchrad=True, sch=None, ) time.sleep(0.5) else: # Apply the alignment regutils.align( self.t1w_brain, self.ap_path, init=self.t1w2dwi_xfm, xfm=self.t1wtissue2dwi_xfm, bins=None, interp="spline", dof=6, cost="mutualinfo", out=self.t1w2dwi, searchrad=True, sch=None, ) time.sleep(0.5) self.t1w2dwi = regutils.apply_mask_to_image(self.t1w2dwi, self.B0_mask, self.t1w2dwi) return