def create_intersect_mask(show_list, meanepi, savingpath_percentile, layer, mask_dict, intersection): #We create the mask of intersection for all subject for each number of subvectors & each layer for number in show_list: mask_list = mask_dict[number] #in the doc, threshold = 1 will make the function compute the intersection of masks #threshold = 0 will compute the union of all mask in mask list if intersection == True: mask_inter = masking.intersect_masks(mask_list, threshold=1, connected=False) else: mask_inter = masking.intersect_masks(mask_list, threshold=0, connected=False) #We save the mask if intersection == True: mask_path = os.path.join( savingpath_percentile, 'mask_intersection_layer_' + str(layer) + '_number_' + str(number) + '.nii.gz') elif union == True: mask_path = os.path.join( savingpath_percentile, 'mask_union_layer_' + str(layer) + 'number' + str(number) + '.nii.gz') mask_inter.to_filename(mask_path) #we plot the results plotting.plot_roi(mask_inter, title='roi', bg_img=meanepi)
def create_clean_mask(self, num_std_dev=1.5): """ Create a subject-refined version of the clustering mask. """ import os from pynets.core import utils from nilearn.masking import intersect_masks from nilearn.image import index_img, math_img, resample_img mask_name = os.path.basename(self.clust_mask).split('.nii')[0] self.atlas = "%s%s%s%s%s" % (mask_name, '_', self.clust_type, '_k', str(self.k)) print("%s%s%s%s%s%s%s" % ('\nCreating atlas using ', self.clust_type, ' at cluster level ', str(self.k), ' for ', str(self.atlas), '...\n')) self._dir_path = utils.do_dir_path(self.atlas, self.func_file) self.uatlas = "%s%s%s%s%s%s%s%s" % (self._dir_path, '/', mask_name, '_clust-', self.clust_type, '_k', str(self.k), '.nii.gz') # Load clustering mask self._func_img.set_data_dtype(np.float32) func_vol_img = index_img(self._func_img, 1) func_vol_img.set_data_dtype(np.uint16) clust_mask_res_img = resample_img(nib.load(self.clust_mask), target_affine=func_vol_img.affine, target_shape=func_vol_img.shape, interpolation='nearest') clust_mask_res_img.set_data_dtype(np.uint16) func_data = np.asarray(func_vol_img.dataobj).astype('float32') func_int_thr = np.round(np.mean(func_data[func_data > 0]) - np.std(func_data[func_data > 0]) * num_std_dev, 3) if self.mask is not None: self._mask_img = nib.load(self.mask) self._mask_img.set_data_dtype(np.uint16) mask_res_img = resample_img(self._mask_img, target_affine=func_vol_img.affine, target_shape=func_vol_img.shape, interpolation='nearest') mask_res_img.set_data_dtype(np.uint16) self._clust_mask_corr_img = intersect_masks([math_img('img > ' + str(func_int_thr), img=func_vol_img), math_img('img > 0.01', img=clust_mask_res_img), math_img('img > 0.01', img=mask_res_img)], threshold=1, connected=False) self._clust_mask_corr_img.set_data_dtype(np.uint16) self._mask_img.uncache() mask_res_img.uncache() else: self._clust_mask_corr_img = intersect_masks([math_img('img > ' + str(func_int_thr), img=func_vol_img), math_img('img > 0.01', img=clust_mask_res_img)], threshold=1, connected=False) self._clust_mask_corr_img.set_data_dtype(np.uint16) nib.save(self._clust_mask_corr_img, "%s%s%s%s" % (self._dir_path, '/', mask_name, '.nii.gz')) del func_data func_vol_img.uncache() clust_mask_res_img.uncache() return self.atlas
def create_intersect(subject_list): fig = plt.figure(figsize=(20, 15)) mask_list = [] i = 1 for subject in tqdm(subject_list): if subject < 10: subject_str = '0' + str(subject) else: subject_str = str(subject) filename_mask = "/home/brain/datasets/SherlockMerlin_ds001110/sub-" + subject_str + "/func/sub-" + subject_str + "_task-SherlockMovie_bold_space-MNI152NLin2009cAsym_brainmask.nii.gz" filename_irm = "/home/brain/datasets/SherlockMerlin_ds001110/sub-" + subject_str + "/func/sub-" + subject_str + "_task-SherlockMovie_bold_space-MNI152NLin2009cAsym_preproc.nii.gz" meanepi = (index_img(filename_irm, 22)) mask_list.append(filename_mask) ax = plt.subplot(3, 6, i) plotting.plot_roi(filename_mask, bg_img=meanepi, axes=ax, figure=fig) i += 1 mask_inter = masking.intersect_masks(mask_list, threshold=1, connected=False) ax = plt.subplot(3, 6, i) plotting.plot_roi(mask_inter, bg_img=meanepi, axes=ax, figure=fig) saving_path = os.path.join(savingpath, 'mask_inter.nii.gz') mask_inter.to_filename(saving_path) return mask_inter
def collapse_mask(mask, auto_label=True, custom_mask=None): """collapse separate masks into one mask with multiple integers overlapping areas are ignored Args: mask: nibabel or Brain_Data instance custom_mask: nibabel instance or string to file path; optional Returns: out: Brain_Data instance of a mask with different integers indicating different masks """ from nltools.data import Brain_Data if not isinstance(mask, Brain_Data): if isinstance(mask, nib.Nifti1Image): mask = Brain_Data(mask, mask=custom_mask) else: raise ValueError("Make sure mask is a nibabel or Brain_Data " "instance.") if len(mask.shape()) > 1: if len(mask) > 1: out = mask.empty() # Create list of masks and find any overlaps m_list = [] for x in range(len(mask)): m_list.append(mask[x].to_nifti()) intersect = intersect_masks(m_list, threshold=1, connected=False) intersect = Brain_Data( nib.Nifti1Image(np.abs(intersect.get_data() - 1), intersect.get_affine()), mask=custom_mask, ) merge = [] if auto_label: # Combine all masks into sequential order # ignoring any areas of overlap for i in range(len(m_list)): merge.append( np.multiply( Brain_Data(m_list[i], mask=custom_mask).data, intersect.data) * (i + 1)) out.data = np.sum(np.array(merge).T, 1).astype(int) else: # Collapse masks using value as label for i in range(len(m_list)): merge.append( np.multiply( Brain_Data(m_list[i], mask=custom_mask).data, intersect.data)) out.data = np.sum(np.array(merge).T, 1) return out else: warnings.warn("Doesn't need to be collapased")
def similarity(self, image, method='correlation'): """ Calculate similarity of Brain_Data() instance with single Brain_Data or Nibabel image Args: image: Brain_Data or Nibabel instance of weight map Returns: pexp: Outputs a vector of pattern expression values """ if not isinstance(image, Brain_Data): if isinstance(image, nib.Nifti1Image): image = Brain_Data(image) else: raise ValueError( "Image is not a Brain_Data or nibabel instance") dim = image.shape() # Check to make sure masks are the same for each dataset and if not create a union mask # This might be handy code for a new Brain_Data method if np.sum(self.nifti_masker.mask_img.get_data() == 1) != np.sum( image.nifti_masker.mask_img.get_data() == 1): new_mask = intersect_masks( [self.nifti_masker.mask_img, image.nifti_masker.mask_img], threshold=1, connected=False) new_nifti_masker = NiftiMasker(mask_img=new_mask) data2 = new_nifti_masker.fit_transform(self.to_nifti()) image2 = new_nifti_masker.fit_transform(image.to_nifti()) else: data2 = self.data image2 = image.data # Calculate pattern expression if method is 'dot_product': if len(image2.shape) > 1: if image2.shape[0] > 1: pexp = [] for i in range(image2.shape[0]): pexp.append(np.dot(data2, image2[i, :])) pexp = np.array(pexp) else: pexp = np.dot(data2, image2) else: pexp = np.dot(data2, image2) elif method is 'correlation': if len(image2.shape) > 1: if image2.shape[0] > 1: pexp = [] for i in range(image2.shape[0]): pexp.append(pearson(image2[i, :], data2)) pexp = np.array(pexp) else: pexp = pearson(image2, data2) else: pexp = pearson(image2, data2) return pexp
def _intersect_clustering_mask(clustering, mask): "Take 3D Niimg clustering and bigger mask, output reduced mask" dat = clustering.get_data() new_ = np.zeros_like(dat) new_[dat > 0] = 1 clustering_mask = new_img_like(clustering, new_) return intersect_masks([clustering_mask, mask], threshold=1, connected=True)
def similarity(self, image, method='correlation'): """ Calculate similarity of Brain_Data() instance with single Brain_Data or Nibabel image Args: self: Brain_Data instance of data to be applied image: Brain_Data or Nibabel instance of weight map Returns: pexp: Outputs a vector of pattern expression values """ if not isinstance(image, Brain_Data): if isinstance(image, nib.Nifti1Image): image = Brain_Data(image) else: raise ValueError("Image is not a Brain_Data or nibabel instance") dim = image.shape() # Check to make sure masks are the same for each dataset and if not create a union mask # This might be handy code for a new Brain_Data method if np.sum(self.nifti_masker.mask_img.get_data()==1)!=np.sum(image.nifti_masker.mask_img.get_data()==1): new_mask = intersect_masks([self.nifti_masker.mask_img, image.nifti_masker.mask_img], threshold=1, connected=False) new_nifti_masker = NiftiMasker(mask_img=new_mask) data2 = new_nifti_masker.fit_transform(self.to_nifti()) image2 = new_nifti_masker.fit_transform(image.to_nifti()) else: data2 = self.data image2 = image.data # Calculate pattern expression if method is 'dot_product': if len(image2.shape) > 1: if image2.shape[0]>1: pexp = [] for i in range(image2.shape[0]): pexp.append(np.dot(data2, image2[i,:])) pexp = np.array(pexp) else: pexp = np.dot(data2, image2) else: pexp = np.dot(data2, image2) elif method is 'correlation': if len(image2.shape) > 1: if image2.shape[0]>1: pexp = [] for i in range(image2.shape[0]): pexp.append(pearson(image2[i,:], data2)) pexp = np.array(pexp) else: pexp = pearson(image2, data2) else: pexp = pearson(image2, data2) return pexp
def mask_roi(dir_path, roi, mask, img_file): """ Create derivative ROI based on intersection of roi and brain mask. Parameters ---------- dir_path : str Path to directory containing subject derivative data for given run. roi : str File path to binarized/boolean region-of-interest Nifti1Image file. mask : str Path to binarized/boolean brain mask Nifti1Image file. img_file : str File path to Nifti1Image to use to generate an epi-mask. Returns ------- roi : str File path to binarized/boolean region-of-interest Nifti1Image file, reduced to the spatial intersection with the input brain mask. """ import os.path as op from nilearn import masking from nilearn.masking import intersect_masks from nilearn.image import math_img, resample_img img_mask_path = f"{dir_path}/{op.basename(img_file).split('.')[0]}_mask.nii.gz" nib.save(masking.compute_epi_mask(img_file), img_mask_path) if roi and mask: print("Refining ROI...") _mask_img = nib.load(img_mask_path) _roi_img = nib.load(roi) roi_res_img = resample_img( _roi_img, target_affine=_mask_img.affine, target_shape=_mask_img.shape, interpolation="nearest", ) masked_roi_img = intersect_masks( [ math_img("img > 0.0", img=_mask_img), math_img("img > 0.0", img=roi_res_img), ], threshold=1, connected=False, ) roi_red_path = f"{dir_path}/{op.basename(roi).split('.')[0]}_mask.nii.gz" nib.save(masked_roi_img, roi_red_path) roi = roi_red_path return roi
def multivariate_similarity(self, images, method='ols'): """ Predict spatial distribution of Brain_Data() instance from linear combination of other Brain_Data() instances or Nibabel images Args: self: Brain_Data instance of data to be applied images: Brain_Data instance of weight map Returns: out: dictionary of regression statistics in Brain_Data instances {'beta','t','p','df','residual'} """ ## Notes: Should add ridge, and lasso, elastic net options options if len(self.shape()) > 1: raise ValueError("This method can only decompose a single brain image.") if not isinstance(images, Brain_Data): raise ValueError("Images are not a Brain_Data instance") dim = images.shape() # Check to make sure masks are the same for each dataset and if not create a union mask # This might be handy code for a new Brain_Data method if np.sum(self.nifti_masker.mask_img.get_data()==1)!=np.sum(images.nifti_masker.mask_img.get_data()==1): new_mask = intersect_masks([self.nifti_masker.mask_img, images.nifti_masker.mask_img], threshold=1, connected=False) new_nifti_masker = NiftiMasker(mask_img=new_mask) data2 = new_nifti_masker.fit_transform(self.to_nifti()) image2 = new_nifti_masker.fit_transform(images.to_nifti()) else: data2 = self.data image2 = images.data # Add intercept and transpose image2 = np.vstack((np.ones(image2.shape[1]),image2)).T # Calculate pattern expression if method is 'ols': b = np.dot(np.linalg.pinv(image2), data2) res = data2 - np.dot(image2,b) sigma = np.std(res,axis=0) stderr = np.dot(np.matrix(np.diagonal(np.linalg.inv(np.dot(image2.T,image2)))**.5).T,np.matrix(sigma)) t_out = b /stderr df = image2.shape[0]-image2.shape[1] p = 2*(1-t.cdf(np.abs(t_out),df)) return {'beta':b, 't':t_out, 'p':p, 'df':df, 'sigma':sigma, 'residual':res}
def fit_subject(sub, space): funcs = sorted( glob( f'../derivatives/fmriprep/{sub}/ses-*/func/*task-flocBLOCKED*space-{space}*desc-preproc_bold.nii.gz' )) masks = [f.replace('preproc_bold', 'brain_mask') for f in funcs] mask = masking.intersect_masks(masks, threshold=0.9) conf_files = [ f.split('space')[0] + 'desc-confounds_regressors.tsv' for f in funcs ] ccols = ['trans_x', 'trans_y', 'trans_z', 'rot_x', 'rot_y', 'rot_z'] confs = [pd.read_csv(c, sep='\t').loc[:, ccols] for c in conf_files] events = [ f"../{sub}/ses{f.split('ses')[1].split('func')[0]}/func/{op.basename(f).split('desc')[0]}events.tsv" for f in conf_files ] flm = FirstLevelModel(t_r=0.7, slice_time_ref=0.5, drift_model='cosine', high_pass=0.01, mask_img=mask, smoothing_fwhm=3.5, noise_model='ols', verbose=True) flm.fit(funcs, events, confs) con_defs = [('face', '4*face - object - character - body - place'), ('place', '4*place - object - face - character - body'), ('body', '4*body - object - face - character - place'), ('character', '4*character - object - face - place - body')] for name, df in con_defs: roi = flm.compute_contrast(df) f_out = f'../derivatives/floc/{sub}/rois/{sub}_task-flocBLOCKED_space-{space}_desc-{name}_zscore.nii.gz' if not op.isdir(op.dirname(f_out)): os.makedirs(op.dirname(f_out)) roi.to_filename(f_out)
def load_and_append_periodic_runs_single_subject(run1_boldfile, run2_boldfile, run1_maskfile, run2_maskfile, zscorewithinrun=True, connected_clusters=False): """ For a given subject, load the data from the first two runs (periodic stimulation), mask with a union of the run masks and z score if desired. """ # get union mask print('intersecting masks :', '\t', run1_maskfile, '\t', 'and', '\t',run2_maskfile) unionmask = intersect_masks([run1_maskfile, run2_maskfile], threshold=0, connected=connected_clusters) # load data, apply mask run1_arr = apply_mask(load_img(run1_boldfile), mask_img=unionmask).T run2_arr = apply_mask(load_img(run2_boldfile), mask_img=unionmask).T # zscore within run if desired if zscorewithinrun: for runimg in [run1_arr, run2_arr]: runimg = zscore(np.nan_to_num(runimg), axis=1) # concatenate runs sub_arr = np.concatenate((run1_arr, run2_arr), axis=1) print('finished loading masks: ', run1_maskfile, ' and ', run2_maskfile) return sub_arr, unionmask
def test_intersect_masks_filename(): # Create dummy masks mask_a = np.zeros((4, 4, 1), dtype=np.bool) mask_a[2:4, 2:4] = 1 mask_a_img = Nifti1Image(mask_a.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ mask_b = np.zeros((4, 4, 1), dtype=np.bool) mask_b[1:3, 1:3] = 1 mask_b_img = Nifti1Image(mask_b.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ with write_tmp_imgs(mask_a_img, mask_b_img, create_files=True)\ as filenames: mask_ab = np.zeros((4, 4, 1), dtype=np.bool) mask_ab[2, 2] = 1 mask_ab_ = intersect_masks(filenames, threshold=1.) assert_array_equal(mask_ab, get_data(mask_ab_))
def test_intersect_masks_filename(): # Create dummy masks mask_a = np.zeros((4, 4, 1), dtype=np.bool) mask_a[2:4, 2:4] = 1 mask_a_img = Nifti1Image(mask_a.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ mask_b = np.zeros((4, 4, 1), dtype=np.bool) mask_b[1:3, 1:3] = 1 mask_b_img = Nifti1Image(mask_b.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ with write_tmp_imgs(mask_a_img, mask_b_img, create_files=True)\ as filenames: mask_ab = np.zeros((4, 4, 1), dtype=np.bool) mask_ab[2, 2] = 1 mask_ab_ = intersect_masks(filenames, threshold=1.) assert_array_equal(mask_ab, mask_ab_.get_data())
struct_file = os.path.join(analysis_dir, subject, 'anat', '%s_desc-preproc_T1w.nii.gz' % subject) struct_mask_file = os.path.join(analysis_dir, subject, 'anat', '%s_desc-brain_mask.nii.gz' % subject) bold_mask_file = glob( os.path.join( analysis_dir, subject, 'ses-%d' % session, 'func', '%s_ses-%d_task-sequence_run-%d_space-T1w_desc-brain_mask.nii.gz' % (subject, session, run))) bold_file = path struct_img = resample_to_img(struct_file, bold_file) struct_mask_img = resample_to_img(struct_mask_file, bold_mask_file) bold_img = mean_img(bold_file) bold_mask_img = load_img(bold_mask_file) mask = intersect_masks((struct_mask_img, bold_mask_img)) masker = NiftiMasker(mask) x = masker.fit_transform(struct_img).ravel() y = masker.fit_transform(bold_img).ravel() ind = np.logical_and(x > 0, y > 0) x = x[ind] y = y[ind] MI = mutual_info_regression(x.reshape(-1, 1), y)[0] cor = pearsonr(x, y)[0] res = [subject, session, run, MI, cor] print(res) results.append(res) #plot_epi(struct_img, cut_coords = (0, 0, 0)) #plot_epi(bold_img, cut_coords = (0, 0, 0)) #plot_epi(mask, cut_coords = (0, 0, 0)) #sns.scatterplot(np.log(x), np.log(y))
def group_one_sample_t_test(masks, effects_maps, contrasts, output_dir, start_time=base_reporter.pretty_time(), **kwargs): """ Runs a one-sample t-test procedure for group analysis. Here, we are for each experimental condition, only interested refuting the null hypothesis H0: "The average effect accross the subjects is zero!" Parameters ---------- masks: list of strings or nibabel image objects subject masks, one per subject effects_maps: list of dicts of lists effects maps from subject-level GLM; each entry is a dictionary; each entry (indexed by condition id) of this dictionary is the filename (or correspinding nibabel image object) for the effects maps for that condition (aka contrast),for that subject contrasts: dictionary of array_likes contrasts vectors, indexed by condition id kwargs: dict_like kwargs for plot_stats_map API """ # make output directory if not os.path.exists(output_dir): os.makedirs(output_dir) assert len(masks) == len(effects_maps), (len(masks), len(effects_maps)) # compute group mask group_mask = intersect_masks(masks) # construct design matrix (only one covariate, namely the "mean effect") design_matrix = np.ones(len(effects_maps) )[:, np.newaxis] # only the intercept group_level_z_maps = {} group_level_t_maps = {} for contrast_id in contrasts: print "\tcontrast id: %s" % contrast_id # effects maps will be the input to the second level GLM first_level_image = nibabel.concat_images( [x[contrast_id] for x in effects_maps]) # fit 2nd level GLM for given contrast group_model = FirstLevelGLM(first_level_image, design_matrix, group_mask) group_model.fit(do_scaling=False, model='ols') # specify and estimate the contrast contrast_val = np.array(([[1.]]) ) # the only possible contrast ! z_map, t_map = group_model.contrast( contrast_val, con_id='one_sample %s' % contrast_id, output_z=True, output_stat=True) # save map for map_type, map_img in zip(["z", "t"], [z_map, t_map]): map_dir = os.path.join(output_dir, '%s_maps' % map_type) if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join(map_dir, 'group_level_%s.nii.gz' % ( contrast_id)) print "\t\tWriting %s ..." % map_path nibabel.save(map_img, map_path) if map_type == "z": group_level_z_maps[contrast_id] = map_path elif map_type == "t": group_level_z_maps[contrast_id] = map_path # do stats report stats_report_filename = os.path.join(output_dir, "report_stats.html") generate_subject_stats_report(stats_report_filename, contrasts, group_level_z_maps, group_mask, start_time=start_time, **kwargs) print "\r\nStatistic report written to %s\r\n" % ( stats_report_filename) return group_level_z_maps
def test_intersect_masks(): """ Test the intersect_masks function """ # Create dummy masks mask_a = np.zeros((4, 4, 1), dtype=np.bool) mask_a[2:4, 2:4] = 1 mask_a_img = Nifti1Image(mask_a.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ mask_b = np.zeros((4, 4, 1), dtype=np.bool) mask_b[1:3, 1:3] = 1 mask_b_img = Nifti1Image(mask_b.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ mask_c = np.zeros((4, 4, 1), dtype=np.bool) mask_c[:, 2] = 1 mask_c[0, 0] = 1 mask_c_img = Nifti1Image(mask_c.astype(int), np.eye(4)) # +---+---+---+---+ # | X | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ mask_ab = np.zeros((4, 4, 1), dtype=np.bool) mask_ab[2, 2] = 1 mask_ab_ = intersect_masks([mask_a_img, mask_b_img], threshold=1.) assert_array_equal(mask_ab, mask_ab_.get_data()) mask_abc = mask_a + mask_b + mask_c mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=0., connected=False) assert_array_equal(mask_abc, mask_abc_.get_data()) mask_abc[0, 0] = 0 mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=0.) assert_array_equal(mask_abc, mask_abc_.get_data()) mask_abc = mask_ab mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=1.) assert_array_equal(mask_abc, mask_abc_.get_data()) mask_abc[1, 2] = 1 mask_abc[3, 2] = 1 mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img]) assert_array_equal(mask_abc, mask_abc_.get_data())
def create_bestvoxels_mask(roi_img, localizer_img, toppercentile=25): """ select voxels within roi_img having the largest values in localizer_img """ masked_data = apply_mask(localizer_img, roi_img) threshold = scoreatpercentile(masked_data, 100 - toppercentile) mask = binarize_img(localizer_img, threshold) return intersect_masks((roi_img, mask), threshold=1)
def create_localizer_mask(roi_img, localizer_img, loc_threshold): """ select voxels within roi_img that have a value above loc_threshold in localizer_img """ locmask = binarize_img(localizer_img, loc_threshold) return intersect_masks((roi_img, locmask), threshold=1)
def prep_tissues(t1_mask, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi, tiss_class, cmc_step_size=0.2): """ Estimate a tissue classifier for tractography. Parameters ---------- t1_mask : str File path to a T1w mask. gm_in_dwi : str File path to grey-matter tissue segmentation Nifti1Image. vent_csf_in_dwi : str File path to ventricular CSF tissue segmentation Nifti1Image. wm_in_dwi : str File path to white-matter tissue segmentation Nifti1Image. tiss_class : str Tissue classification method. cmc_step_size : float Step size from CMC tissue classification method. Returns ------- tiss_classifier : obj Tissue classifier object. References ---------- .. [1] Zhang, Y., Brady, M. and Smith, S. Segmentation of Brain MR Images Through a Hidden Markov Random Field Model and the Expectation-Maximization Algorithm IEEE Transactions on Medical Imaging, 20(1): 45-56, 2001 .. [2] Avants, B. B., Tustison, N. J., Wu, J., Cook, P. A. and Gee, J. C. An open source multivariate framework for n-tissue segmentation with evaluation on public data. Neuroinformatics, 9(4): 381-400, 2011. """ try: import cPickle as pickle except ImportError: import _pickle as pickle from dipy.tracking.stopping_criterion import ActStoppingCriterion, CmcStoppingCriterion, BinaryStoppingCriterion from nilearn.masking import intersect_masks from nilearn.image import math_img # Loads mask mask_img = nib.load(t1_mask) # Load tissue maps and prepare tissue classifier wm_img = nib.load(wm_in_dwi) gm_img = nib.load(gm_in_dwi) gm_mask_data = np.asarray(gm_img.dataobj) wm_mask_data = np.asarray(wm_img.dataobj) vent_csf_in_dwi_data = np.asarray(nib.load(vent_csf_in_dwi).dataobj) if tiss_class == 'act': background = np.ones(mask_img.shape) background[(gm_mask_data + wm_mask_data + vent_csf_in_dwi_data) > 0] = 0 gm_mask_data[background > 0] = 1 tiss_classifier = ActStoppingCriterion(gm_mask_data, vent_csf_in_dwi_data) del background elif tiss_class == 'bin': tiss_classifier = BinaryStoppingCriterion(np.asarray(intersect_masks([math_img('img > 0.0', img=mask_img), math_img('img > 0.0', img=wm_img)], threshold=1, connected=False).dataobj)) elif tiss_class == 'cmc': voxel_size = np.average(mask_img.header['pixdim'][1:4]) tiss_classifier = CmcStoppingCriterion.from_pve(wm_mask_data, gm_mask_data, vent_csf_in_dwi_data, step_size=cmc_step_size, average_voxel_size=voxel_size) elif tiss_class == 'wb': tiss_classifier = BinaryStoppingCriterion(np.asarray(mask_img.dataobj).astype('bool')) else: raise ValueError('Tissue classifier cannot be none.') del gm_mask_data, wm_mask_data, vent_csf_in_dwi_data mask_img.uncache() gm_img.uncache() wm_img.uncache() return tiss_classifier
def track_ensemble(target_samples, atlas_data_wm_gm_int, labels_im_file, recon_path, sphere, directget, curv_thr_list, step_list, track_type, maxcrossing, roi_neighborhood_tol, min_length, waymask, B0_mask, t1w2dwi, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi, tiss_class, cache_dir): """ Perform native-space ensemble tractography, restricted to a vector of ROI masks. target_samples : int Total number of streamline samples specified to generate streams. atlas_data_wm_gm_int : str File path to Nifti1Image in T1w-warped native diffusion space, restricted to wm-gm interface. parcels : list List of 3D boolean numpy arrays of atlas parcellation ROI masks from a Nifti1Image in T1w-warped native diffusion space. recon_path : str File path to diffusion reconstruction model. tiss_classifier : str Tissue classification method. sphere : obj DiPy object for modeling diffusion directions on a sphere. directget : str The statistical approach to tracking. Options are: det (deterministic), closest (clos), and prob (probabilistic). curv_thr_list : list List of integer curvature thresholds used to perform ensemble tracking. step_list : list List of float step-sizes used to perform ensemble tracking. track_type : str Tracking algorithm used (e.g. 'local' or 'particle'). maxcrossing : int Maximum number if diffusion directions that can be assumed per voxel while tracking. roi_neighborhood_tol : float Distance (in the units of the streamlines, usually mm). If any coordinate in the streamline is within this distance from the center of any voxel in the ROI, the filtering criterion is set to True for this streamline, otherwise False. Defaults to the distance between the center of each voxel and the corner of the voxel. min_length : int Minimum fiber length threshold in mm. waymask_data : ndarray Tractography constraint mask array in native diffusion space. B0_mask_data : ndarray B0 brain mask data. n_seeds_per_iter : int Number of seeds from which to initiate tracking for each unique ensemble combination. By default this is set to 250. max_length : int Maximum number of steps to restrict tracking. particle_count pft_back_tracking_dist : float Distance in mm to back track before starting the particle filtering tractography. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 2 mm. pft_front_tracking_dist : float Distance in mm to run the particle filtering tractography after the the back track distance. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 1 mm. particle_count : int Number of particles to use in the particle filter. min_separation_angle : float The minimum angle between directions [0, 90]. Returns ------- streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. References ---------- .. [1] Takemura, H., Caiafa, C. F., Wandell, B. A., & Pestilli, F. (2016). Ensemble Tractography. PLoS Computational Biology. https://doi.org/10.1371/journal.pcbi.1004692 """ import os import gc import time import warnings from joblib import Parallel, delayed import itertools from pynets.dmri.track import run_tracking from colorama import Fore, Style from pynets.dmri.utils import generate_sl from nibabel.streamlines.array_sequence import concatenate, ArraySequence from pynets.core.utils import save_3d_to_4d from nilearn.masking import intersect_masks from nilearn.image import math_img from pynets.core.utils import load_runconfig warnings.filterwarnings("ignore") tmp_files_dir = f"{cache_dir}/tmp_files" joblib_dir = f"{cache_dir}/joblib_tracking" os.makedirs(tmp_files_dir, exist_ok=True) os.makedirs(joblib_dir, exist_ok=True) hardcoded_params = load_runconfig() nthreads = hardcoded_params["nthreads"][0] n_seeds_per_iter = \ hardcoded_params['tracking']["n_seeds_per_iter"][0] max_length = \ hardcoded_params['tracking']["max_length"][0] pft_back_tracking_dist = \ hardcoded_params['tracking']["pft_back_tracking_dist"][0] pft_front_tracking_dist = \ hardcoded_params['tracking']["pft_front_tracking_dist"][0] particle_count = \ hardcoded_params['tracking']["particle_count"][0] min_separation_angle = \ hardcoded_params['tracking']["min_separation_angle"][0] min_streams = \ hardcoded_params['tracking']["min_streams"][0] timeout = hardcoded_params['tracking']["track_timeout"][0] all_combs = list(itertools.product(step_list, curv_thr_list)) # Construct seeding mask seeding_mask = f"{tmp_files_dir}/seeding_mask.nii.gz" if waymask is not None and os.path.isfile(waymask): waymask_img = math_img("img > 0.0075", img=nib.load(waymask)) waymask_img.to_filename(waymask) atlas_data_wm_gm_int_img = intersect_masks( [ waymask_img, math_img("img > 0.001", img=nib.load(atlas_data_wm_gm_int)), math_img("img > 0.001", img=nib.load(labels_im_file)) ], threshold=1, connected=False, ) nib.save(atlas_data_wm_gm_int_img, seeding_mask) else: atlas_data_wm_gm_int_img = intersect_masks( [ math_img("img > 0.001", img=nib.load(atlas_data_wm_gm_int)), math_img("img > 0.001", img=nib.load(labels_im_file)) ], threshold=1, connected=False, ) nib.save(atlas_data_wm_gm_int_img, seeding_mask) tissues4d = save_3d_to_4d([ B0_mask, labels_im_file, seeding_mask, t1w2dwi, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi ]) # Commence Ensemble Tractography start = time.time() stream_counter = 0 all_streams = [] ix = 0 try: while float(stream_counter) < float(target_samples) and \ float(ix) < 0.50*float(len(all_combs)): with Parallel(n_jobs=nthreads, backend='loky', mmap_mode='r+', temp_folder=joblib_dir, verbose=0, timeout=timeout) as parallel: out_streams = parallel( delayed(run_tracking) (i, recon_path, n_seeds_per_iter, directget, maxcrossing, max_length, pft_back_tracking_dist, pft_front_tracking_dist, particle_count, roi_neighborhood_tol, waymask, min_length, track_type, min_separation_angle, sphere, tiss_class, tissues4d, tmp_files_dir) for i in all_combs) out_streams = [ i for i in out_streams if i is not None and i is not ArraySequence() and len(i) > 0 ] if len(out_streams) > 1: out_streams = concatenate(out_streams, axis=0) if len(out_streams) < min_streams: ix += 2 print(f"Fewer than {min_streams} streamlines tracked " f"on last iteration with cache directory: " f"{cache_dir}. Loosening tolerance and " f"anatomical constraints. Check {tissues4d} or " f"{recon_path} for errors...") # if track_type != 'particle': # tiss_class = 'wb' roi_neighborhood_tol = float(roi_neighborhood_tol) * 1.25 # min_length = float(min_length) * 0.9875 continue else: ix -= 1 # Append streamline generators to prevent exponential growth # in memory consumption all_streams.extend([generate_sl(i) for i in out_streams]) stream_counter += len(out_streams) del out_streams print("%s%s%s%s" % ( "\nCumulative Streamline Count: ", Fore.CYAN, stream_counter, "\n", )) gc.collect() print(Style.RESET_ALL) os.system(f"rm -rf {joblib_dir}/*") except BaseException: os.system(f"rm -rf {tmp_files_dir} &") return None if ix >= 0.75*len(all_combs) and \ float(stream_counter) < float(target_samples): print(f"Tractography failed. >{len(all_combs)} consecutive sampling " f"iterations with few streamlines.") os.system(f"rm -rf {tmp_files_dir} &") return None else: os.system(f"rm -rf {tmp_files_dir} &") print("Tracking Complete: ", str(time.time() - start)) del parallel, all_combs gc.collect() if stream_counter != 0: print('Generating final ArraySequence...') return ArraySequence([ArraySequence(i) for i in all_streams]) else: print('No streamlines generated!') return None
subs = sorted([os.path.basename(s) for s in glob('../derivatives/fmriprep/sub-??')]) R = [] for sub in subs: funcs = sorted(glob(f'../derivatives/fmriprep/{sub}/ses-*/func/*task-face*MNI*desc-preproc_bold.nii.gz')) confs = sorted(glob(f'../derivatives/fmriprep/{sub}/ses-*/func/*task-face*desc-confounds_regressors.tsv')) masks = [f.replace('preproc_bold', 'brain_mask') for f in funcs] events = sorted(glob(f'../{sub}/ses-*/func/*task-face*events.tsv')) cols = ['rot_x', 'rot_y', 'rot_z', 'trans_x', 'trans_y', 'trans_z'] confs = [pd.read_csv(c, sep='\t').loc[:, cols] for c in confs] events = [pd.read_csv(e, sep='\t').drop('trial_type', axis=1).rename({'expression': 'trial_type'}, axis=1) for e in events] events = [e.loc[~e['trial_type'].isna(), :] for e in events] print(events) mask = masking.intersect_masks(masks, threshold=1) flm = FirstLevelModel( t_r=0.7, slice_time_ref=0.5, hrf_model='glover', drift_model='cosine', high_pass=0.01, noise_model='ols', mask_img=mask, verbose=True, smoothing_fwhm=4, n_jobs=10 ) flm.fit(funcs, confounds=confs, events=events) con = flm.compute_contrast('smiling - neutral') #roi = image.resample_to_img(roi, con, interpolation='nearest')
def test_intersect_masks(): """ Test the intersect_masks function """ # Create dummy masks mask_a = np.zeros((4, 4, 1), dtype=np.bool) mask_a[2:4, 2:4] = 1 mask_a_img = Nifti1Image(mask_a.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ mask_b = np.zeros((4, 4, 1), dtype=np.bool) mask_b[1:3, 1:3] = 1 mask_b_img = Nifti1Image(mask_b.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ mask_c = np.zeros((4, 4, 1), dtype=np.bool) mask_c[:, 2] = 1 mask_c[0, 0] = 1 mask_c_img = Nifti1Image(mask_c.astype(int), np.eye(4)) # +---+---+---+---+ # | X | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ mask_ab = np.zeros((4, 4, 1), dtype=np.bool) mask_ab[2, 2] = 1 mask_ab_ = intersect_masks([mask_a_img, mask_b_img], threshold=1.) assert_array_equal(mask_ab, mask_ab_.get_data()) # Test intersect mask images with '>f8'. This function uses # largest_connected_component to check if intersect_masks passes with # connected=True (which is by default) mask_a_img_change_dtype = Nifti1Image(mask_a_img.get_data().astype('>f8'), affine=mask_a_img.get_affine()) mask_b_img_change_dtype = Nifti1Image(mask_b_img.get_data().astype('>f8'), affine=mask_b_img.get_affine()) mask_ab_change_type = intersect_masks([mask_a_img_change_dtype, mask_b_img_change_dtype], threshold=1.) assert_array_equal(mask_ab, mask_ab_change_type.get_data()) mask_abc = mask_a + mask_b + mask_c mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=0., connected=False) assert_array_equal(mask_abc, mask_abc_.get_data()) mask_abc[0, 0] = 0 mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=0.) assert_array_equal(mask_abc, mask_abc_.get_data()) mask_abc = mask_ab mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=1.) assert_array_equal(mask_abc, mask_abc_.get_data()) mask_abc[1, 2] = 1 mask_abc[3, 2] = 1 mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img]) assert_array_equal(mask_abc, mask_abc_.get_data())
def prepare_inputs(self, num_std_dev=1.5): """Helper function to creating temporary nii's and prepare inputs from time-series extraction""" import os.path as op import nibabel as nib from nilearn.image import math_img, index_img, resample_to_img from nilearn.masking import intersect_masks if not op.isfile(self.func_file): raise FileNotFoundError( "\nFunctional data input not found! Check that the" " file(s) specified with the -i " "flag exist(s)") if self.conf: if not op.isfile(self.conf): raise FileNotFoundError( "\nConfound regressor file not found! Check " "that the file(s) specified with the -conf flag " "exist(s)") self._func_img = nib.load(self.func_file) self._func_img.set_data_dtype(np.float32) func_vol_img = index_img(self._func_img, 1) func_vol_img.set_data_dtype(np.uint16) func_data = np.asarray(func_vol_img.dataobj, dtype=np.float32) func_int_thr = np.round( np.mean(func_data[func_data > 0]) - np.std(func_data[func_data > 0]) * num_std_dev, 3, ) hdr = self._func_img.header self._net_parcels_map_nifti = nib.load(self.net_parcels_nii_path, mmap=True) self._net_parcels_map_nifti.set_data_dtype(np.int16) if self.hpass: if len(hdr.get_zooms()) == 4: self._t_r = float(hdr.get_zooms()[-1]) else: self._t_r = None else: self._t_r = None if self.hpass is not None: if float(self.hpass) > 0: self.hpass = float(self.hpass) self._detrending = False else: self.hpass = None self._detrending = True else: self.hpass = None self._detrending = True if self.mask is not None: # Ensure mask is binary and contains only voxels that also # overlap with the parcellation and first functional volume self._mask_img = intersect_masks( [ math_img(f"img > {func_int_thr}", img=func_vol_img), math_img("img > 0.0001", img=resample_to_img(nib.load(self.mask), func_vol_img)) ], threshold=1, connected=False, ) self._mask_img.set_data_dtype(np.uint16) else: print("Warning: Proceeding to extract time-series without a " "brain mask...") self._mask_img = None if self.smooth: if float(self.smooth) > 0: print(f"Smoothing FWHM: {self.smooth} mm\n") if self.hpass: print(f"Applying high-pass filter: {self.hpass} Hz\n") return
heschl_mask = "/data2/azubaidi/ForrestGumpHearingLoss/BIDS_ForrGump/" \ + "derivatives/fmriprep/ROIs/HeschisGyrus/mni_Heschl_ROI.nii.gz" base_path = '/data2/azubaidi/ForrestGumpHearingLoss/BIDS_ForrGump/derivatives/encoding_results/temporal_lobe_mask' \ '/lagging0to-15.3_permutation_train_only/sub-10/acq-N4/' scores_path = base_path + 'sub-10_task-aomovie_acq-N4_desc-scores.nii.gz' pval_path = base_path + 'sub-10_task-aomovie_acq-N4_desc-permutationpval.pkl' masks = base_path + 'sub-10_task-aomovie_acq-N4_desc-masks.pkl' perm_all_path = base_path + 'sub-10_task-aomovie_acq-N4_desc-permutations.pkl' mask = joblib.load(masks)[0] roi_mask = resample_img(heschl_mask, mask._affine, mask.shape, interpolation='nearest') roi_mask = intersect_masks([mask, roi_mask]) mean_scores = mean_img(scores_path) perm_all = joblib.load(perm_all_path) pval = joblib.load(pval_path) pval = unmask(pval, mask) pval = apply_mask(pval, roi_mask) n_permutations = perm_all.shape[1] thresh = 1.0 / n_permutations pval_mask = pval > thresh pval[pval_mask] = 0 pvals = unmask(pval, roi_mask) selected_r_scores = apply_mask(mean_scores, roi_mask) selected_r_scores[pval_mask] = 0 selected_r_scores = unmask(selected_r_scores, roi_mask) display = plotting.plot_glass_brain(pvals,
def preprocess_funcs(ddict, cfg, logger): """ Preprocesses a set of functional files (either volumetric nifti or surface gifti); masking, high-pass filter (DCT) and normalization only. """ if 'fs' not in cfg['space']: # no need for mask in surface files if ddict['gm_prob'] is None: # use functional brain masks logger.info("Creating mask by intersection of fMRI masks") fmasks = [ f.replace('desc-preproc_bold', 'desc-brain_mask') for f in ddict['funcs'] ] mask = masking.intersect_masks(fmasks, threshold=0.8) else: # Using provided masks logger.info("Creating mask using GM probability map") # Downsample (necessary by default) gm_prob = image.resample_to_img(ddict['gm_prob'], ddict['funcs'][0]) gm_prob_data = gm_prob.get_fdata() # Threshold gm_prob_data = (gm_prob_data >= cfg['gm_thresh']).astype(int) mask = nib.Nifti1Image(gm_prob_data, affine=gm_prob.affine) else: # If fsaverage{5,6} space, don't use any mask mask = None ddict['mask'] = mask logger.info("Starting preprocessing of functional data ... ") out = Parallel(n_jobs=cfg['n_cpus'])( delayed(_run_func_parallel)(ddict, cfg, run, func, logger) for run, func in enumerate( tqdm_ctm(ddict['funcs'], tdesc('Preprocessing funcs:')))) # Concatenate data in time dimension data = np.vstack([d[0] for d in out]) run_idx = np.concatenate([r[1] for r in out]).astype(int) # Save functional data, ALWAYS as npy file (saves time/disk space) save_data(data, cfg, ddict, par_dir='preproc', run=None, desc='preproc', dtype='bold') # Save run_idx out_dir = op.join(cfg['save_dir'], 'preproc') np.save(op.join(out_dir, f"task-{cfg['c_task']}_run_idx.npy"), run_idx) # Extract TRs ddict['trs'] = [o[2] for o in out] logger.info(f"Found the following TRs across runs: {ddict['trs']}") # Save mask save_data(ddict['mask'], cfg, ddict, par_dir='preproc', run=None, desc='preproc', dtype='mask', nii=True) # Store in data-dictionary (ddict) ddict['preproc_func'] = data ddict['run_idx'] = run_idx return ddict
# Create a precise brain mask, by combining RATS and SPM sammba_brain_mask_file = os.path.join( sammba_dir, 'anat_n0_unifized_brain_mask.nii.gz') spm_tissues_files = [ os.path.join(spm_dir, 'c{0}anat_n0_clear_hd.nii'.format(n)) # Try after N3 for n in range(1, 4) ] rough_mask_img = image.math_img('np.max(imgs, axis=-1) > .01', imgs=spm_tissues_files) spm_labels_img = image.math_img('img * (np.argmax(imgs, axis=-1) + 1)', img=rough_mask_img, imgs=spm_tissues_files) spm_gm_wm_img = image.math_img('np.logical_or(img==1, img==2)', img=spm_labels_img) brain_mask_img = masking.intersect_masks( [sammba_brain_mask_file, spm_gm_wm_img], threshold=0) brain_mask_file = os.path.join(sammba_dir, 'anat_n0_precise_brain_mask.nii.gz') brain_contour_file = compute_mask_contour(brain_mask_file) check_niimg(brain_contour_file).to_filename( os.path.join(spm_dir, 'anat_n0_precise_brain_mask_contour.nii')) nwarp_apply = afni.NwarpApply().run transforms = [ os.path.join(sammba_dir, 'anat_n0_unifized_affine_general_warped_WARP.nii.gz'), os.path.join(sammba_dir, 'anat_n0_unifized_masked_aff.aff12.1D') ] warp = "'" + ' '.join(transforms) + "'" sammba_registered_contour_file = fname_presuffix(brain_contour_file, suffix='_warped',
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, 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. """ 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: uatlas_res_template = resample_to_img(nib.load(uatlas_parcels), template_img, interpolation="nearest") else: uatlas_res_template = resample_to_img(nib.load(uatlas), template_img, interpolation="nearest") uatlas_res_template_data = np.asarray(uatlas_res_template.dataobj) uatlas_res_template_data[ uatlas_res_template_data != uatlas_res_template_data.astype(int)] = 0 uatlas_res_template = nib.Nifti1Image( uatlas_res_template_data.astype("int32"), 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, ) # Apply linear transformation from template to dwi space regutils.align( aligned_atlas_skull, ap_path, init=t1w2dwi_bbr_xfm, out=dwi_aligned_atlas, dof=6, searchrad=True, interp="nearestneighbour", cost="mutualinfo", ) except BaseException: print( "Warning: Atlas is not in correct dimensions, or input is low quality,\nusing linear template " "registration.") regutils.align( aligned_atlas_t1mni, t1w_brain, init=mni2t1_xfm, out=aligned_atlas_skull, dof=6, searchrad=True, interp="nearestneighbour", cost="mutualinfo", ) regutils.align( aligned_atlas_skull, ap_path, init=t1w2dwi_bbr_xfm, out=dwi_aligned_atlas, dof=6, searchrad=True, interp="nearestneighbour", cost="mutualinfo", ) else: regutils.align( aligned_atlas_t1mni, t1w_brain, init=mni2t1_xfm, out=aligned_atlas_skull, dof=6, searchrad=True, interp="nearestneighbour", cost="mutualinfo", ) regutils.align( aligned_atlas_skull, ap_path, init=t1w2dwi_xfm, out=dwi_aligned_atlas, dof=6, searchrad=True, interp="nearestneighbour", cost="mutualinfo", ) 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) uatlas_res_template_data = np.asarray(atlas_img.dataobj) uatlas_res_template_data[ uatlas_res_template_data != uatlas_res_template_data.astype(int)] = 0 atlas_img_corr = nib.Nifti1Image( uatlas_res_template_data.astype("uint32"), affine=atlas_img.affine, header=atlas_img.header, ) 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) os.system( f"fslmaths {dwi_aligned_atlas} -mas {B0_mask} {dwi_aligned_atlas} " f"2>/dev/null") os.system(f"fslmaths {dwi_aligned_atlas_wmgm_int} -mas {B0_mask} " f"{dwi_aligned_atlas_wmgm_int} 2>/dev/null") 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...") atlas_img.uncache() atlas_img_corr.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 test_intersect_masks(): """ Test the intersect_masks function """ # Create dummy masks mask_a = np.zeros((4, 4, 1), dtype=np.bool) mask_a[2:4, 2:4] = 1 mask_a_img = Nifti1Image(mask_a.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ # | | | X | X | # +---+---+---+---+ mask_b = np.zeros((4, 4, 1), dtype=np.bool) mask_b[1:3, 1:3] = 1 mask_b_img = Nifti1Image(mask_b.astype(int), np.eye(4)) # +---+---+---+---+ # | | | | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | X | X | | # +---+---+---+---+ # | | | | | # +---+---+---+---+ mask_c = np.zeros((4, 4, 1), dtype=np.bool) mask_c[:, 2] = 1 mask_c[0, 0] = 1 mask_c_img = Nifti1Image(mask_c.astype(int), np.eye(4)) # +---+---+---+---+ # | X | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ # | | | X | | # +---+---+---+---+ mask_ab = np.zeros((4, 4, 1), dtype=np.bool) mask_ab[2, 2] = 1 mask_ab_ = intersect_masks([mask_a_img, mask_b_img], threshold=1.) assert_array_equal(mask_ab, get_data(mask_ab_)) # Test intersect mask images with '>f8'. This function uses # largest_connected_component to check if intersect_masks passes with # connected=True (which is by default) mask_a_img_change_dtype = Nifti1Image(get_data(mask_a_img).astype('>f8'), affine=mask_a_img.affine) mask_b_img_change_dtype = Nifti1Image(get_data(mask_b_img).astype('>f8'), affine=mask_b_img.affine) mask_ab_change_type = intersect_masks( [mask_a_img_change_dtype, mask_b_img_change_dtype], threshold=1.) assert_array_equal(mask_ab, get_data(mask_ab_change_type)) mask_abc = mask_a + mask_b + mask_c mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=0., connected=False) assert_array_equal(mask_abc, get_data(mask_abc_)) mask_abc[0, 0] = 0 mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=0.) assert_array_equal(mask_abc, get_data(mask_abc_)) mask_abc = mask_ab mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img], threshold=1.) assert_array_equal(mask_abc, get_data(mask_abc_)) mask_abc[1, 2] = 1 mask_abc[3, 2] = 1 mask_abc_ = intersect_masks([mask_a_img, mask_b_img, mask_c_img]) assert_array_equal(mask_abc, get_data(mask_abc_))
subjects = Parallel( n_jobs=n_jobs, verbose=100)(delayed( run_suject_level1_glm)( subject_data, **kwargs) for subject_data in subjects) else: subjects = [run_suject_level1_glm(subject_data, **kwargs) for subject_data in subjects] subjects = [subject for subject in subjects if subject] # level 2 stats_start_time = pretty_time() mask_images = [subject_data.mask for subject_data in subjects] group_mask = nibabel.Nifti1Image( intersect_masks(mask_images).astype(np.int8), nibabel.load(mask_images[0]).get_affine()) nibabel.save(group_mask, os.path.join( task_output_dir, "mask.nii.gz")) print "... done.\r\n" print "Group GLM" contrasts = subjects[0].contrasts subjects_effects_maps = [subject_data.effects_maps for subject_data in subjects] group_one_sample_t_test( mask_images, subjects_effects_maps, contrasts, task_output_dir,
def create_spherical_roi_volumes(node_size, coords, template_mask): """ Create volume ROI mask of spheres from a given set of coordinates and radius. Parameters ---------- node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's for tracking. coords : list List of (x, y, z) tuples in mm-space corresponding to a coordinate atlas used or which represent the center-of-mass of each parcellation node. template_mask : str Path to binarized version of standard (MNI)-space template Nifti1Image file. Returns ------- parcel_list : list List of 3D boolean numpy arrays or binarized Nifti1Images corresponding to ROI masks. par_max : int The maximum label intensity in the parcellation image. node_size : int Spherical centroid node size in the case that coordinate-based centroids are used as ROI's for tracking. parc : bool Indicates whether to use the raw parcels as ROI nodes instead of coordinates at their center-of-mass. """ from pynets.core.nodemaker import get_sphere, mmToVox from nilearn.masking import intersect_masks mask_img = nib.load(template_mask) mask_aff = mask_img.affine mask_shape = mask_img.shape mask_img.uncache() print(f"Creating spherical ROI atlas with radius: {node_size}") coords_vox = [] for i in coords: coords_vox.append(mmToVox(mask_aff, i)) coords_vox = list(set(list(tuple(x) for x in coords_vox))) x_vox = np.diagonal(mask_aff[:3, 0:3])[0] y_vox = np.diagonal(mask_aff[:3, 0:3])[1] z_vox = np.diagonal(mask_aff[:3, 0:3])[2] parcel_list_all = [] i = 0 for coord in coords_vox: sphere_vol = np.zeros(mask_shape, dtype=bool) sphere_vol[tuple( get_sphere(coord, node_size, (np.abs(x_vox), y_vox, z_vox), mask_shape).T)] = i * 1 parcel_list_all.append( nib.Nifti1Image(sphere_vol.astype('bool').astype('uint16'), affine=mask_aff)) i += 1 # remove the intersection parcel_intersect = np.invert( np.asarray(intersect_masks(parcel_list_all, threshold=1).dataobj).astype('bool')) parcel_list = [] for mask in parcel_list_all: non_ovlp = np.asarray(mask.dataobj) * parcel_intersect parcel_list.append( nib.Nifti1Image(non_ovlp.astype('uint16'), affine=mask_aff)) par_max = len(coords) if par_max > 0: parc = True else: raise ValueError('Number of nodes is zero.') return parcel_list, par_max, node_size, parc
def prep_tissues(t1_mask, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi, tiss_class, B0_mask, cmc_step_size=0.2): """ Estimate a tissue classifier for tractography. Parameters ---------- t1_mask : Nifti1Image T1w mask img. gm_in_dwi : Nifti1Image Grey-matter tissue segmentation Nifti1Image. vent_csf_in_dwi : Nifti1Image Ventricular CSF tissue segmentation Nifti1Image. wm_in_dwi : Nifti1Image White-matter tissue segmentation Nifti1Image. tiss_class : str Tissue classification method. cmc_step_size : float Step size from CMC tissue classification method. Returns ------- tiss_classifier : obj Tissue classifier object. References ---------- .. [1] Zhang, Y., Brady, M. and Smith, S. Segmentation of Brain MR Images Through a Hidden Markov Random Field Model and the Expectation-Maximization Algorithm IEEE Transactions on Medical Imaging, 20(1): 45-56, 2001 .. [2] Avants, B. B., Tustison, N. J., Wu, J., Cook, P. A. and Gee, J. C. An open source multivariate framework for n-tissue segmentation with evaluation on public data. Neuroinformatics, 9(4): 381-400, 2011. """ import gc from dipy.tracking.stopping_criterion import ( ActStoppingCriterion, CmcStoppingCriterion, BinaryStoppingCriterion, ) from nilearn.masking import intersect_masks from nilearn.image import math_img # Load B0 mask B0_mask_img = math_img("img > 0.01", img=B0_mask) # Load t1 mask mask_img = math_img("img > 0.01", img=t1_mask) # Load tissue maps and prepare tissue classifier wm_mask_img = math_img("img > 0.01", img=wm_in_dwi) gm_mask_img = math_img("img > 0.01", img=gm_in_dwi) vent_csf_in_dwi_img = math_img("img > 0.01", img=vent_csf_in_dwi) gm_data = np.asarray(gm_mask_img.dataobj, dtype=np.float32) wm_data = np.asarray(wm_mask_img.dataobj, dtype=np.float32) vent_csf_in_dwi_data = np.asarray(vent_csf_in_dwi_img.dataobj, dtype=np.float32) if tiss_class == "act": background = np.ones(mask_img.shape) background[(gm_data + wm_data + vent_csf_in_dwi_data) > 0] = 0 gm_data[background > 0] = 1 tiss_classifier = ActStoppingCriterion(gm_data, vent_csf_in_dwi_data) del background elif tiss_class == "wm": tiss_classifier = BinaryStoppingCriterion( np.asarray( intersect_masks( [ mask_img, wm_mask_img, B0_mask_img, nib.Nifti1Image(np.invert( vent_csf_in_dwi_data.astype('bool')).astype('int'), affine=mask_img.affine) ], threshold=1, connected=False, ).dataobj)) elif tiss_class == "cmc": tiss_classifier = CmcStoppingCriterion.from_pve( wm_data, gm_data, vent_csf_in_dwi_data, step_size=cmc_step_size, average_voxel_size=np.average(mask_img.header["pixdim"][1:4]), ) elif tiss_class == "wb": tiss_classifier = BinaryStoppingCriterion( np.asarray( intersect_masks( [ mask_img, B0_mask_img, nib.Nifti1Image(np.invert( vent_csf_in_dwi_data.astype('bool')).astype('int'), affine=mask_img.affine), ], threshold=1, connected=False, ).dataobj)) else: raise ValueError("Tissue classifier cannot be none.") B0_mask_img.uncache() mask_img.uncache() wm_mask_img.uncache() gm_mask_img.uncache() del gm_data, wm_data, vent_csf_in_dwi_data gc.collect() return tiss_classifier
def group_one_sample_t_test(masks, effects_maps, contrasts, output_dir, start_time=base_reporter.pretty_time(), **kwargs): """ Runs a one-sample t-test procedure for group analysis. Here, we are for each experimental condition, only interested refuting the null hypothesis H0: "The average effect accross the subjects is zero!" Parameters ---------- masks: list of strings or nibabel image objects subject masks, one per subject effects_maps: list of dicts of lists effects maps from subject-level GLM; each entry is a dictionary; each entry (indexed by condition id) of this dictionary is the filename (or correspinding nibabel image object) for the effects maps for that condition (aka contrast),for that subject contrasts: dictionary of array_likes contrasts vectors, indexed by condition id kwargs: dict_like kwargs for plot_stats_map API """ # make output directory if not os.path.exists(output_dir): os.makedirs(output_dir) assert len(masks) == len(effects_maps), (len(masks), len(effects_maps)) # compute group mask group_mask = intersect_masks(masks) # construct design matrix (only one covariate, namely the "mean effect") design_matrix = np.ones( len(effects_maps))[:, np.newaxis] # only the intercept group_level_z_maps = {} group_level_t_maps = {} for contrast_id in contrasts: print("\tcontrast id: %s" % contrast_id) # effects maps will be the input to the second level GLM first_level_image = nibabel.concat_images( [x[contrast_id] for x in effects_maps]) # fit 2nd level GLM for given contrast group_model = FirstLevelGLM(first_level_image, design_matrix, group_mask) group_model.fit(do_scaling=False, model='ols') # specify and estimate the contrast contrast_val = np.array(([[1.]])) # the only possible contrast ! z_map, t_map = group_model.contrast(contrast_val, con_id='one_sample %s' % contrast_id, output_z=True, output_stat=True) # save map for map_type, map_img in zip(["z", "t"], [z_map, t_map]): map_dir = os.path.join(output_dir, '%s_maps' % map_type) if not os.path.exists(map_dir): os.makedirs(map_dir) map_path = os.path.join(map_dir, 'group_level_%s.nii.gz' % (contrast_id)) print("\t\tWriting %s ..." % map_path) nibabel.save(map_img, map_path) if map_type == "z": group_level_z_maps[contrast_id] = map_path elif map_type == "t": group_level_z_maps[contrast_id] = map_path # do stats report stats_report_filename = os.path.join(output_dir, "report_stats.html") generate_subject_stats_report(stats_report_filename, contrasts, group_level_z_maps, group_mask, start_time=start_time, **kwargs) print("\r\nStatistic report written to %s\r\n" % stats_report_filename) return group_level_z_maps
def track_ensemble(target_samples, atlas_data_wm_gm_int, labels_im_file, recon_path, sphere, traversal, curv_thr_list, step_list, track_type, maxcrossing, roi_neighborhood_tol, min_length, waymask, B0_mask, t1w2dwi, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi, tiss_class, BACKEND='threading'): """ Perform native-space ensemble tractography, restricted to a vector of ROI masks. Parameters ---------- target_samples : int Total number of streamline samples specified to generate streams. atlas_data_wm_gm_int : str File path to Nifti1Image in T1w-warped native diffusion space, restricted to wm-gm interface. parcels : list List of 3D boolean numpy arrays of atlas parcellation ROI masks from a Nifti1Image in T1w-warped native diffusion space. recon_path : str File path to diffusion reconstruction model. tiss_classifier : str Tissue classification method. sphere : obj DiPy object for modeling diffusion directions on a sphere. traversal : str The statistical approach to tracking. Options are: det (deterministic), closest (clos), and prob (probabilistic). curv_thr_list : list List of integer curvature thresholds used to perform ensemble tracking. step_list : list List of float step-sizes used to perform ensemble tracking. track_type : str Tracking algorithm used (e.g. 'local' or 'particle'). maxcrossing : int Maximum number if diffusion directions that can be assumed per voxel while tracking. roi_neighborhood_tol : float Distance (in the units of the streamlines, usually mm). If any coordinate in the streamline is within this distance from the center of any voxel in the ROI, the filtering criterion is set to True for this streamline, otherwise False. Defaults to the distance between the center of each voxel and the corner of the voxel. min_length : int Minimum fiber length threshold in mm. waymask_data : ndarray Tractography constraint mask array in native diffusion space. B0_mask_data : ndarray B0 brain mask data. n_seeds_per_iter : int Number of seeds from which to initiate tracking for each unique ensemble combination. By default this is set to 250. max_length : int Maximum number of steps to restrict tracking. particle_count pft_back_tracking_dist : float Distance in mm to back track before starting the particle filtering tractography. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 2 mm. pft_front_tracking_dist : float Distance in mm to run the particle filtering tractography after the the back track distance. The total particle filtering tractography distance is equal to back_tracking_dist + front_tracking_dist. By default this is set to 1 mm. particle_count : int Number of particles to use in the particle filter. min_separation_angle : float The minimum angle between directions [0, 90]. Returns ------- streamlines : ArraySequence DiPy list/array-like object of streamline points from tractography. References ---------- .. [1] Takemura, H., Caiafa, C. F., Wandell, B. A., & Pestilli, F. (2016). Ensemble Tractography. PLoS Computational Biology. https://doi.org/10.1371/journal.pcbi.1004692 """ import os import gc import time import warnings import time import tempfile from joblib import Parallel, delayed, Memory import itertools import pickle5 as pickle from pynets.dmri.track import run_tracking from colorama import Fore, Style from pynets.dmri.utils import generate_sl from nibabel.streamlines.array_sequence import concatenate, ArraySequence from pynets.core.utils import save_3d_to_4d from nilearn.masking import intersect_masks from nilearn.image import math_img from pynets.core.utils import load_runconfig from dipy.tracking import utils warnings.filterwarnings("ignore") pickle.HIGHEST_PROTOCOL = 5 joblib_dir = tempfile.mkdtemp() os.makedirs(joblib_dir, exist_ok=True) hardcoded_params = load_runconfig() nthreads = hardcoded_params["omp_threads"][0] os.environ['MKL_NUM_THREADS'] = str(nthreads) os.environ['OPENBLAS_NUM_THREADS'] = str(nthreads) n_seeds_per_iter = \ hardcoded_params['tracking']["n_seeds_per_iter"][0] max_length = \ hardcoded_params['tracking']["max_length"][0] pft_back_tracking_dist = \ hardcoded_params['tracking']["pft_back_tracking_dist"][0] pft_front_tracking_dist = \ hardcoded_params['tracking']["pft_front_tracking_dist"][0] particle_count = \ hardcoded_params['tracking']["particle_count"][0] min_separation_angle = \ hardcoded_params['tracking']["min_separation_angle"][0] min_streams = \ hardcoded_params['tracking']["min_streams"][0] seeding_mask_thr = hardcoded_params['tracking']["seeding_mask_thr"][0] timeout = hardcoded_params['tracking']["track_timeout"][0] all_combs = list(itertools.product(step_list, curv_thr_list)) # Construct seeding mask seeding_mask = f"{os.path.dirname(labels_im_file)}/seeding_mask.nii.gz" if waymask is not None and os.path.isfile(waymask): waymask_img = math_img(f"img > {seeding_mask_thr}", img=nib.load(waymask)) waymask_img.to_filename(waymask) atlas_data_wm_gm_int_img = intersect_masks( [ waymask_img, math_img("img > 0.001", img=nib.load(atlas_data_wm_gm_int)), math_img("img > 0.001", img=nib.load(labels_im_file)) ], threshold=1, connected=False, ) nib.save(atlas_data_wm_gm_int_img, seeding_mask) else: atlas_data_wm_gm_int_img = intersect_masks( [ math_img("img > 0.001", img=nib.load(atlas_data_wm_gm_int)), math_img("img > 0.001", img=nib.load(labels_im_file)) ], threshold=1, connected=False, ) nib.save(atlas_data_wm_gm_int_img, seeding_mask) tissues4d = save_3d_to_4d([ B0_mask, labels_im_file, seeding_mask, t1w2dwi, gm_in_dwi, vent_csf_in_dwi, wm_in_dwi ]) # Commence Ensemble Tractography start = time.time() stream_counter = 0 all_streams = [] ix = 0 memory = Memory(location=joblib_dir, mmap_mode='r+', verbose=0) os.chdir(f"{memory.location}/joblib") @memory.cache def load_recon_data(recon_path): import h5py with h5py.File(recon_path, 'r') as hf: recon_data = hf['reconstruction'][:].astype('float32') hf.close() return recon_data recon_shelved = load_recon_data.call_and_shelve(recon_path) @memory.cache def load_tissue_data(tissues4d): return nib.load(tissues4d) tissue_shelved = load_tissue_data.call_and_shelve(tissues4d) try: while float(stream_counter) < float(target_samples) and \ float(ix) < 0.50*float(len(all_combs)): with Parallel(n_jobs=nthreads, backend=BACKEND, mmap_mode='r+', verbose=0) as parallel: out_streams = parallel( delayed(run_tracking) (i, recon_shelved, n_seeds_per_iter, traversal, maxcrossing, max_length, pft_back_tracking_dist, pft_front_tracking_dist, particle_count, roi_neighborhood_tol, min_length, track_type, min_separation_angle, sphere, tiss_class, tissue_shelved) for i in all_combs) out_streams = list(filter(None, out_streams)) if len(out_streams) > 1: out_streams = concatenate(out_streams, axis=0) else: continue if waymask is not None and os.path.isfile(waymask): try: out_streams = out_streams[utils.near_roi( out_streams, np.eye(4), np.asarray( nib.load(waymask).dataobj).astype("bool"), tol=int(round(roi_neighborhood_tol * 0.50, 1)), mode="all")] except BaseException: print(f"\n{Fore.RED}No streamlines generated in " f"waymask vacinity\n") print(Style.RESET_ALL) return None if len(out_streams) < min_streams: ix += 1 print(f"\n{Fore.YELLOW}Fewer than {min_streams} " f"streamlines tracked " f"on last iteration...\n") print(Style.RESET_ALL) if ix > 5: print(f"\n{Fore.RED}No streamlines generated\n") print(Style.RESET_ALL) return None continue else: ix -= 1 stream_counter += len(out_streams) all_streams.extend([generate_sl(i) for i in out_streams]) del out_streams print("%s%s%s%s" % ( "\nCumulative Streamline Count: ", Fore.CYAN, stream_counter, "\n", )) gc.collect() print(Style.RESET_ALL) if time.time() - start > timeout: print(f"\n{Fore.RED}Warning: Tractography timed " f"out: {time.time() - start}") print(Style.RESET_ALL) memory.clear(warn=False) return None except RuntimeError as e: print(f"\n{Fore.RED}Error: Tracking failed due to:\n{e}\n") print(Style.RESET_ALL) memory.clear(warn=False) return None print("Tracking Complete: ", str(time.time() - start)) memory.clear(warn=False) del parallel, all_combs gc.collect() if stream_counter != 0: print('Generating final ...') return ArraySequence([ArraySequence(i) for i in all_streams]) else: print(f"\n{Fore.RED}No streamlines generated!") print(Style.RESET_ALL) return None
def atlas2t1w2dwi_align( uatlas, uatlas_parcels, atlas, t1w_brain, t1w_brain_mask, mni2t1w_warp, t1_aligned_mni, ap_path, 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 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_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.") regutils.applyxfm(t1w_brain, aligned_atlas_t1mni, mni2t1_xfm, aligned_atlas_skull, interp="nearestneighbour") time.sleep(0.5) 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) else: regutils.applyxfm(t1w_brain, aligned_atlas_t1mni, mni2t1_xfm, aligned_atlas_skull, interp="nearestneighbour") time.sleep(0.5) 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_skull
def create_clean_mask(self, num_std_dev=1.5): """ Create a subject-refined version of the clustering mask. """ import os from pynets.core import utils from nilearn.masking import intersect_masks from nilearn.image import index_img, math_img, resample_img mask_name = os.path.basename(self.clust_mask).split(".nii")[0] self.atlas = f"{mask_name}{'_'}{self.clust_type}{'_k'}{str(self.k)}" print(f"\nCreating atlas using {self.clust_type} at cluster level" f" {str(self.k)} for {str(self.atlas)}...\n") self._dir_path = utils.do_dir_path(self.atlas, self.outdir) self.parcellation = f"{self._dir_path}/{mask_name}_" \ f"clust-{self.clust_type}" \ f"_k{str(self.k)}.nii.gz" # Load clustering mask self._func_img.set_data_dtype(np.float32) func_vol_img = index_img(self._func_img, 1) func_vol_img.set_data_dtype(np.uint16) clust_mask_res_img = resample_img( nib.load(self.clust_mask), target_affine=func_vol_img.affine, target_shape=func_vol_img.shape, interpolation="nearest", ) clust_mask_res_img.set_data_dtype(np.uint16) func_data = np.asarray(func_vol_img.dataobj, dtype=np.float32) func_int_thr = np.round( np.mean(func_data[func_data > 0]) - np.std(func_data[func_data > 0]) * num_std_dev, 3, ) if self.mask is not None: self._mask_img = nib.load(self.mask) self._mask_img.set_data_dtype(np.uint16) mask_res_img = resample_img( self._mask_img, target_affine=func_vol_img.affine, target_shape=func_vol_img.shape, interpolation="nearest", ) mask_res_img.set_data_dtype(np.uint16) self._clust_mask_corr_img = intersect_masks( [ math_img(f"img > {func_int_thr}", img=func_vol_img), math_img("img > 0.01", img=clust_mask_res_img), math_img("img > 0.01", img=mask_res_img), ], threshold=1, connected=False, ) self._clust_mask_corr_img.set_data_dtype(np.uint16) self._mask_img.uncache() mask_res_img.uncache() else: self._clust_mask_corr_img = intersect_masks( [ math_img("img > " + str(func_int_thr), img=func_vol_img), math_img("img > 0.01", img=clust_mask_res_img), ], threshold=1, connected=False, ) self._clust_mask_corr_img.set_data_dtype(np.uint16) nib.save(self._clust_mask_corr_img, f"{self._dir_path}{'/'}{mask_name}{'.nii.gz'}") del func_data func_vol_img.uncache() clust_mask_res_img.uncache() return self.atlas
def average_brain_mask(derivatives=DERIVATIVES): """Compute an average brain masks across all the brain masks available""" from nilearn.masking import intersect_masks masks = glob.glob(os.path.join(derivatives, 'sub-*/ses-00/mask.nii.gz')) return (intersect_masks(masks, .25))
if n_jobs > 1: subjects = Parallel(n_jobs=n_jobs, verbose=100)( delayed(run_suject_level1_glm)(subject_data, **kwargs) for subject_data in subjects) else: subjects = [ run_suject_level1_glm(subject_data, **kwargs) for subject_data in subjects ] subjects = [subject for subject in subjects if subject] # level 2 stats_start_time = pretty_time() mask_images = [subject_data.mask for subject_data in subjects] group_mask = nibabel.Nifti1Image( intersect_masks(mask_images).astype(np.int8), nibabel.load(mask_images[0]).get_affine()) nibabel.save(group_mask, os.path.join(task_output_dir, "mask.nii.gz")) print "... done.\r\n" print "Group GLM" contrasts = subjects[0].contrasts subjects_effects_maps = [ subject_data.effects_maps for subject_data in subjects ] group_one_sample_t_test( mask_images, subjects_effects_maps, contrasts, task_output_dir,
test_set = ['left button press (auditory cue)'] ref = [contrast for contrast in contrasts if contrast not in test_set] n_ref = len(ref) nifti_masker = NiftiMasker('mask_GM_forFunc.nii') affine = load(nifti_masker.mask).get_affine() # fetch the data ref_imgs = datasets.fetch_localizer_contrasts(ref).cmaps n_subjects = len(ref_imgs) / n_ref # Create a population mask one_contrast = [img for img in ref_imgs if 'horizontal' in img] mask_ = compute_multi_background_mask(one_contrast) mask_image = intersect_masks(['mask_GM_forFunc.nii', mask_]) mask = mask_image.get_data() n_voxels = mask.sum() save(mask_image, '/tmp/mask.nii') nifti_masker = NiftiMasker(mask_image) # write directory write_dir = op.join(getcwd(), 'results') if not op.exists(write_dir): mkdir(write_dir) ############################################################################### # Global parameters n_clusters = 5000