def test_high_level_glm_with_paths(): shapes, rk = ((5, 6, 4, 20), (5, 6, 4, 19)), 3 with InTemporaryDirectory(): mask_file, fmri_files, design_files = write_fake_fmri_data(shapes, rk) multi_session_model = FMRILinearModel(fmri_files, design_files, mask_file) multi_session_model.fit() z_image, = multi_session_model.contrast([np.eye(rk)[1]] * 2) assert_array_equal(get_affine(z_image), get_affine(load(mask_file))) assert_true(z_image.get_data().std() < 3.0) # Delete objects attached to files to avoid WindowsError when deleting # temporary directory del z_image, fmri_files, multi_session_model
def test_high_level_glm_with_paths(): shapes, rk = ((5, 6, 4, 20), (5, 6, 4, 19)), 3 with InTemporaryDirectory(): mask_file, fmri_files, design_files = write_fake_fmri_data(shapes, rk) multi_session_model = FMRILinearModel(fmri_files, design_files, mask_file) multi_session_model.fit() z_image, = multi_session_model.contrast([np.eye(rk)[1]] * 2) assert_array_equal(get_affine(z_image), get_affine(load(mask_file))) assert_true(z_image.get_data().std() < 3.) # Delete objects attached to files to avoid WindowsError when deleting # temporary directory del z_image, fmri_files, multi_session_model
def make_feature_from_image(self, path, fid=''): """Extract the information from an image to make it a domain a feature Parameters ---------- path: string or Nifti1Image instance, the image from which one wished to extract data fid: string, optional identifier of the resulting feature. if '', the feature is not stored Returns ------- the correponding set of values """ if isinstance(path, string_types): nim = load(path) else: nim = path if (get_affine(nim) != self.affine).any(): raise ValueError('nim and self do not have the same referential') data = nim.get_data() feature = data[self.ijk[:, 0], self.ijk[:, 1], self.ijk[:, 2]] if fid is not '': self.features[fid] = feature return feature
def subdomain_from_image(mim, nn=18): """Return a SubDomain instance from the input mask image. Parameters ---------- mim: NiftiIImage instance, or string path toward such an image supposedly a label image nn: int, optional Neighboring system considered from the image can be 6, 18 or 26. Returns ------- The MultipleROI instance Notes ----- Only labels > -1 are considered """ if isinstance(mim, string_types): iim = load(mim) else: iim = mim return subdomain_from_array(iim.get_data(), get_affine(iim), nn)
def mask_parcellation(mask_images, nb_parcel, threshold=0, output_image=None): """ Performs the parcellation of a certain mask Parameters ---------- mask_images: string or Nifti1Image or list of strings/Nifti1Images, paths of mask image(s) that define(s) the common space. nb_parcel: int, number of desired parcels threshold: float, optional, level of intersection of the masks output_image: string, optional path of the output image Returns ------- wim: Nifti1Imagine instance, representing the resulting parcellation """ if isinstance(mask_images, basestring): mask = mask_images elif isinstance(mask_images, Nifti1Image): mask = mask_images else: # mask_images should be a list mask_data = intersect_masks(mask_images, threshold=0) > 0 mask = Nifti1Image(mask_data.astype('u8'), get_affine(load(mask_images[0]))) domain = grid_domain_from_image(mask) cent, labels, J = kmeans(domain.coord, nb_parcel) sub_dom = SubDomains(domain, labels) # get id (or labels) image wim = sub_dom.to_image(fid='id', roi=True) return wim
def test_example(): # Test example runs correctly eg_img = pjoin(dirname(__file__), 'some_blobs.nii') nim = load(eg_img) mask_image = Nifti1Image((nim.get_data()**2 > 0).astype('u8'), get_affine(nim)) domain = grid_domain_from_image(mask_image) data = nim.get_data() values = data[data != 0] # parameters threshold = 3.0 # blob-forming threshold smin = 5 # size threshold on blobs # compute the nested roi object nroi = HROI_as_discrete_domain_blobs(domain, values, threshold=threshold, smin=smin) # compute region-level activation averages activation = [ values[nroi.select_id(id, roi=False)] for id in nroi.get_id() ] nroi.set_feature('activation', activation) average_activation = nroi.representative_feature('activation') averages = [blob.mean() for blob in nroi.get_feature('activation')] assert_almost_equal(averages, average_activation, 6) # Test repeat assert_equal(average_activation, nroi.representative_feature('activation')) # Binary image is default bin_wim = nroi.to_image() bin_vox = bin_wim.get_data() assert_equal(np.unique(bin_vox), [0, 1]) id_wim = nroi.to_image('id', roi=True, descrip='description') id_vox = id_wim.get_data() mask = bin_vox.astype(bool) assert_equal(id_vox[~mask], -1) ids = nroi.get_id() assert_equal(np.unique(id_vox), [-1] + list(ids)) # Test activation wim = nroi.to_image('activation', roi=True, descrip='description') # Sadly, all cast to int assert_equal(np.unique(wim.get_data().astype(np.int32)), [-1, 3, 4, 5]) # end blobs or leaves lroi = nroi.copy() lroi.reduce_to_leaves() assert_equal(lroi.k, 14) assert_equal(len(lroi.get_feature('activation')), lroi.k)
def subdomain_from_position_and_image(nim, pos): """Keep the set of labels of the image corresponding to a certain index so that their position is closest to the prescribed one. Parameters ---------- mim: NiftiIImage instance, or string path toward such an image supposedly a label image pos: array of shape(3) or list of length 3, the prescribed position """ tmp = subdomain_from_image(nim) coord = np.array([tmp.domain.coord[tmp.label == k].mean(0) for k in range(tmp.k)]) idx = ((coord - pos) ** 2).sum(1).argmin() return subdomain_from_array(nim.get_data() == idx, get_affine(nim))
def get_anat(cls): filename = find_mni_template() if cls.anat is None: if filename is None: raise OSError('Cannot find template file T1_brain.nii.gz ' 'required to plot anatomy, see the nipy documentation ' 'installaton section for how to install template files.') anat_im = load(filename) anat = anat_im.get_data() anat = anat.astype(np.float) anat_mask = ndimage.morphology.binary_fill_holes(anat > 0) anat = np.ma.masked_array(anat, np.logical_not(anat_mask)) cls.anat_sform = get_affine(anat_im) cls.anat = anat cls.anat_max = anat.max() return cls.anat, cls.anat_sform, cls.anat_max
def subdomain_from_position_and_image(nim, pos): """Keep the set of labels of the image corresponding to a certain index so that their position is closest to the prescribed one. Parameters ---------- mim: NiftiIImage instance, or string path toward such an image supposedly a label image pos: array of shape(3) or list of length 3, the prescribed position """ tmp = subdomain_from_image(nim) coord = np.array( [tmp.domain.coord[tmp.label == k].mean(0) for k in range(tmp.k)]) idx = ((coord - pos)**2).sum(1).argmin() return subdomain_from_array(nim.get_data() == idx, get_affine(nim))
def get_anat(cls): filename = find_mni_template() if cls.anat is None: if filename is None: raise OSError( 'Cannot find template file T1_brain.nii.gz ' 'required to plot anatomy, see the nipy documentation ' 'installaton section for how to install template files.') anat_im = load(filename) anat = anat_im.get_data() anat = anat.astype(np.float) anat_mask = ndimage.morphology.binary_fill_holes(anat > 0) anat = np.ma.masked_array(anat, np.logical_not(anat_mask)) cls.anat_sform = get_affine(anat_im) cls.anat = anat cls.anat_max = anat.max() return cls.anat, cls.anat_sform, cls.anat_max
def test_example(): # Test example runs correctly eg_img = pjoin(dirname(__file__), 'some_blobs.nii') nim = load(eg_img) mask_image = Nifti1Image((nim.get_data() ** 2 > 0).astype('u8'), get_affine(nim)) domain = grid_domain_from_image(mask_image) data = nim.get_data() values = data[data != 0] # parameters threshold = 3.0 # blob-forming threshold smin = 5 # size threshold on blobs # compute the nested roi object nroi = HROI_as_discrete_domain_blobs(domain, values, threshold=threshold, smin=smin) # compute region-level activation averages activation = [values[nroi.select_id(id, roi=False)] for id in nroi.get_id()] nroi.set_feature('activation', activation) average_activation = nroi.representative_feature('activation') averages = [blob.mean() for blob in nroi.get_feature('activation')] assert_almost_equal(averages, average_activation, 6) # Test repeat assert_equal(average_activation, nroi.representative_feature('activation')) # Binary image is default bin_wim = nroi.to_image() bin_vox = bin_wim.get_data() assert_equal(np.unique(bin_vox), [0, 1]) id_wim = nroi.to_image('id', roi=True, descrip='description') id_vox = id_wim.get_data() mask = bin_vox.astype(bool) assert_equal(id_vox[~mask], -1) ids = nroi.get_id() assert_equal(np.unique(id_vox), [-1] + list(ids)) # Test activation wim = nroi.to_image('activation', roi=True, descrip='description') # Sadly, all cast to int assert_equal(np.unique(wim.get_data().astype(np.int32)), [-1, 3, 4, 5]) # end blobs or leaves lroi = nroi.copy() lroi.reduce_to_leaves() assert_equal(lroi.k, 14) assert_equal(len(lroi.get_feature('activation')), lroi.k)
def grid_domain_from_image(mim, nn=18): """Return a NDGridDomain instance from the input mask image Parameters ---------- mim: NiftiIImage instance, or string path toward such an image supposedly a mask (where is used to crate the DD) nn: int, optional neighboring system considered from the image can be 6, 18 or 26 Returns ------- The corresponding NDGridDomain instance """ if isinstance(mim, string_types): iim = load(mim) else: iim = mim return grid_domain_from_binary_array(iim.get_data(), get_affine(iim), nn)
def group_reproducibility_metrics( mask_images, contrast_images, variance_images, thresholds, ngroups, method, cluster_threshold=10, number_of_samples=10, sigma=6., do_clusters=True, do_voxels=True, do_peaks=True, swap=False): """ Main function to perform reproducibility analysis, including nifti1 io Parameters ---------- threshold: list or 1-d array, the thresholds to be tested Returns ------- cluster_rep_results: dictionary, results of cluster-level reproducibility analysis voxel_rep_results: dictionary, results of voxel-level reproducibility analysis peak_rep_results: dictionary, results of peak-level reproducibility analysis """ from nibabel import load from ..mask import intersect_masks if ((len(variance_images) == 0) & (method is not 'crfx')): raise ValueError('Variance images are necessary') nsubj = len(contrast_images) # compute the group mask affine = get_affine(load(mask_images[0])) mask = intersect_masks(mask_images, threshold=0) > 0 domain = grid_domain_from_binary_array(mask, affine) # read the data group_con = [] group_var = [] for s in range(nsubj): group_con.append(load(contrast_images[s]).get_data()[mask]) if len(variance_images) > 0: group_var.append(load(variance_images[s]).get_data()[mask]) group_con = np.squeeze(np.array(group_con)).T group_con[np.isnan(group_con)] = 0 if len(variance_images) > 0: group_var = np.squeeze(np.array(group_var)).T group_var[np.isnan(group_var)] = 0 group_var = np.maximum(group_var, 1.e-15) # perform the analysis voxel_rep_results = {} cluster_rep_results = {} peak_rep_results = {} for ng in ngroups: if do_voxels: voxel_rep_results.update({ng: {}}) if do_clusters: cluster_rep_results.update({ng: {}}) if do_peaks: peak_rep_results.update({ng: {}}) for th in thresholds: kappa = [] cls = [] pk = [] kwargs = {'threshold': th, 'csize': cluster_threshold} for i in range(number_of_samples): if do_voxels: kappa.append(voxel_reproducibility( group_con, group_var, domain, ng, method, swap, **kwargs)) if do_clusters: cls.append(cluster_reproducibility( group_con, group_var, domain, ng, sigma, method, swap, **kwargs)) if do_peaks: pk.append(peak_reproducibility( group_con, group_var, domain, ng, sigma, method, swap, **kwargs)) if do_voxels: voxel_rep_results[ng].update({th: np.array(kappa)}) if do_clusters: cluster_rep_results[ng].update({th: np.array(cls)}) if do_peaks: peak_rep_results[ng].update({th: np.array(cls)}) return voxel_rep_results, cluster_rep_results, peak_rep_results
def to_image(self, fid=None, roi=False, method="mean", descrip=None): """Generates a label image that represents self. Parameters ---------- fid: str, Feature to be represented. If None, a binary image of the MROI domain will be we created. roi: bool, Whether or not to write the desired feature as a ROI one. (i.e. a ROI feature corresponding to `fid` will be looked upon, and if not found, a representative feature will be computed from the `fid` feature). method: str, If a feature is written as a ROI feature, this keyword tweaks the way the representative feature is computed. descrip: str, Description of the image, to be written in its header. Notes ----- Requires that self.dom is an ddom.NDGridDomain Returns ------- nim : nibabel nifti image Nifti image corresponding to the ROI feature to be written. """ if not isinstance(self.domain, ddom.NDGridDomain): print('self.domain is not an NDGridDomain; nothing was written.') return None if fid is None: # write a binary representation of the domain if no fid provided nim = self.domain.to_image(data=(self.label != -1).astype(np.int32)) if descrip is None: descrip = 'binary representation of MROI' else: data = -np.ones(self.label.size, dtype=np.int32) tmp_image = self.domain.to_image() mask = tmp_image.get_data().copy().astype(bool) if not roi: # write a feature if fid not in self.features: raise ValueError("`%s` feature could not be found" % fid) for i in self.get_id(): data[self.select_id(i, roi=False)] = \ self.get_feature(fid, i) else: # write a roi feature if fid in self.roi_features: # write from existing roi feature for i in self.get_id(): data[self.select_id(i, roi=False)] = \ self.get_roi_feature( fid, i) elif fid in self.features: # write from representative feature summary_feature = self.representative_feature( fid, method=method) for i in self.get_id(): data[self.select_id(i, roi=False)] = \ summary_feature[self.select_id(i)] # MROI object was defined on a masked image: we square it back. wdata = -np.ones(mask.shape, data.dtype) wdata[mask] = data nim = Nifti1Image(wdata, get_affine(tmp_image)) # set description of the image if descrip is not None: get_header(nim)['descrip'] = descrip return nim
def get_3d_peaks(image, mask=None, threshold=0., nn=18, order_th=0, verbose=False): """ returns all the peaks of image that are with the mask and above the provided threshold Parameters ---------- image, (3d) test image mask=None, (3d) mask image By default no masking is performed threshold=0., float, threshold value above which peaks are considered nn=18, int, number of neighbours of the topological spatial model order_th=0, int, threshold on topological order to validate the peaks Returns ------- peaks, a list of dictionaries, where each dict has the fields: vals, map value at the peak order, topological order of the peak ijk, array of shape (1,3) grid coordinate of the peak pos, array of shape (n_maxima,3) mm coordinates (mapped by affine) of the peaks """ # Masking shape = image.shape if mask is not None: data = image.get_data() * mask.get_data() xyz = np.array(np.where(data > threshold)).T data = data[data > threshold] else: data = image.get_data().ravel() xyz = np.reshape(np.indices(shape), (3, np.prod(shape))).T affine = get_affine(image) if not (data > threshold).any(): if verbose: print('no suprathreshold voxels found') return None # Extract local maxima and connex components above some threshold ff = field_from_graph_and_data(wgraph_from_3d_grid(xyz, k=18), data) maxima, order = ff.get_local_maxima(th=threshold) # retain only the maxima greater than the specified order maxima = maxima[order > order_th] order = order[order > order_th] n_maxima = len(maxima) if n_maxima == 0: # should not occur ? return None # reorder the maxima to have decreasing peak value vals = data[maxima] idx = np.argsort(-vals) maxima = maxima[idx] order = order[idx] vals = data[maxima] ijk = xyz[maxima] pos = np.dot(np.hstack((ijk, np.ones((n_maxima, 1)))), affine.T)[:, :3] peaks = [{ 'val': vals[k], 'order': order[k], 'ijk': ijk[k], 'pos': pos[k] } for k in range(n_maxima)] return peaks
def parcel_input(mask_images, learning_images, ths=.5, fdim=None): """Instantiating a Parcel structure from a give set of input Parameters ---------- mask_images: string or Nifti1Image or list of strings/Nifti1Images, paths of mask image(s) that define(s) the common space. learning_images: (nb_subject-) list of (nb_feature-) list of strings, paths of feature images used as input to the parcellation procedure ths=.5: threshold to select the regions that are common across subjects. if ths = .5, thethreshold is half the number of subjects fdim: int, optional if nb_feature (the dimension of the data) used in subsequent analyses if greater than fdim, a PCA is perfomed to reduce the information in the data Byd efault, no reduction is performed Returns ------- domain : discrete_domain.DiscreteDomain instance that stores the spatial information on the parcelled domain feature: (nb_subect-) list of arrays of shape (domain.size, fdim) feature information available to parcellate the data """ nb_subj = len(learning_images) # get a group-level mask if isinstance(mask_images, basestring): mask = mask_images elif isinstance(mask_images, Nifti1Image): mask = mask_images else: # mask_images should be a list grp_mask = intersect_masks(mask_images, threshold=ths) > 0 mask = Nifti1Image(grp_mask.astype('u8'), get_affine(load(mask_images[0]))) # build the domain domain = grid_domain_from_image(mask, nn=6) #nn = 6 for speed up and stability # load the functional data feature = [] nbeta = len(learning_images[0]) for s in range(nb_subj): if len(learning_images[s]) != nbeta: raise ValueError('Inconsistent number of dimensions') feature.append(np.array([domain.make_feature_from_image(b) for b in learning_images[s]]).T) # Possibly reduce the dimension of the functional data if (len(feature[0].shape) == 1) or (fdim is None): return domain, feature if fdim < feature[0].shape[1]: import numpy.linalg as nl subj = np.concatenate([s * np.ones(feature[s].shape[0]) \ for s in range(nb_subj)]) cfeature = np.concatenate(feature) cfeature -= np.mean(cfeature, 0) m1, m2, m3 = nl.svd(cfeature, 0) cfeature = np.dot(m1, np.diag(m2)) cfeature = cfeature[:, 0:fdim] feature = [cfeature[subj == s] for s in range(nb_subj)] return domain, feature
def group_reproducibility_metrics(mask_images, contrast_images, variance_images, thresholds, ngroups, method, cluster_threshold=10, number_of_samples=10, sigma=6., do_clusters=True, do_voxels=True, do_peaks=True, swap=False): """ Main function to perform reproducibility analysis, including nifti1 io Parameters ---------- threshold: list or 1-d array, the thresholds to be tested Returns ------- cluster_rep_results: dictionary, results of cluster-level reproducibility analysis voxel_rep_results: dictionary, results of voxel-level reproducibility analysis peak_rep_results: dictionary, results of peak-level reproducibility analysis """ from nibabel import load from ..mask import intersect_masks if ((len(variance_images) == 0) & (method is not 'crfx')): raise ValueError('Variance images are necessary') nsubj = len(contrast_images) # compute the group mask affine = get_affine(load(mask_images[0])) mask = intersect_masks(mask_images, threshold=0) > 0 domain = grid_domain_from_binary_array(mask, affine) # read the data group_con = [] group_var = [] for s in range(nsubj): group_con.append(load(contrast_images[s]).get_data()[mask]) if len(variance_images) > 0: group_var.append(load(variance_images[s]).get_data()[mask]) group_con = np.squeeze(np.array(group_con)).T group_con[np.isnan(group_con)] = 0 if len(variance_images) > 0: group_var = np.squeeze(np.array(group_var)).T group_var[np.isnan(group_var)] = 0 group_var = np.maximum(group_var, 1.e-15) # perform the analysis voxel_rep_results = {} cluster_rep_results = {} peak_rep_results = {} for ng in ngroups: if do_voxels: voxel_rep_results.update({ng: {}}) if do_clusters: cluster_rep_results.update({ng: {}}) if do_peaks: peak_rep_results.update({ng: {}}) for th in thresholds: kappa = [] cls = [] pk = [] kwargs = {'threshold': th, 'csize': cluster_threshold} for i in range(number_of_samples): if do_voxels: kappa.append( voxel_reproducibility(group_con, group_var, domain, ng, method, swap, **kwargs)) if do_clusters: cls.append( cluster_reproducibility(group_con, group_var, domain, ng, sigma, method, swap, **kwargs)) if do_peaks: pk.append( peak_reproducibility(group_con, group_var, domain, ng, sigma, method, swap, **kwargs)) if do_voxels: voxel_rep_results[ng].update({th: np.array(kappa)}) if do_clusters: cluster_rep_results[ng].update({th: np.array(cls)}) if do_peaks: peak_rep_results[ng].update({th: np.array(cls)}) return voxel_rep_results, cluster_rep_results, peak_rep_results
def __init__(self, fmri_data, design_matrices, mask="compute", m=0.2, M=0.9, threshold=0.5): """Load the data Parameters ---------- fmri_data : Image or str or sequence of Images / str fmri images / paths of the (4D) fmri images design_matrices : arrays or str or sequence of arrays / str design matrix arrays / paths of .npz files mask : str or Image or None, optional string can be 'compute' or a path to an image image is an input (assumed binary) mask image(s), if 'compute', the mask is computed if None, no masking will be applied m, M, threshold: float, optional parameters of the masking procedure. Should be within [0, 1] Notes ----- The only computation done here is mask computation (if required) Examples -------- We need the example data package for this example >>> from nipy.utils import example_data >>> from nipy.modalities.fmri.glm import FMRILinearModel >>> fmri_files = [example_data.get_filename('fiac', 'fiac0', run) ... for run in ['run1.nii.gz', 'run2.nii.gz']] >>> design_files = [example_data.get_filename('fiac', 'fiac0', run) ... for run in ['run1_design.npz', 'run2_design.npz']] >>> mask = example_data.get_filename('fiac', 'fiac0', 'mask.nii.gz') >>> multi_session_model = FMRILinearModel(fmri_files, design_files, mask) >>> multi_session_model.fit() >>> z_image, = multi_session_model.contrast([np.eye(13)[1]] * 2) The number of voxels with p < 0.001 >>> np.sum(z_image.get_data() > 3.09) 671 """ # manipulate the arguments if isinstance(fmri_data, basestring) or hasattr(fmri_data, "get_data"): fmri_data = [fmri_data] if isinstance(design_matrices, (basestring, np.ndarray)): design_matrices = [design_matrices] if len(fmri_data) != len(design_matrices): raise ValueError("Incompatible number of fmri runs and " "design matrices were provided") self.fmri_data, self.design_matrices = [], [] self.glms, self.means = [], [] # load the fmri data for fmri_run in fmri_data: if isinstance(fmri_run, basestring): self.fmri_data.append(load(fmri_run)) else: self.fmri_data.append(fmri_run) # set self.affine as the affine of the first image self.affine = get_affine(self.fmri_data[0]) # load the designs for design_matrix in design_matrices: if isinstance(design_matrix, basestring): loaded = np.load(design_matrix) self.design_matrices.append(loaded[loaded.files[0]]) else: self.design_matrices.append(design_matrix) # load the mask if mask == "compute": mask = compute_mask_sessions(fmri_data, m=m, M=M, cc=1, threshold=threshold, opening=0) self.mask = Nifti1Image(mask.astype(np.int8), self.affine) elif mask == None: mask = np.ones(self.fmri_data[0].shape[:3]).astype(np.int8) self.mask = Nifti1Image(mask, self.affine) else: if isinstance(mask, basestring): self.mask = load(mask) else: self.mask = mask
def as_volume_img(obj, copy=True, squeeze=True, world_space=None): """ Convert the input to a VolumeImg. Parameters ---------- obj : filename, pynifti or brifti object, or volume dataset. Input object, in any form that can be converted to a VolumeImg. This includes Nifti filenames, pynifti or brifti objects, or other volumetric dataset objects. copy: boolean, optional If copy is True, the data and affine arrays are copied, elsewhere a view is taken. squeeze: boolean, optional If squeeze is True, the data array is squeeze on for dimensions above 3. world_space: string or None, optional An optional specification of the world space, to override that given by the image. Returns ------- volume_img: VolumeImg object A VolumeImg object containing the data. The metadata is kept as much as possible in the metadata attribute. Notes ------ The world space might not be correctly defined by the input object (in particular, when loading data from disk). In this case, you can correct it manually using the world_space keyword argument. For pynifti objects, the data is transposed. """ if hasattr(obj, 'as_volume_img'): obj = obj.as_volume_img(copy=copy) if copy: obj = obj.__copy__() return obj elif isinstance(obj, basestring): if not os.path.exists(obj): raise ValueError("The file '%s' cannot be found" % obj) obj = nib.load(obj) copy = False if isinstance(obj, SpatialImage): data = obj.get_data() affine = get_affine(obj) header = dict(get_header(obj)) fname = obj.file_map['image'].filename if fname: header['filename'] = fname elif hasattr(obj, 'data') and hasattr(obj, 'sform') and \ hasattr(obj, 'getVolumeExtent'): # Duck-types to a pynifti object data = obj.data.T affine = obj.sform header = obj.header filename = obj.getFilename() if filename != '': header['filename'] = filename else: raise ValueError('Invalid type (%s) passed in: cannot convert %s to ' 'VolumeImg' % (type(obj), obj)) if world_space is None and header.get('sform_code', 0) == 4: world_space = 'mni152' data = np.asanyarray(data) affine = np.asanyarray(affine) if copy: data = data.copy() affine = affine.copy() if squeeze: # Squeeze the dimensions above 3 shape = [ val for index, val in enumerate(data.shape) if val != 1 or index < 3 ] data = np.reshape(data, shape) return VolumeImg(data, affine, world_space, metadata=header)
def surrogate_4d_dataset(shape=(20, 20, 20), mask=None, n_scans=1, n_sess=1, dmtx=None, sk=1.0, noise_level=1.0, signal_level=1.0, out_image_file=None, seed=False): """ Create surrogate (simulated) 3D activation data with spatial noise. Parameters ----------- shape = (20, 20, 20): tuple of integers, the shape of each image mask=None: brifti image instance, referential- and mask- defining image (overrides shape) n_scans: int, optional, number of scans to be simlulated overrided by the design matrix n_sess: int, optional, the number of simulated sessions dmtx: array of shape(n_scans, n_rows), the design matrix sk: float, optionnal Amount of spatial noise smoothness. noise_level: float, optionnal Amplitude of the spatial noise. amplitude=noise_level) signal_level: float, optional, Amplitude of the signal out_image_file: string or list of strings or None, optionnal If not None, the resulting is saved as (set of) nifti file(s) with the given file path(s) seed=False: int, optionnal If seed is not False, the random number generator is initialized at a certain value Returns ------- dataset: a list of n_sess ndarray of shape (shape[0], shape[1], shape[2], n_scans) The surrogate activation map """ if seed: nr = np.random.RandomState([seed]) else: import numpy.random as nr if mask is not None: shape = mask.shape affine = get_affine(mask) mask_data = mask.get_data().astype('bool') else: affine = np.eye(4) mask_data = np.ones(shape).astype('bool') if dmtx is not None: n_scans = dmtx.shape[0] if (out_image_file is not None) and isinstance(out_image_file, string_types): out_image_file = [out_image_file] shape_4d = shape + (n_scans, ) output_images = [] if dmtx is not None: beta = [] for r in range(dmtx.shape[1]): betar = nd.gaussian_filter(nr.randn(*shape), sk) betar /= np.std(betar) beta.append(signal_level * betar) beta = np.rollaxis(np.array(beta), 0, 4) for ns in range(n_sess): data = np.zeros(shape_4d) # make the signal if dmtx is not None: data[mask_data] += np.dot(beta[mask_data], dmtx.T) for s in range(n_scans): # make some noise noise = nr.randn(*shape) # smooth the noise noise = nd.gaussian_filter(noise, sk) noise *= noise_level / np.std(noise) # make the mixture data[:, :, :, s] += noise data[:, :, :, s] += 100 * mask_data wim = Nifti1Image(data, affine) output_images.append(wim) if out_image_file is not None: save(wim, out_image_file[ns]) return output_images
def surrogate_4d_dataset(shape=(20, 20, 20), mask=None, n_scans=1, n_sess=1, dmtx=None, sk=1.0, noise_level=1.0, signal_level=1.0, out_image_file=None, seed=False): """ Create surrogate (simulated) 3D activation data with spatial noise. Parameters ----------- shape = (20, 20, 20): tuple of integers, the shape of each image mask=None: brifti image instance, referential- and mask- defining image (overrides shape) n_scans: int, optional, number of scans to be simlulated overrided by the design matrix n_sess: int, optional, the number of simulated sessions dmtx: array of shape(n_scans, n_rows), the design matrix sk: float, optionnal Amount of spatial noise smoothness. noise_level: float, optionnal Amplitude of the spatial noise. amplitude=noise_level) signal_level: float, optional, Amplitude of the signal out_image_file: string or list of strings or None, optionnal If not None, the resulting is saved as (set of) nifti file(s) with the given file path(s) seed=False: int, optionnal If seed is not False, the random number generator is initialized at a certain value Returns ------- dataset: a list of n_sess ndarray of shape (shape[0], shape[1], shape[2], n_scans) The surrogate activation map """ if seed: nr = np.random.RandomState([seed]) else: import numpy.random as nr if mask is not None: shape = mask.shape affine = get_affine(mask) mask_data = mask.get_data().astype('bool') else: affine = np.eye(4) mask_data = np.ones(shape).astype('bool') if dmtx is not None: n_scans = dmtx.shape[0] if (out_image_file is not None) and isinstance(out_image_file, basestring): out_image_file = [out_image_file] shape_4d = shape + (n_scans,) output_images = [] if dmtx is not None: beta = [] for r in range(dmtx.shape[1]): betar = nd.gaussian_filter(nr.randn(*shape), sk) betar /= np.std(betar) beta.append(signal_level * betar) beta = np.rollaxis(np.array(beta), 0, 4) for ns in range(n_sess): data = np.zeros(shape_4d) # make the signal if dmtx is not None: data[mask_data] += np.dot(beta[mask_data], dmtx.T) for s in range(n_scans): # make some noise noise = nr.randn(*shape) # smooth the noise noise = nd.gaussian_filter(noise, sk) noise *= noise_level / np.std(noise) # make the mixture data[:, :, :, s] += noise data[:, :, :, s] += 100 * mask_data wim = Nifti1Image(data, affine) output_images.append(wim) if out_image_file is not None: save(wim, out_image_file[ns]) return output_images
def as_volume_img(obj, copy=True, squeeze=True, world_space=None): """ Convert the input to a VolumeImg. Parameters ---------- obj : filename, pynifti or brifti object, or volume dataset. Input object, in any form that can be converted to a VolumeImg. This includes Nifti filenames, pynifti or brifti objects, or other volumetric dataset objects. copy: boolean, optional If copy is True, the data and affine arrays are copied, elsewhere a view is taken. squeeze: boolean, optional If squeeze is True, the data array is squeeze on for dimensions above 3. world_space: string or None, optional An optional specification of the world space, to override that given by the image. Returns ------- volume_img: VolumeImg object A VolumeImg object containing the data. The metadata is kept as much as possible in the metadata attribute. Notes ------ The world space might not be correctly defined by the input object (in particular, when loading data from disk). In this case, you can correct it manually using the world_space keyword argument. For pynifti objects, the data is transposed. """ if hasattr(obj, 'as_volume_img'): obj = obj.as_volume_img(copy=copy) if copy: obj = obj.__copy__() return obj elif isinstance(obj, string_types): if not os.path.exists(obj): raise ValueError("The file '%s' cannot be found" % obj) obj = nib.load(obj) copy = False if isinstance(obj, SpatialImage): data = obj.get_data() affine = get_affine(obj) header = dict(get_header(obj)) fname = obj.file_map['image'].filename if fname: header['filename'] = fname elif hasattr(obj, 'data') and hasattr(obj, 'sform') and \ hasattr(obj, 'getVolumeExtent'): # Duck-types to a pynifti object data = obj.data.T affine = obj.sform header = obj.header filename = obj.getFilename() if filename != '': header['filename'] = filename else: raise ValueError('Invalid type (%s) passed in: cannot convert %s to ' 'VolumeImg' % (type(obj), obj)) if world_space is None and header.get('sform_code', 0) == 4: world_space = 'mni152' data = np.asanyarray(data) affine = np.asanyarray(affine) if copy: data = data.copy() affine = affine.copy() if squeeze: # Squeeze the dimensions above 3 shape = [val for index, val in enumerate(data.shape) if val !=1 or index < 3] data = np.reshape(data, shape) return VolumeImg(data, affine, world_space, metadata=header)
def __init__(self, fmri_data, design_matrices, mask='compute', m=0.2, M=0.9, threshold=.5): """Load the data Parameters ---------- fmri_data : Image or str or sequence of Images / str fmri images / paths of the (4D) fmri images design_matrices : arrays or str or sequence of arrays / str design matrix arrays / paths of .npz files mask : str or Image or None, optional string can be 'compute' or a path to an image image is an input (assumed binary) mask image(s), if 'compute', the mask is computed if None, no masking will be applied m, M, threshold: float, optional parameters of the masking procedure. Should be within [0, 1] Notes ----- The only computation done here is mask computation (if required) Examples -------- We need the example data package for this example >>> from nipy.utils import example_data >>> from nipy.modalities.fmri.glm import FMRILinearModel >>> fmri_files = [example_data.get_filename('fiac', 'fiac0', run) ... for run in ['run1.nii.gz', 'run2.nii.gz']] >>> design_files = [example_data.get_filename('fiac', 'fiac0', run) ... for run in ['run1_design.npz', 'run2_design.npz']] >>> mask = example_data.get_filename('fiac', 'fiac0', 'mask.nii.gz') >>> multi_session_model = FMRILinearModel(fmri_files, design_files, mask) >>> multi_session_model.fit() >>> z_image, = multi_session_model.contrast([np.eye(13)[1]] * 2) The number of voxels with p < 0.001 >>> np.sum(z_image.get_data() > 3.09) 671 """ # manipulate the arguments if isinstance(fmri_data, basestring) or hasattr(fmri_data, 'get_data'): fmri_data = [fmri_data] if isinstance(design_matrices, (basestring, np.ndarray)): design_matrices = [design_matrices] if len(fmri_data) != len(design_matrices): raise ValueError('Incompatible number of fmri runs and ' 'design matrices were provided') self.fmri_data, self.design_matrices = [], [] self.glms, self.means = [], [] # load the fmri data for fmri_run in fmri_data: if isinstance(fmri_run, basestring): self.fmri_data.append(load(fmri_run)) else: self.fmri_data.append(fmri_run) # set self.affine as the affine of the first image self.affine = get_affine(self.fmri_data[0]) # load the designs for design_matrix in design_matrices: if isinstance(design_matrix, basestring): loaded = np.load(design_matrix) self.design_matrices.append(loaded[loaded.files[0]]) else: self.design_matrices.append(design_matrix) # load the mask if mask == 'compute': mask = compute_mask_sessions(fmri_data, m=m, M=M, cc=1, threshold=threshold, opening=0) self.mask = Nifti1Image(mask.astype(np.int8), self.affine) elif mask == None: mask = np.ones(self.fmri_data[0].shape[:3]).astype(np.int8) self.mask = Nifti1Image(mask, self.affine) else: if isinstance(mask, basestring): self.mask = load(mask) else: self.mask = mask
def to_image(self, fid=None, roi=False, method="mean", descrip=None): """Generates a label image that represents self. Parameters ---------- fid: str, Feature to be represented. If None, a binary image of the MROI domain will be we created. roi: bool, Whether or not to write the desired feature as a ROI one. (i.e. a ROI feature corresponding to `fid` will be looked upon, and if not found, a representative feature will be computed from the `fid` feature). method: str, If a feature is written as a ROI feature, this keyword tweaks the way the representative feature is computed. descrip: str, Description of the image, to be written in its header. Notes ----- Requires that self.dom is an ddom.NDGridDomain Returns ------- nim : nibabel nifti image Nifti image corresponding to the ROI feature to be written. """ if not isinstance(self.domain, ddom.NDGridDomain): print('self.domain is not an NDGridDomain; nothing was written.') return None if fid is None: # write a binary representation of the domain if no fid provided nim = self.domain.to_image( data=(self.label != -1).astype(np.int32)) if descrip is None: descrip = 'binary representation of MROI' else: data = -np.ones(self.label.size, dtype=np.int32) tmp_image = self.domain.to_image() mask = tmp_image.get_data().copy().astype(bool) if not roi: # write a feature if fid not in self.features: raise ValueError("`%s` feature could not be found" % fid) for i in self.get_id(): data[self.select_id(i, roi=False)] = \ self.get_feature(fid, i) else: # write a roi feature if fid in self.roi_features: # write from existing roi feature for i in self.get_id(): data[self.select_id(i, roi=False)] = \ self.get_roi_feature( fid, i) elif fid in self.features: # write from representative feature summary_feature = self.representative_feature( fid, method=method) for i in self.get_id(): data[self.select_id(i, roi=False)] = \ summary_feature[self.select_id(i)] # MROI object was defined on a masked image: we square it back. wdata = -np.ones(mask.shape, data.dtype) wdata[mask] = data nim = Nifti1Image(wdata, get_affine(tmp_image)) # set description of the image if descrip is not None: get_header(nim)['descrip'] = descrip return nim