def gen_mask(t1w_head, t1w_brain, mask): import os.path as op 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(dtype=np.float32) try: t1w_brain_mask = deep_skull_strip(t1w_data, t1w_brain_mask, img) except RuntimeError as e: print(e, 'Deepbrain extraction failed...') del t1w_data # Threshold T1w brain to binary in anat space math_img("img > 0.0001", img=nib.load(t1w_brain_mask)).to_filename(t1w_brain_mask) t1w_brain = apply_mask_to_image(t1w_head, t1w_brain_mask, t1w_brain) assert op.isfile(t1w_brain) assert op.isfile(t1w_brain_mask) return t1w_brain, t1w_brain_mask
def get_brain_regions_cruise(cortex_l, cortex_r, type): from nilearn import image import os from nipype.utils.filemanip import split_filename from scipy import ndimage _, fn_l, _ = split_filename(cortex_l) _, fn_r, _ = split_filename(cortex_l) cortex_l = image.load_img(cortex_l) cortex_r = image.load_img(cortex_r) new_fn = os.path.abspath('{}.nii.gz'.format(fn_l)).replace('left_', '') if type == 'wm': wm = image.math_img('(cortex_l == 2) + (cortex_r == 2)', cortex_l=cortex_l, cortex_r=cortex_r) wm = image.new_img_like(wm, ndimage.binary_erosion(wm.get_data())) wm.to_filename(new_fn) elif type == 'csf': csf = image.math_img('(cortex_l + cortex_r) == 0', cortex_l=cortex_l, cortex_r=cortex_r) csf = image.new_img_like(csf, ndimage.binary_erosion(csf.get_data())) csf.to_filename(new_fn) return new_fn
def make_submask(mask): from nilearn import image import numpy as np import os.path as op from nipype.utils.filemanip import split_filename _, fn, ext = split_filename(mask) im = image.load_img(mask) data = im.get_data() percentiles = np.percentile(data[data != 0], [33, 66]) mask1 = image.math_img('(im > 0) & (im < {})'.format(percentiles[0]), im=im) mask2 = image.math_img('(im > {}) & (im < {})'.format(*percentiles), im=im) mask3 = image.math_img('(im > {})'.format(percentiles[1]), im=im) fn1 = op.abspath('{}_maskA{}'.format(fn, ext)) fn2 = op.abspath('{}_maskB{}'.format(fn, ext)) fn3 = op.abspath('{}_maskC{}'.format(fn, ext)) mask1.to_filename(fn1) mask2.to_filename(fn2) mask3.to_filename(fn3) return fn3, fn2, fn1
def nistats_confound_glm(nifti_file, confounds_file, which_confounds): import pandas as pd import nibabel as nb import numpy as np from nistats.regression import OLSModel from scipy.stats import zscore from nilearn.image import math_img from nilearn.plotting import plot_stat_map import matplotlib.pyplot as plt infile = nb.load(nifti_file) mean_img = math_img('np.mean(infile, axis=-1)', infile=infile) in_data = infile.get_data().astype(np.float32) confounds_table = pd.read_table(confounds_file)[which_confounds] # we assume the confounds nor the nifti_file need temporal filtering cfz = confounds_table.apply(zscore) cfz['intercept'] = np.ones(infile.shape[-1]) om = OLSModel(np.array(cfz)) om_rr = om.fit(in_data.reshape((-1,infile.shape[-1])).T) resid_img = nb.Nifti1Image(om_rr.resid.T.reshape(infile.shape).astype(np.float32), affine=infile.affine, header=infile.header) cleaned_img = math_img('(resid_img + mean_img[...,np.newaxis]).astype(np.float32)', resid_img=resid_img, mean_img=mean_img) output_nifti = nifti_file.replace('.nii.gz', '_nuis.nii.gz') cleaned_img.to_filename(output_nifti) output_pdf = confounds_file.replace('.tsv', '_sd-diff.pdf') f = plt.figure(figsize=(24,6)) plot_stat_map(math_img('(infile.std(axis=-1)-cleaned_img.std(axis=-1))/infile.std(axis=-1)', infile=infile, cleaned_img=cleaned_img), bg_img=mean_img, figure=f, cut_coords=(0,0,0), threshold=0.125, vmax=1, cmap='viridis', output_file=output_pdf) return output_pdf, output_nifti
def test_anat_to_template(): anat_file = os.path.join(os.path.dirname(testing_data.__file__), 'anat.nii.gz') brain_mask_file = os.path.join(os.path.dirname(testing_data.__file__), 'mask.nii.gz') brain_file = os.path.join(tst.tmpdir, 'brain.nii.gz') math_img('img1 * img2', img1=anat_file, img2=brain_mask_file).to_filename(brain_file) # Check error is raised if wrong registration kind assert_raises_regex(ValueError, "Registration kind must be one of ", struct.anat_to_template, anat_file, brain_file, anat_file, brain_file, tst.tmpdir, registration_kind='rigidd') # test common space of one image is itself register_result = struct.anat_to_template(anat_file, brain_file, anat_file, brain_file, write_dir=tst.tmpdir, registration_kind='rigid', verbose=0) pretransform = np.loadtxt(register_result.pretransform) assert_array_almost_equal(pretransform, [1, 0, 0, 0, 0, 1, 0, 0, 0, 0, 1, 0], decimal=1) assert_true(os.path.isfile(register_result.registered)) assert_true(register_result.transform is None)
def gen_tissue(self): """ A function to segment and threshold tissue types from T1w. """ # Segment the t1w brain into probability maps maps = regutils.segment_t1w(self.t1w_brain, self.map_path) self.wm_mask = maps['wm_prob'] self.gm_mask = maps['gm_prob'] self.csf_mask = maps['csf_prob'] self.t1w_brain = regutils.check_orient_and_dims(self.t1w_brain, self.vox_size) self.wm_mask = regutils.check_orient_and_dims(self.wm_mask, self.vox_size) self.gm_mask = regutils.check_orient_and_dims(self.gm_mask, self.vox_size) self.csf_mask = regutils.check_orient_and_dims(self.csf_mask, self.vox_size) # Threshold WM to binary in dwi space t_img = load_img(self.wm_mask) mask = math_img('img > 0.2', img=t_img) mask.to_filename(self.wm_mask_thr) # Threshold T1w brain to binary in anat space t_img = load_img(self.t1w_brain) mask = math_img('img > 0.0', img=t_img) mask.to_filename(self.t1w_brain_mask) # Extract wm edge os.system("fslmaths {} -edge -bin -mas {} {}".format(self.wm_mask_thr, self.wm_mask_thr, self.wm_edge)) return
def createTFCEfMRIOverlayImages(folder,suffix,title='',vmax=8,display_mode='z',slices=range(-20,50,10),threshold=0.94999,plotToAxis=False,f=[],axes=[],colorbar=True,tight_layout=False,draw_cross=False,annotate=False): TFCEposImg,posImg,TFCEnegImg,negImg=getFileNamesfromFolder(folder,suffix) bg_img='./Templates/MNI152_.5mm_masked_edged.nii.gz' # threshold=0.949 pos=image.math_img("np.multiply(img1,img2)", img1=image.threshold_img(TFCEposImg,threshold=threshold),img2=posImg) neg=image.math_img("np.multiply(img1,img2)", img1=image.threshold_img(TFCEnegImg,threshold=threshold),img2=negImg) fw=image.math_img("img1-img2",img1=pos,img2=neg) if plotToAxis: display=plotting.plot_stat_map(fw,display_mode=display_mode,threshold=0, cut_coords=slices,vmax=vmax,colorbar=colorbar, bg_img=bg_img,black_bg=False,title=title,dim=0, figure=f,axes=axes,draw_cross=draw_cross, annotate=annotate) else: display=plotting.plot_stat_map(fw,display_mode=display_mode,threshold=0, cut_coords=slices,vmax=vmax,colorbar=colorbar,bg_img=bg_img, black_bg=False,title=title,dim=0,annotate=annotate) if tight_layout: display.tight_layout() return display
def cluster_binary_img(binary_img, mask_img, min_region_size='exhaustive'): # get voxel resolution in binary_img # NOTE: function currently assumes equal width in x,y,z direction voxel_sizes = binary_img.header.get_zooms() # if not specfied by user, cluster exhaustive, i.e. assign each and every # voxel to one and only one cluster if min_region_size == 'exhaustive': min_region_size_ = _get_voxel_volume(voxel_sizes) - 1 else: min_region_size_ = min_region_size # count overall number of 1s in the binary image total_n_voxels = np.count_nonzero(binary_img.get_fdata()) # extract clusters in binary image cluster_imgs, indices = connected_regions( maps_img=binary_img, min_region_size=min_region_size_, extract_type='connected_components', smoothing_fwhm=None, mask_img=mask_img) # Get sizes of clusters (number of voxels that have been assigned to each region) # As a sanity check + for user information get size of every region and # count overall number of voxels that have been assigned to that region cluster_sizes = [] total_n_voxels_assigned = 0 for idx, cluster_img in enumerate(iter_img(cluster_imgs)): cluster_img_data = cluster_img.get_fdata() cluster_img_size = np.count_nonzero(cluster_img_data) cluster_sizes.append(cluster_img_size) total_n_voxels_assigned += cluster_img_size if total_n_voxels_assigned != total_n_voxels: raise ValueError( 'Number of voxels in output clustered image is different from total number of voxels in input binary image ' ) # Collapse the extracted cluster images to one cluster atlas image cluster_imgs_labeled = [] for idx, cluster_img in enumerate(iter_img(cluster_imgs), start=1): cluster_img_labeled = math_img( f"np.where(cluster_img == 1,{idx},cluster_img)", cluster_img=cluster_img) cluster_imgs_labeled.append(cluster_img_labeled) cluster_img_atlas = math_img("np.sum(imgs,axis=3)", imgs=cluster_imgs_labeled) # plot the cluster atlas image plotting.plot_roi(cluster_img_atlas, title='Clustered Binary Image', draw_cross=False) return cluster_sizes, cluster_img_atlas
def average_image_pairs(image_pairs, image_paths, rotated_bvecs, bvals, confounds_tsvs, raw_concatenated_files, verbose=False): """Create 4D series of averaged images, gradients, and confounds""" averaged_images = [] new_bvecs = [] confounds = pd.concat( [pd.read_csv(fname, delimiter='\t') for fname in confounds_tsvs]) merged_confounds = [] merged_bvals = [] # Load the raw concatenated images for qc raw_concatenated_img = concat_imgs(raw_concatenated_files) raw_averaged_images = [] confounds1_rename = {col: col + "_1" for col in confounds.columns} confounds2_rename = {col: col + "_2" for col in confounds.columns} for index1, index2 in image_pairs: confounds1 = confounds.iloc[index1].copy().rename(confounds1_rename) confounds2 = confounds.iloc[index2].copy().rename(confounds2_rename) confounds_both = confounds1.append(confounds2) averaged_images.append( math_img('(a+b)/2', a=image_paths[index1], b=image_paths[index2])) raw_averaged_images.append( math_img('(a[..., %d] + a[..., %d]) / 2' % (index1, index2), a=raw_concatenated_img)) new_bval = (bvals[index1] + bvals[index2]) / 2. merged_bvals.append(new_bval) rotated1 = rotated_bvecs[:, index1] rotated2 = rotated_bvecs[:, index2] new_bvec, bvec_error = average_bvec(rotated1, rotated2) new_bvecs.append(new_bvec) confounds_both['vec_averaging_error'] = bvec_error confounds_both['rotated_grad_x_1'] = rotated1[0] confounds_both['rotated_grad_y_1'] = rotated1[1] confounds_both['rotated_grad_z_1'] = rotated1[2] confounds_both['rotated_grad_x_2'] = rotated2[0] confounds_both['rotated_grad_y_2'] = rotated2[1] confounds_both['rotated_grad_z_2'] = rotated2[2] confounds_both['mean_grad_x'] = new_bvec[0] confounds_both['mean_grad_y'] = new_bvec[1] confounds_both['mean_grad_z'] = new_bvec[2] confounds_both['mean_b'] = new_bval merged_confounds.append(confounds_both) if verbose: print('%d: %d [%.4fdeg error]\n\t%d (%.4f %.4f %.4f)' % (index1, index2, bvec_error, new_bval, new_bvec[0], new_bvec[1], new_bvec[2])) averaged_confounds = pd.DataFrame(merged_confounds) return concat_imgs(averaged_images), concat_imgs(raw_averaged_images), \ np.array(merged_bvals), np.array(new_bvecs), averaged_confounds
def plot(self, downsample=1, out_base="."): out_path = os.path.join(out_base, self.subject, self.name, self.task) os.makedirs(out_path, exist_ok=True) raw = nib.load(self.path) M = np.max(raw.get_data()) n = raw.shape[3] mean = nimage.mean_img(raw) xyzcuts = nilplot.find_xyz_cut_coords(mean) xcuts = nilplot.find_cut_slices(mean, "x") ycuts = nilplot.find_cut_slices(mean, "y") zcuts = nilplot.find_cut_slices(mean, "z") del raw nrange = range(0, n, downsample) for i, img in enumerate(nimage.iter_img(self.path)): if i in nrange: nilplot.plot_epi(nimage.math_img("img / %f" % (M), img=img), colorbar=False, output_file="%s/orth_epi%0d.png" % (out_path, i), annotate=True, cut_coords=xyzcuts, cmap="gist_heat") nilplot.plot_epi(nimage.math_img("img / %f" % (M), img=img), colorbar=False, output_file="%s/x_epi%0d.png" % (out_path, i), annotate=True, display_mode="x", cut_coords=xcuts, cmap="gist_heat") nilplot.plot_epi(nimage.math_img("img / %f" % (M), img=img), colorbar=False, output_file="%s/y_epi%0d.png" % (out_path, i), annotate=True, display_mode="y", cut_coords=ycuts, cmap="gist_heat") nilplot.plot_epi(nimage.math_img("img / %f" % (M), img=img), colorbar=False, output_file="%s/z_epi%0d.png" % (out_path, i), annotate=True, display_mode="z", cut_coords=zcuts, cmap="gist_heat") slice_names = ["orth_epi", "x_epi", "y_epi", "z_epi"] for slic in slice_names: filenames = ["%s/%s%0d.png" % (out_path, slic, i) for i in nrange] with imageio.get_writer('%s/%s.gif' % (out_path, slic), mode='I') as writer: for i, filename in zip(nrange, filenames): image = Image.open(filename) draw = ImageDraw.Draw(image) fnt = ImageFont.truetype('Pillow/Tests/fonts/FreeMono.ttf', 16) draw.text((2, 2), str(i), font=fnt, fill=(255, 0, 0, 255)) image.save(filename, "PNG") image = imageio.imread(filename) writer.append_data(image)
def main(sourcedata, derivatives, subject, session, tmp_dir): sourcedata_layout = BIDSLayout(sourcedata) sourcedata_df = sourcedata_layout.as_data_frame() events = sourcedata_df[(sourcedata_df['type'] == 'events') & (sourcedata_df['subject'] == subject) & (sourcedata_df['session'] == session)] derivatives_layout = BIDSLayout(os.path.join(derivatives, 'spynoza')) derivatives_df = derivatives_layout.as_data_frame() bold = derivatives_df[(derivatives_df['type'] == 'preproc') & (derivatives_df['subject'] == subject) & (derivatives_df['session'] == session)] mask = derivatives_layout.get(subject=subject, session=session, type='mask', return_type='file')[0] mask = image.math_img('(im > .5).astype(int)', im=mask) print(mask) row = bold.iloc[0] results_dir = os.path.join(derivatives, 'modelfitting_av', 'glm2', 'sub-{}'.format(row['subject'])) os.makedirs(results_dir, exist_ok=True) av_bold_fn = os.path.join( results_dir, 'sub-{}_ses-{}_bold_average.nii.gz'.format(row['subject'], row['session'])) av_bold = average_over_runs(bold.path.tolist(), output_filename=av_bold_fn) av_bold = image.math_img('(av_bold / av_bold.mean(-1)[..., np.newaxis])', av_bold=av_bold) av_bold.to_filename(av_bold_fn) model = FirstLevelModel(t_r=4, mask=mask, drift_model=None) paradigm = pd.read_table(events.iloc[0]['path']) model.fit(av_bold, paradigm) left_right = model.compute_contrast('eye_L - eye_R', output_type='z_score') left_right.to_filename( os.path.join( results_dir, 'sub-{}_ses-{}_left_over_right_zmap.nii.gz'.format( row['subject'], row['session'], ))) left_right = model.compute_contrast('eye_L - eye_R', output_type='effect_size') left_right.to_filename( os.path.join( results_dir, 'sub-{}_ses-{}_left_over_right_psc.nii.gz'.format( row['subject'], row['session'])))
def main(modality, field_strength, bids_folder): if modality == 'T1w': source = op.join(bids_folder, 'derivatives', 'fmriprep') template = op.join(source, 'sub-*', 'anat', f'sub-*_space-MNI152NLin2009cAsym_desc-preproc_{modality}.nii.gz') target_fn = op.join(bids_folder, 'derivatives', 'registration', 'group') else: source = op.join(bids_folder, 'derivatives', 'registration') template = op.join(source, 'sub-*', f'ses-{field_strength}*', 'anat', f'sub-*_ses-*_space-MNI152NLin2009cAsym_desc-registered_{modality}.nii.gz') target_fn = op.join(source, 'group') print(sorted(glob.glob(template))) ims = [image.load_img(im) for im in glob.glob(template)] for im in ims: print(im.get_filename()) n_voxels = [np.prod(im.shape) for im in ims] largest_fov = np.argmax(n_voxels) from collections import deque ims = deque(ims) ims.rotate(-largest_fov) ims = [image.math_img('im / np.mean(im[im!=0])', im=im) for im in ims] mean_img = ims[0] sum_img = image.new_img_like(ims[0], np.zeros(ims[0].shape) ) for ix in tqdm(range(1, len(ims))): im = image.resample_to_img(ims[ix], mean_img) mean_img = image.math_img('mean_img + im', mean_img=mean_img, im=im) sum_img = image.math_img('sum_img + (im != 0)', sum_img=sum_img, im=im) ims[ix].uncache() mean_img = image.math_img(f'np.nan_to_num(np.clip(mean_img / sum_img, 0, 10))', mean_img=mean_img, sum_img=sum_img) if not op.exists(target_fn): os.makedirs(target_fn) target_fn = op.join(target_fn, f'group_space-MNI152NLin2009cAsym_field-{field_strength}_{modality}.nii.gz') print(target_fn) mean_img.to_filename(target_fn)
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 get_largest_two_comps(in_img, out_comps): """ Get the two largest connected components :param in_img: input image :param out_comps: output image with two components """ first_comp = largest_connected_component_img(in_img) residual = math_img('img1 - img2', img1=in_img, img2=first_comp) second_comp = largest_connected_component_img(residual) comb_comps = math_img('img1 + img2', img1=first_comp, img2=second_comp) nib.save(comb_comps, out_comps)
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 main(subject, derivatives): dseg_l = get_bids_file(derivatives, 'nighres', 'anat', subject, 'dseg', 'anat', 'average', description='cortex', hemisphere='left') dseg_r = get_bids_file(derivatives, 'nighres', 'anat', subject, 'dseg', 'anat', 'average', description='cortex', hemisphere='right') dseg = image.math_img('dseg_l + dseg_r', dseg_l=dseg_l, dseg_r=dseg_r) t1w = get_bids_file(derivatives, 'averaged_mp2rages', 'anat', subject, 'T1w', 'anat', 'average') mask_folder = op.join(derivatives, 'pycortex', 'masks', 'sub-{subject}').format(**locals()) if not op.exists(mask_folder): os.makedirs(mask_folder) pc_subject = 'odc.{}'.format(subject) masks = cortex.utils.get_roi_masks(pc_subject, 'identity.t1w', gm_sampler='thick') for mask in masks: new_fn = op.join( mask_folder, 'sub-{subject}_desc-{mask}_mask.nii.gz').format(**locals()) mask_im = image.new_img_like(t1w, masks[mask].T) mask_im.to_filename(new_fn) cropped_fn = op.join( mask_folder, 'sub-{subject}_desc-{mask}_gm_mask.nii.gz').format(**locals()) cropped_mask_im = image.math_img('mask * (dseg == 1)', mask=mask_im, dseg=dseg) cropped_mask_im.to_filename(cropped_fn)
def make_pysurfer_images_lh_rh(folder,suffix='cope1',hemi='lh',threshold=0.9499,coords=(),surface='inflated',fwhm=0,filename='',saveFolder=[],vmax=5.0,bsize=5): from surfer import Brain, io TFCEposImg,posImg,TFCEnegImg,negImg=getFileNamesfromFolder(folder,suffix) pos=image.math_img("np.multiply(img1,img2)", img1=image.threshold_img(TFCEposImg,threshold=threshold),img2=posImg) neg=image.math_img("np.multiply(img1,img2)", img1=image.threshold_img(TFCEnegImg,threshold=threshold),img2=negImg) fw=image.math_img("img1-img2",img1=pos,img2=neg) if fwhm==0: smin=np.min(np.abs(fw.get_data()[fw.get_data()!=0])) else: smin=2 mri_file = "%s/thresholded_posneg.nii.gz" % folder fw.to_filename(mri_file) """Bring up the visualization""" brain = Brain("fsaverage",hemi,surface, offscreen=True , background="white") """Project the volume file and return as an array""" reg_file = os.path.join("/opt/freesurfer","average/mni152.register.dat") surf_data = io.project_volume_data(mri_file, hemi, reg_file,smooth_fwhm=fwhm) # surf_data_rh = io.project_volume_data(mri_file, "rh", reg_file,smooth_fwhm=fwhm) """ You can pass this array to the add_overlay method for a typical activation overlay (with thresholding, etc.). """ brain.add_overlay(surf_data, min=smin, max=vmax, name="activation", hemi=hemi) # brain.overlays["activation"] # brain.add_overlay(surf_data_rh, min=smin, max=5, name="ang_corr_rh", hemi='rh') if len(coords)>0: if coords[0]>0: hemi2='rh' else: hemi2='lh' brain.add_foci(coords, map_surface="pial", color="gold",hemi=hemi2) if len(saveFolder)>0: folder=saveFolder image_out=brain.save_montage('%s/%s-%s.png' % (folder,hemi,filename),order=['l','m'],orientation='h',border_size=bsize,colorbar=None) else: image_out=brain.save_image('%s/surfaceplot.jpg' % folder) brain.close() return image_out
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 gen_tissue(self, wm_mask_existing, gm_mask_existing, csf_mask_existing, overwrite): """ A function to segment and threshold tissue types from T1w. """ import time import shutil # Segment the t1w brain into probability maps if (wm_mask_existing is not None and gm_mask_existing is not None and csf_mask_existing is not None and overwrite is False): print("Existing segmentations detected...") wm_mask = regutils.orient_reslice(wm_mask_existing, self.basedir_path, self.vox_size, overwrite=False) gm_mask = regutils.orient_reslice(gm_mask_existing, self.basedir_path, self.vox_size, overwrite=False) csf_mask = regutils.orient_reslice(csf_mask_existing, self.basedir_path, self.vox_size, overwrite=False) else: try: maps = regutils.segment_t1w(self.t1w_brain, self.map_name) wm_mask = maps["wm_prob"] gm_mask = maps["gm_prob"] csf_mask = maps["csf_prob"] except RuntimeError as e: print( e, "Segmentation failed. Does the input anatomical image " "still contained skull?") # Threshold WM to binary in dwi space math_img("img > 0.10", img=nib.load(wm_mask)).to_filename(self.wm_mask_thr) # Extract wm edge self.wm_edge = regutils.get_wm_contour(wm_mask, self.wm_mask_thr, self.wm_edge) time.sleep(0.5) shutil.copyfile(wm_mask, self.wm_mask) shutil.copyfile(gm_mask, self.gm_mask) shutil.copyfile(csf_mask, self.csf_mask) return
def _post_skullstrip(anat_skullstripped, anat_postprocess, anat_dir, flip_x): """ Here we assume the input file is skull stripped already, and therefore this function wouldn't do much except maybe flipping the orientation of the scan. args: anat_skullstripped: name of the anatomical scan file. This file is assumed to be already skull stripped. flip_x: whether to flip the x axis of the input scan. See: utils.flip_x_axis anat_out: the name of the output file, with extension. anat_dir: current working directory """ in_file = build_image_path(anat_skullstripped, anat_dir, check_exist=True) out_file = build_image_path(anat_postprocess, anat_dir, check_exist=False) if not flip_x: if in_file == out_file: return out_file # nothing to do here # else if (not flip_x and anat != anat_out), copy the input file copyfile(in_file, out_file) return out_file # else, we need to re-orientate I = math_img('np.flipud(data)', data = in_file) print 'anatomical data flipped' nib.save(I, out_file) return out_file
def math_img(formula, out_file='', **imgs): """ Use nilearn.image.math_img. This function in addition allows imgs to contain numerical scalar values. Returns ------- out_file: str The absolute path to the output file. """ import numpy as np from nilearn.image import math_img from six import string_types for arg in list(imgs.keys()): if isinstance(imgs[arg], string_types): continue if np.isscalar(imgs[arg]): if arg not in formula: raise ValueError("Could not find {} in the formula: {}.".format(arg, formula)) formula = formula.replace(arg, str(imgs[arg])) imgs.pop(arg) return math_img(formula=formula, **imgs)
def main(): # Future: add arguments for inFn, outFn, and volNum parser = argparse.ArgumentParser() parser.add_argument('-i', '--input', type=str, help='/path/to/input/file') parser.add_argument('-o', '--output', type=str, help='/path/to/input/file') args = parser.parse_args() # Specify filepaths inFn = args.input outFn = args.output # load the image img = nibabel.load(inFn) aff = img.affine # resample the image resampled = nibabel.processing.resample_to_output(img, [4, 4, 4]) scaling = np.abs(4 / aff[0][0]) # If the image was a mask, threshold it to a binary image if "mask" in inFn: resampled = math_img("img >= 1", img=resampled) # newAff = changeCoords(aff, scaling) # print(aff) # print(newAff) # data = resampled.get_fdata() # img = nibabel.Nifti1Image(data, newAff) # Save the volume # nibabel.save(img, outFn) nibabel.save(resampled, outFn)
def elementary_contrasts(con_imgs, var_imgs, mask_img): """ """ outputs = [] n_contrasts = 4 for i in range(n_contrasts): effects = [math_img('-(1. / 3) * i1', i1=con_img) for con_img in con_imgs] effects[i] = con_imgs[i] variance = [math_img('(1. / 9) * i1', i1=var_img) for var_img in var_imgs] variance[i] = var_imgs[i] output = compute_contrast( effects, variance, mask_img) outputs.append(output) return(outputs)
def deface_t2w(image, warped_mask, outfile): """ Deface T2w image using the defaced T1w image as deface mask. Parameters ---------- image : str Path to image. warped_mask : str Path to warped defaced T1w image. outfile: str Name of the defaced file. """ from nibabel import load, Nifti1Image from nilearn.image import math_img # functionality copied from pydeface infile_img = load(image) warped_mask_img = load(warped_mask) warped_mask_img = math_img('img > 0', img=warped_mask_img) try: outdata = infile_img.get_fdata().squeeze() * warped_mask_img.get_fdata( ) except ValueError: tmpdata = np.stack([warped_mask_img.get_fdata()] * infile_img.get_fdata().shape[-1], axis=-1) outdata = infile_img.fget_data() * tmpdata masked_brain = Nifti1Image(outdata, infile_img.get_affine(), infile_img.get_header()) masked_brain.to_filename(outfile)
def get_masker_coord(filename): if 'BASC' in filename: basc = datasets.fetch_atlas_basc_multiscale_2015(version='sym')['scale444'] filename=basc nib_basc444 = nib.load(basc) labels_data = nib_basc444.get_data() else: nib_parcel = nib.load(filename) labels_data = nib_parcel.get_data() #fetch all possible label values all_labels = np.unique(labels_data) # remove the 0. value which correspond to voxels out of ROIs all_labels = all_labels[1:] # bari_labels = np.zeros((all_labels.shape[0],3)) # ## go through all labels # for i,curlabel in enumerate(all_labels): # vox_in_label = np.stack(np.argwhere(labels_data == curlabel)) # bari_labels[i] = vox_in_label.mean(axis=0) # allcoords=[] for i,curlabel in enumerate(all_labels): img_curlab = math_img(formula="img==%d"%curlabel,img=filename) allcoords.append(find_xyz_cut_coords(img_curlab)) allcoords=np.array(allcoords) return allcoords
def make_rois_img(rois_aggregate): rois_img = rois_aggregate[0] for i in range(1, len(rois_aggregate)): rois_img = math_img('i1 + %d * i2' % (i + 1), i1=rois_img, i2=rois_aggregate[i]) return rois_img
def make_pca_mask(pca_map, mask): from nilearn import image from nipype.utils.filemanip import split_filename import os.path as op _, fn, ext = split_filename(mask) pca_map = image.load_img(pca_map) mask = image.load_img(mask) pca_map = image.resample_to_img(pca_map, mask, interpolation='nearest') new_mask = image.math_img('pca_map * (mask > 0)', pca_map=pca_map, mask=mask) tmp = new_mask.get_data() tmp[tmp != 0] -= tmp[tmp != 0].min() - 1e-4 tmp[tmp != 0] /= tmp[tmp != 0].max() new_mask = image.new_img_like(new_mask, tmp) new_mask.to_filename(op.abspath('{}_map{}'.format(fn, ext))) return new_mask.get_filename()
def _run_interface(self, runtime): output_fname = fname_presuffix(self.inputs.dwi_series, suffix='_b0_series', use_ext=True, newpath=runtime.cwd) output_mean_fname = fname_presuffix(output_fname, suffix='_mean', use_ext=True, newpath=runtime.cwd) if isdefined(self.inputs.b0_indices): indices = np.array(self.inputs.b0_indices).astype(np.int) elif isdefined(self.inputs.bval_file): bvals = np.loadtxt(self.inputs.bval_file) indices = np.flatnonzero(bvals < self.inputs.b0_threshold) if indices.size == 0: raise ValueError("No b<%d images found" % self.inputs.b0_threshold) else: raise ValueError("No gradient information available") new_data = nim.index_img(self.inputs.dwi_series, indices) new_data.to_filename(output_fname) self._results['b0_series'] = output_fname if new_data.ndim == 3: self._results['b0_average'] = output_fname else: mean_image = nim.math_img('img.mean(3)', img=new_data) mean_image.to_filename(output_mean_fname) self._results['b0_average'] = output_mean_fname return runtime
def t2starw(self): if self._t2starw is None: self._t2starw = image.mean_img(self.t2starw_echoes) self._t2starw = image.math_img('im / np.percentile(im, 95) * 4095', im=self._t2starw) return self._t2starw
def _get_spheres_from_masker(masker, img): """Re-extract spheres from coordinates to make niimg. Note that this will take a while, as it uses the exact same function that nilearn calls to extract data for NiftiSpheresMasker """ ref_img = nib.load(img) ref_img = nib.Nifti1Image(ref_img.get_fdata()[:, :, :, [0]], ref_img.affine) X, A = _apply_mask_and_get_affinity(masker.seeds, ref_img, masker.radius, masker.allow_overlap) # label sphere masks spheres = A.toarray() spheres *= np.arange(1, len(masker.seeds) + 1)[:, np.newaxis] # combine masks, taking the maximum if overlap occurs arr = np.zeros(spheres.shape[1]) for i in np.arange(spheres.shape[0]): arr = np.maximum(arr, spheres[i, :]) arr = arr.reshape(ref_img.shape[:-1]) spheres_img = nib.Nifti1Image(arr, ref_img.affine) if masker.mask_img is not None: mask_img_ = resample_to_img(masker.mask_img, spheres_img) spheres_img = math_img('img1 * img2', img1=spheres_img, img2=mask_img_) return spheres_img
def _add_mask_to_library(self, mask_name: str = '', target_affine=None, target_shape=None, mask_threshold=0.5): # Todo: find solution for multiprocessing spaming if mask_name in self.photon_masks.keys(): original_mask_object = self.photon_masks[mask_name] else: logger.debug("Checking custom mask") original_mask_object = self._check_custom_mask(mask_name) mask_object = MaskObject(name=mask_name, mask_file=original_mask_object.mask_file) #mask_object.mask = image.threshold_img(mask_object.mask_file, threshold=mask_threshold) mask_object.mask = image.math_img('img > {}'.format(mask_threshold), img=mask_object.mask_file) if target_affine is not None and target_shape is not None: mask_object.mask = self._resample(mask_object.mask, target_affine=target_affine, target_shape=target_shape) # check if roi is empty if np.sum(mask_object.mask.dataobj != 0) == 0: mask_object.is_empty = True msg = 'No voxels in mask after resampling (' + mask_object.name + ').' logger.error(msg) raise ValueError(msg) AtlasLibrary.LIBRARY[(mask_object.name, str(target_affine), str(target_shape), str(mask_threshold))] = mask_object logger.debug("BrainMask: Done adding mask to library!")
def save_imgs(bg_img, stats_img, seed_img, output_path): vmin, vmax = abs(args.vmin), abs(args.vmax) if args.mask: stats_img = image.math_img('img1 * img2', img1=stats_img, img2=datasets.load_mni152_brain_mask()) slices = {'x': (-71, 72), 'y': (-107, 74), 'z': (-70, 82)} for key, value in slices.items(): for i in range(value[0], value[1]): if args.verbose: print(f'slice: {key}={i}') img = plotting.plot_stat_map(bg_img=bg_img, stat_map_img=stats_img, threshold=vmin, vmax=vmax, display_mode=key, cut_coords=[i], colorbar=False, annotate=False, draw_cross=False) if args.seed: img.add_overlay(seed_img, cmap='cold_hot', alpha=.25) img.savefig(f'{output_path}_{key}={i}.png', dpi=600) img.close() del img
def math_img(formula, out_file='', **imgs): """ Use nilearn.image.math_img. This function in addition allows imgs to contain numerical scalar values. Returns ------- out_file: str The absolute path to the output file. """ import numpy as np import nilearn.image as niimg from six import string_types for arg in list(imgs.keys()): if isinstance(imgs[arg], string_types): continue if np.isscalar(imgs[arg]): if arg not in formula: raise ValueError("Could not find {} in the formula: {}.".format(arg, formula)) formula = formula.replace(arg, str(imgs[arg])) imgs.pop(arg) return niimg.math_img(formula=formula, **imgs)
def generate_fmri_data_for_subject(subject): """ Input : Take as input each fmri file. One file = One block Load all fmri data and apply a global mask mak on it. The global mask is computed using the mask from each fmri run (block). Applying a global mask for a subject uniformize the data. Output: Output fmri_runs for a subject, corrected using a global mask """ fmri_filenames = sorted( glob.glob( os.path.join(paths.rootpath, "fmri-data/en", "sub-%03d" % subject, "func", "resample*.nii"))) masks_filenames = sorted( glob.glob( os.path.join(paths.path2Data, "en/fmri_data/masks", "sub_{}".format(subject), "resample*.pkl"))) masks = [] for file in masks_filenames: with open(file, 'rb') as f: mask = pickle.load(f) masks.append(mask) global_mask = math_img('img>0.5', img=mean_img(masks)) masker = MultiNiftiMasker(global_mask, detrend=True, standardize=True) masker.fit() fmri_runs = [masker.transform(f) for f in tqdm(fmri_filenames)] print(fmri_runs[0].shape) return fmri_runs
def concat_RL(R_img, L_img, rl_idx_pair, rl_sign_pair=None): """ Given R and L ICA images and their component index pairs, concatenate images to create bilateral image using the index pairs. Sign flipping can be specified in rl_sign_pair. """ # Make sure images have same number of components and indices are less than the n_components assert R_img.shape == L_img.shape n_components = R_img.shape[3] assert np.max(rl_idx_pair) < n_components n_rl_imgs = len(rl_idx_pair[0]) assert n_rl_imgs == len(rl_idx_pair[1]) if rl_sign_pair: assert n_rl_imgs == len(rl_sign_pair[0]) assert n_rl_imgs == len(rl_sign_pair[1]) # Match indice pairs and combine terms = R_img.terms.keys() rl_imgs = [] rl_term_vals = [] for i in range(n_rl_imgs): rci, lci = rl_idx_pair[0][i], rl_idx_pair[1][i] R_comp_img = index_img(R_img, rci) L_comp_img = index_img(L_img, lci) # sign flipping r_sign = rl_sign_pair[0][i] if rl_sign_pair else 1 l_sign = rl_sign_pair[1][i] if rl_sign_pair else 1 R_comp_img = math_img("%d*img" % (r_sign), img=R_comp_img) L_comp_img = math_img("%d*img" % (l_sign), img=L_comp_img) # combine images rl_imgs.append(math_img("r+l", r=R_comp_img, l=L_comp_img)) # combine terms if terms: r_ic_terms, r_ic_term_vals = get_ic_terms(R_img.terms, rci, sign=r_sign) l_ic_terms, l_ic_term_vals = get_ic_terms(L_img.terms, lci, sign=l_sign) rl_term_vals.append((r_ic_term_vals + l_ic_term_vals) / 2) # Squash into single image concat_img = nib.concat_images(rl_imgs) if terms: concat_img.terms = dict(zip(terms, np.asarray(rl_term_vals).T)) return concat_img
def test_math_img(): img1 = Nifti1Image(np.ones((10, 10, 10, 10)), np.eye(4)) img2 = Nifti1Image(np.zeros((10, 10, 10, 10)), np.eye(4)) expected_result = Nifti1Image(np.ones((10, 10, 10)), np.eye(4)) formula = "np.mean(img1, axis=-1) - np.mean(img2, axis=-1)" for create_files in (True, False): with testing.write_tmp_imgs(img1, img2, create_files=create_files) as imgs: result = math_img(formula, img1=imgs[0], img2=imgs[1]) assert_array_equal(result.get_data(), expected_result.get_data()) assert_array_equal(result.affine, expected_result.affine) assert_equal(result.shape, expected_result.shape)
def scale_MP2RAGE(in_file, minimum=0, mean=100, overwrite=True): """ Scales the MP2RAGE such that does not have any negative values and a mean around 100. Based on https://mail.nmr.mgh.harvard.edu/pipermail//freesurfer/2017-July/052950.html """ scaled = image.math_img('(img - np.min(img)) * 100', img=in_file) json = in_file.replace('.nii.gz', '.json') if overwrite: scaled.to_filename(in_file) else: scaled.to_filename(in_file.replace('acq-', 'acq-Rescaled')) if os.path.isfile(json): os.rename(json, json.replace('acq-', 'acq-Rescaled'))
print("\n\nCollection {0}:".format(this_meta['id'])) current_collection = this_meta['collection_id'] # Load and validate the downloaded image. t_img = load_img(this_meta['absolute_path']) deg_of_freedom = this_meta['number_of_subjects'] - 2 print(" Image {1}: degrees of freedom: {2}".format( "", this_meta['id'], deg_of_freedom)) # Convert data, create new image. z_img = new_img_like( t_img, t_to_z(t_img.get_data(), deg_of_freedom=deg_of_freedom)) z_imgs.append(z_img) ###################################################################### # Plot the combined z maps # ------------------------ cut_coords = [-15, -8, 6, 30, 46, 62] meta_analysis_img = math_img( 'np.sum(z_imgs, axis=3) / np.sqrt(z_imgs.shape[3])', z_imgs=z_imgs) plotting.plot_stat_map(meta_analysis_img, display_mode='z', threshold=6, cut_coords=cut_coords, vmax=12) plotting.show()
The goal of this example is to illustrate the use of the function :func:`nilearn.image.math_img` with a list of images as input. We compare the means of 2 resting state 4D images. The mean of the images could have been computed with nilearn :func:`nilearn.image.mean_img` function. """ ############################################################################### # Fetching 2 subject resting state functionnal MRI from datasets. from nilearn import datasets dataset = datasets.fetch_adhd(n_subjects=2) ############################################################################### # Print basic information on the adhd subjects resting state datasets. print('Subject 1 resting state dataset at: %s' % dataset.func[0]) print('Subject 2 resting state dataset at: %s' % dataset.func[1]) ############################################################################### # Comparing the means of the 2 resting state datasets. from nilearn import plotting, image result_img = image.math_img("np.mean(img1, axis=-1) - np.mean(img2, axis=-1)", img1=dataset.func[0], img2=dataset.func[1]) plotting.plot_stat_map(result_img, title="Comparing means of 2 resting state 4D images.") plotting.show()
""" Negating an image with math_img =============================== The goal of this example is to illustrate the use of the function :func:`nilearn.image.math_img` on T-maps. We compute a negative image by multiplying its voxel values with -1. """ from nilearn import datasets, plotting, image ############################################################################### # Retrieve the data: the localizer dataset with contrast maps. motor_images = datasets.fetch_neurovault_motor_task() stat_img = motor_images.images[0] ############################################################################### # Multiply voxel values by -1. negative_stat_img = image.math_img("-img", img=stat_img) plotting.plot_stat_map(stat_img, cut_coords=(36, -27, 66), threshold=3, title="t-map", vmax=9 ) plotting.plot_stat_map(negative_stat_img, cut_coords=(36, -27, 66), threshold=3, title="Negative t-map", vmax=9 ) plotting.show()
########################################################################### # As expected, we find the motor cortex plotting.show() ########################################################################## # Computing the (corrected) p-values with parametric test to compare with # non parametric test import numpy as np from nilearn.image import math_img from nilearn.input_data import NiftiMasker p_val = second_level_model.compute_contrast(output_type='p_value') n_voxels = np.sum(second_level_model.masker_.mask_img_.get_data()) # Correcting the p-values for multiple testing and taking negative logarithm neg_log_pval = math_img("-np.log10(np.minimum(1, img * {}))" .format(str(n_voxels)), img=p_val) ########################################################################### # Let us plot the (corrected) negative log p-values for the parametric test cut_coords = [0] # Since we are plotting negative log p-values and using a threshold equal to 1, # it corresponds to corrected p-values lower than 10%, meaning that there # is less than 10% probability to make a single false discovery # (90% chance that we make no false discovery at all). # This threshold is much more conservative than the previous one. threshold = 1 title = ('Group left-right button press: \n' 'parametric test (FWER < 10%)') display = plotting.plot_glass_brain( neg_log_pval, colorbar=True, display_mode='z', plot_abs=False, vmax=3,
files = dataset.fetch(n_subjects=2, data_types=['task']) # Filter subject 2 only nii_files = filter(lambda fil: fil and '100408' in fil and fil.endswith('_LR.nii.gz'), files) tasks = ['emotion', 'gambling', 'language', 'motor', 'social', 'wm'] # Compute mean images mean_imgs = dict() for task in tasks: mean_imgs[task] = mean_img(filter(lambda fil: task.upper() in fil, nii_files)[0]) # Now make a matrix. fh = plt.figure(figsize=(18, 10)) for ti1, task1 in enumerate(tasks): for ti2 in range(0, ti1 - 1): task2 = tasks[ti2] ax = fh.add_subplot(5, 5, (ti1 - 1) * 5 + ti2 + 1) img = math_img("img1 - img2", img1=mean_imgs[task1], img2=mean_imgs[task2]) plot_stat_map( img, title='%s - %s' % (task1, task2), symmetric_cbar=True, black_bg=True, display_mode='yz', axes=ax) plt.show() # Print out a matrix import pdb; pdb.set_trace()
def spatclust(img, min_cluster_size, threshold=None, index=None, mask=None): """ Spatially clusters `img` Parameters ---------- img : str or img_like Image file or object to be clustered min_cluster_size : int Minimum cluster size (in voxels) threshold : float, optional Whether to threshold `img` before clustering index : array_like, optional Whether to extract volumes from `img` for clustering mask : (S,) array_like, optional Boolean array for masking resultant data array Returns ------- clustered : :obj:`numpy.ndarray` Boolean array of clustered (and thresholded) `img` data """ # we need a 4D image for `niimg.iter_img`, below img = niimg.copy_img(check_niimg(img, atleast_4d=True)) # temporarily set voxel sizes to 1mm isotropic so that `min_cluster_size` # represents the minimum number of voxels we want to be in a cluster, # rather than the minimum size of the desired clusters in mm^3 if not np.all(np.abs(np.diag(img.affine)) == 1): img.set_sform(np.sign(img.affine)) # grab desired volumes from provided image if index is not None: if not isinstance(index, list): index = [index] img = niimg.index_img(img, index) # threshold image if threshold is not None: img = niimg.threshold_img(img, float(threshold)) clout = [] for subbrick in niimg.iter_img(img): # `min_region_size` is not inclusive (as in AFNI's `3dmerge`) # subtract one voxel to ensure we aren't hitting this thresholding issue try: clsts = connected_regions(subbrick, min_region_size=int(min_cluster_size) - 1, smoothing_fwhm=None, extract_type='connected_components')[0] # if no clusters are detected we get a TypeError; create a blank 4D # image object as a placeholder instead except TypeError: clsts = niimg.new_img_like(subbrick, np.zeros(subbrick.shape + (1,))) # if multiple clusters detected, collapse into one volume clout += [niimg.math_img('np.sum(a, axis=-1)', a=clsts)] # convert back to data array and make boolean clustered = utils.load_image(niimg.concat_imgs(clout).get_data()) != 0 # if mask provided, mask output if mask is not None: clustered = clustered[mask] return clustered
def plot_component_comparisons(images, labels, score_mat, sign_mat, force=False, out_dir=None): """ Uses the score_mat to match up two images. If force, one-to-one matching is forced. Sign_mat is used to flip signs when comparing two images. """ # Be careful assert len(images) == 2 assert len(labels) == 2 assert images[0].shape == images[1].shape n_components = images[0].shape[3] # values @ 0 and 1 are the same assert score_mat.shape == sign_mat.shape assert len(score_mat[0]) == n_components # Get indices for matching components match, unmatch = get_match_idx_pair(score_mat, sign_mat, force=force) idx_pair = match["idx"] sign_pair = match["sign"] if not force and unmatch["idx"] is not None: idx_pair = np.hstack((idx_pair, unmatch["idx"])) sign_pair = np.hstack((sign_pair, unmatch["sign"])) n_comp = len(idx_pair[0]) # number of comparisons # Calculate a vmax optimal across all the plots # get nonzero part of the image for proper thresholding of # r- or l- only component nonzero_imgs = [img.get_data()[np.nonzero(img.get_data())] for img in images] dat = np.append(nonzero_imgs[0], nonzero_imgs[1]) vmax = stats.scoreatpercentile(np.abs(dat), 99.99) print("Plotting results.") for i in range(n_comp): c1i, c2i = idx_pair[0][i], idx_pair[1][i] cis = [c1i, c2i] prefix = "unmatched-" if i >= n_components else "" num = i-n_components if i >= n_components else i png_name = '%s%s_%s_%s.png' % (prefix, labels[0], labels[1], num) print "plotting %s" % png_name comp_imgs = [index_img(img, ci) for img, ci in zip(images, cis)] # flip the sign if sign_mat for the corresponding comparison is -1 signs = [sign_pair[0][i], sign_pair[1][i]] comp_imgs = [math_img("%d*img" % (sign), img=img) for sign, img in zip(signs, comp_imgs)] if ('R' in labels and 'L' in labels): # Combine left and right image, show just one. # terms are not combined here comp = math_img("img1+img2", img1=comp_imgs[0], img2=comp_imgs[1]) titles = [_title_from_terms( terms=comp_imgs[labels.index(hemi)].terms, ic_idx=cis[labels.index(hemi)], label=hemi, sign=signs[labels.index(hemi)]) for hemi in labels] fh = plt.figure(figsize=(14, 8)) plot_stat_map( comp, axes=fh.gca(), title="\n".join(titles), black_bg=True, symmetric_cbar=True, vmax=vmax) else: # Show two images, one above the other. fh = plt.figure(figsize=(14, 12)) for ii in [0, 1]: # Subplot per image ax = fh.add_subplot(2, 1, ii + 1) comp = comp_imgs[ii] title = _title_from_terms( terms=images[ii].terms, ic_idx=cis[ii], label=labels[ii], sign=signs[ii]) if ii == 0: display = plot_stat_map(comp, axes=ax, title=title, # noqa black_bg=True, symmetric_cbar=True, vmax=vmax) else: # use same cut coords cut_coords = display.cut_coords # noqa display = plot_stat_map(comp, axes=ax, title=title, black_bg=True, symmetric_cbar=True, vmax=vmax, display_mode='ortho', cut_coords=cut_coords) # Save images instead of displaying if out_dir is not None: save_and_close(out_path=op.join(out_dir, png_name), fh=fh)