def feature_map(self, feature, imPath=None, pw=0.95): """ Given a set of feature values, produce a feature map, assuming that one feature corresponds to one region Parameters ---------- feature, array of shape (self.k) : the information to map imPath=None, string yielding the output image path if not None pw=0.95: volume of the Gaussian ellipsoid associated with the ROIs Returns ------- The image object """ if np.size(feature)!=self.k: raise ValueError, 'Incompatible feature dimension' from nipy.io.imageformats import save, Nifti1Image label = self.map_label(self.generate_coordinates(), pval=pw) label = np.reshape(label, self.shape) values = np.zeros(self.shape) values[label>-1] = feature[label[label>-1].astype(np.int)] wim = Nifti1Image(values, self.affine) wim.get_header()['descrip']='feature image' if imPath!=None: save(wim,imPath) return wim
def make_image(self, path): """ write a int image where the nonzero values are the ROIs Parameters ---------- path: string, the desired image path Note ---- the background values are set to -1 the ROIs values are set as [0..self.k-1] """ if self.shape == None: raise ValueError, "Need self.shape to be defined" data = -np.ones(self.shape, np.int) for k in range(self.k): dk = self.xyz[k].T data[dk[0], dk[1], dk[2]] = k wim = Nifti1Image(data, self.affine) header = wim.get_header() header["descrip"] = "Multiple ROI image" save(wim, path)
def make_image(self, path=None): """ write a int image where the nonzero values are the ROIs Parameters ---------- path: string, optional the desired image path Returns ------- brifti image instance Note ---- the background values are set to -1 the ROIs values are set as [0..self.k-1] """ if self.shape==None: raise ValueError, 'Need self.shape to be defined' data = -np.ones(self.shape,np.int) for k in range(self.k): dk = self.xyz[k].T data[dk[0], dk[1], dk[2]] = k wim = Nifti1Image(data, self.affine) header = wim.get_header() header['descrip'] = "Multiple ROI image" if path!=None: save(wim, path) return wim
def main(): # create the parser parser = argparse.ArgumentParser() # add the arguments parser.add_argument("in_filenames", type=str, nargs="+", help="3D image filenames") parser.add_argument("--out-4d", type=str, help="4D output image name") parser.add_argument( "--check-affines", type=bool, default=True, help="False if you want to ignore differences " "in affines between the 3D images, True if you " "want to raise an error for significant " "differences (default is True)", ) # parse the command line args = parser.parse_args() # get input 3ds filenames = args.in_filenames # affine check check_affines = args.check_affines # get output name out_fname = args.out_4d if out_fname is None: pth, fname = os.path.split(filenames[0]) froot, ext = os.path.splitext(fname) if ext in (".gz", ".bz2"): gz = ext froot, ext = os.path.splitext(froot) else: gz = "" out_fname = pjoin(pth, froot + "_4d" + ext + gz) img4d = do_3d_to_4d(filenames, check_affines=check_affines) nii.save(img4d, out_fname)
def ffx( maskImages, effectImages, varianceImages, resultImage=None): """ Computation of the fixed effecst statistics Parameters ---------- maskImages, string or list of strings the paths of one or several masks when several masks, the half thresholding heuristic is used effectImages, list of strings the paths ofthe effect images varianceImages, list of strings the paths of the associated variance images resultImage=None, string, path of the result images Returns ------- the computed values """ # fixme : check that the images have same referntial # fixme : check that mask_Images is a list if len(effectImages)!=len(varianceImages): raise ValueError, 'Not the correct number of images' tiny = 1.e-15 nsubj = len(effectImages) mask = intersect_masks(maskImages, None, threshold=0.5, cc=True) effects = [] variance = [] for s in range(nsubj): rbeta = load(effectImages[s]) beta = rbeta.get_data()[mask>0] rbeta = load(varianceImages[s]) varbeta = rbeta.get_data()[mask>0] effects.append(beta) variance.append(varbeta) effects = np.array(effects) variance = np.array(variance) effects[np.isnan(effects)] = 0 effects[np.isnan(variance)] = 0 variance[np.isnan(variance)] = tiny variance[variance==0] = tiny t = effects/np.sqrt(variance) t = t.mean(0)*np.sqrt(nsubj) #t = np.sum(effects/variance,0)/np.sum(1.0/np.sqrt(variance),0) nim = load(effectImages[0]) affine = nim.get_affine() tmap = np.zeros(nim.get_shape()) tmap[mask>0] = t tImage = Nifti1Image(tmap, affine) if resultImage!=None: save(tImage, resultImage) return tmap
def save_results(ppm, id_algo, noise): savedir = os.path.join(baseres, subjects[s_idx]) tag = id_algo if noise == 'laplace': tag += '_laplace' for i in range(ntissues): im = Image(ppm[:,:,:,i], affine) fname = id_posterior + '_' + regs[r_idx] + '_' + tag + '_' + str(i) + '.nii' save(Nifti1Image(im), os.path.join(savedir, fname))
def intersect_masks(input_masks, output_filename=None, threshold=0.5, cc=True): """ Given a list of input mask images, generate the output image which is the the threshold-level intersection of the inputs Parameters ---------- input_masks: list of strings or ndarrays paths of the input images nsubj set as len(input_mask_files), or individual masks. output_filename, string: Path of the output image, if None no file is saved. threshold: float within [0, 1], optional gives the level of the intersection. threshold=1 corresponds to keeping the intersection of all masks, whereas threshold=0 is the union of all masks. cc: bool, optional If true, extract the main connected component Returns ------- grp_mask, boolean array of shape the image shape """ grp_mask = None for this_mask in input_masks: if isinstance(this_mask, basestring): # We have a filename this_mask = load(this_mask).get_data() if grp_mask is None: grp_mask = this_mask.copy().astype(np.int) else: grp_mask += this_mask grp_mask = grp_mask>(threshold*len(input_masks)) if np.any(grp_mask>0) and cc: grp_mask = largest_cc(grp_mask) if output_filename is not None: if isinstance(input_masks[0], basestring): nim = load(input_masks[0]) header = nim.get_header() affine = nim.get_affine() else: header = dict() affine = np.eye(4) header['descrip'] = 'mask image' output_image = nifti1.Nifti1Image(grp_mask.astype(np.uint8), affine=affine, header=header, ) save(output_image, output_filename) return grp_mask>0
def to_image(self, path=None): """ Write itself as an image, and returns it """ data = np.zeros(self.shape).astype(np.int8) data[self.ijk[:,0], self.ijk[:,1], self.ijk[:,2]] = 1 nim = Nifti1Image(data, self.affine) nim.get_header()['descrip'] = 'mask image' if path is not None: save(nim, path) return nim
def save(filename, obj): """ Save an nipy image object to a file. """ obj = as_volume_img(obj, copy=False) hdr = imageformats.Nifti1Header() for key, value in obj.metadata.iteritems(): if key in hdr: hdr[key] = value img = imageformats.Nifti1Image(obj.get_data(), obj.affine, header=hdr) imageformats.save(img, filename)
def threshold_z_image(iimage, oimage=None, correction=None, pval=None, smin=0, nn=18, mask_image=None, method=None): """ this function takes a presumably gaussian image threshold and a size threshold and gives as output an image where only the suprathreshold component of size > smin have not been thresholded out This corresponds to a one-sided classical test the null hypothesis can be take to be the standard normal or the empiricall null. Parameters ---------- iimage, string, the path of a presumably z-variate input image oimage=None, string, the path of the output image correction=None, string the correction for multiple comparison method correction can be either None or 'bon' (Bonferroni) or 'fdr' pval=none, float, the desired classical p-value. the default behaviour of pval depends on correction if correction==None, pval = 0.001, else pval = 0.05 smin=0, int, the cluster size threshold mask_image=None, string path of a mask image to determine where thresholding is applies if mask_image==None, the function is implied on where(image) method=None: model of the null distribution: if method==None: standard null if method=='emp': empirical null Returns ------- oimage: the output image """ #?# 1. read the image(s) if mask_image==None: m = None else: mask = load(mask_image) m = mask.get_data() nim = load(iimage) x = nim.get_data() thx = threshold_z_array(x, m, correction, pval, smin, nn, method) ref_dim = nim.get_shape() result = np.zeros(ref_dim) result[m>0] = thx onim = Nifti1Image(result.T, nim.get_affine()) onim.get_header()['descrip']= "thresholded image, threshold= %f,\ cluster size=%d"%(thx, smin) if oimage !=None: save(onim, oimage) return onim
def parcellation_output_with_paths(Pa, mask_images, group_path, indiv_path): """ Function that produces images that describe the spatial structure of the parcellation. It mainly produces label images at the group and subject level Parameters ---------- Pa : Parcellation instance that describes the parcellation mask_images: list of images paths that define the mask coord: array of shape (nvox,3) that contains(approximated) MNI-coordinates of the brain mask voxels considered in the parcellation process group_path, string, path of the group-level parcellation image indiv_path, list of strings, paths of the individual parcellation images fixme ----- the referential-defining information should be part of the Pa instance """ nsubj = Pa.nb_subj mxyz = Pa.ijk # write the template image tlabs = Pa.group_labels rmask = load(mask_images[0]) ref_dim = rmask.get_shape() grid_size = np.prod(ref_dim) affine = rmask.get_affine() Label = np.zeros(ref_dim) Label[Pa.ijk[:,0],Pa.ijk[:,1],Pa.ijk[:,2]]=tlabs+1 wim = Nifti1Image (Label, affine) hdr = wim.get_header() hdr['descrip'] = 'group_level Label image obtained from a \ parcellation procedure' save(wim, group_path) # write subject-related stuff for s in range(nsubj): # write the images labs = Pa.label[:,s] Label = np.zeros(ref_dim).astype(np.int) Label[Pa.ijk[:,0],Pa.ijk[:,1],Pa.ijk[:,2]]=labs+1 wim = Nifti1Image (Label, affine) hdr = wim.get_header() hdr['descrip'] = 'individual Label image obtained \ from a parcellation procedure' save(wim, indiv_path[s])
def threshold_scalar_image(iimage, oimage=None, th=0., smin=0, nn=18, mask_image=None): """ this function takes a 'grey level' threshold and a size threshold and gives as output an image where only the suprathreshold component of size > smin have not been thresholded out Parameters ---------- iimage, string, path of a scalar input image oimage=None, string, path of the scalar output image if None the output image is not written th=0., float, the chosen trheshold smin=0, int, cluster size threshold nn=18, int spatial neighboring system: 6,18 or 26 mask_image=None: a mask image to determine where in image this applies if mask_image==None, the function is implied on where(image) Returns ------- output, image: the output image object Note, the 0 values of iimage are not considered so far """ # FIXME: add a header check here # 1. read the input image if mask_image==None: m = None else: mask = load(mask_image) m = mask.get_data() inim = load(iimage) x = inim.get_data() thx = threshold_array(x, m, th, smin, nn=nn) ref_dim = inim.get_shape() result = np.zeros(ref_dim) result[m>0] = thx onim = Nifti1Image(result.T,inim.get_affine()) onim.get_header()['descrip']= "thresholded image, threshold= %f,\ cluster size=%d"%(th,smin) if oimage !=None: save(onim, oimage) return onim
def main(): # create the parser parser = argparse.ArgumentParser() # add the arguments parser.add_argument('filename', type=str, help='4D image filename') # parse the command line args = parser.parse_args() img = nii.load(args.filename) imgs = nii.four_to_three(img) froot, ext = os.path.splitext(args.filename) if ext in ('.gz', '.bz2'): froot, ext = os.path.splitext(froot) for i, img3d in enumerate(imgs): fname3d = '%s_%04d.nii' % (froot, i) nii.save(img3d, fname3d)
def test_mask_files(): with InTemporaryDirectory(): # Make a 4D file from the anatomical example img = nii.load(anatfile) arr = img.get_data() a2 = np.zeros(arr.shape + (2,)) a2[:, :, :, 0] = arr a2[:, :, :, 1] = arr img = nii.Nifti1Image(a2, np.eye(4)) a_fname = "fourd_anat.nii" nii.save(img, a_fname) # check 4D mask msk1 = nnm.compute_mask_files(a_fname) # and mask from identical list of 3D files msk2 = nnm.compute_mask_files([anatfile, anatfile]) yield assert_array_equal, msk1, msk2
def make_image(self, image_path): """ write a binary nifty image where the nonzero values are the ROI mask Parameters ----------- image_path: string the desired image name """ if self.shape == None: raise ValueError, "self.shape has to be defined" data = np.zeros(self.shape) data[self.discrete] = 1 wim = Nifti1Image(data, self.affine) wim.get_header()["descrip"] = "ROI image" save(wim, image_path)
def ffx_from_stat( maskImages, statImages, resultImage=None): """ Computation of the fixed effects statistics from statistic Parameters ---------- maskImages, string or list of strings the paths of one or several masks when several masks, the half thresholding heuristic is used statImages, list of strings the paths ofthe statitsic images resultImage=None, string, path of the result images Returns ------- the computed values """ # fixme : check that the images have same referntial # fixme : check that mask_Images is a list nsubj = len(statImages) mask = intersect_masks(maskImages, None, threshold=0.5, cc=True) t = [] for s in range(nsubj): rbeta = load(statImages[s]) beta = rbeta.get_data()[mask>0] t.append(beta) t = np.array(t) t[np.isnan(t)] = 0 t = t.mean(0)*np.sqrt(nsubj) nim = load(statImages[0]) affine = nim.get_affine() tmap = np.zeros(nim.get_shape()) tmap[mask>0] = t tImage = Nifti1Image(tmap, affine) if resultImage!=None: save(tImage,resultImage) return tmap
def mask_parcellation(mask_images, nb_parcel, output_image=None): """ Performs the parcellation of a certain mask Parameters ---------- mask_images: list of strings, paths of the mask images that define the common space. nb_parcel: int, number of desired parcels output_image: string, optional path of the output image Returns ------- wim: Nifti1Imagine instance, the resulting parcellation """ from ..mask import intersect_masks # compute the group mask affine = load(mask_images[0]).get_affine() shape = load(mask_images[0]).get_shape() mask = intersect_masks(mask_images, threshold=0)>0 ijk = np.where(mask) ijk = np.array(ijk).T nvox = ijk.shape[0] # Get and cluster coordinates ijk = np.hstack((ijk,np.ones((nvox,1)))) coord = np.dot(ijk, affine.T)[:,:3] cent, tlabs, J = kmeans(coord, nb_parcel) # Write the results label = -np.ones(shape) label[mask]= tlabs wim = Nifti1Image(label, affine) wim.get_header()['descrip'] = 'Label image in %d parcels'%nb_parcel if output_image is not None: save(wim, output_image) return wim
def save_volume(shape, path, affine, mask=None, data=None, descrip=None): """ volume saving utility for masked volumes Parameters ---------- shape, tupe of dimensions of the data path, string, output image path affine, transformation of the grid to a coordinate system mask=None, binary mask used to reduce the volume size data=None data to be put in the volume descrip=None, a string descibing what the image is Fixme ----- Handle the case where data is multi-dimensional """ volume = np.zeros(shape) if mask== None: print "Could not write the image: no mask" return if data == None: print "Could not write the image: no data" return if np.size(data.shape) == 1: volume[mask > 0] = data else: for i in range(data.shape[0]): volume[i][mask[0] > 0] = data[i] wim = Nifti1Image(volume, affine) if descrip !=None: wim.get_header()['descrip']=descrip save(wim, path)
def Parcellation_output(Pa, mask_images, learning_images, coord, nbru, verbose=1,swd = "/tmp"): """ Function that produces images that describe the spatial structure of the parcellation. It mainly produces label images at the group and subject level Parameters ---------- Pa : Parcellation instance that describes the parcellation mask_images: list of images paths that define the mask learning_images: list of float images containing the input data coord: array of shape (nvox,3) that contains(approximated) MNI-coordinates of the brain mask voxels considered in the parcellation process nbru: list of subject ids verbose=1 : verbosity level swd = '/tmp': write directory Results ------- Pa: the updated Parcellation instance """ nsubj = Pa.nb_subj Pa.set_subjects(nbru) # write the template image tlabs = Pa.group_labels LabelImage = os.path.join(swd,"template_parcel.nii") rmask = load(mask_images[0]) ref_dim = rmask.get_shape() affine = rmask.get_affine() Label = np.zeros(ref_dim) Label[Pa.ijk[:,0],Pa.ijk[:,1],Pa.ijk[:,2]]=tlabs+1 wim = Nifti1Image (Label, affine) hdr = wim.get_header() hdr['descrip'] = 'group_level Label image obtained from a \ parcellation procedure' save(wim, LabelImage) # write subject-related stuff Jac = [] if Pa.isfield('jacobian'): Jac = Pa.get_feature('jacobian') Jac = np.reshape(Jac,(Pa.k,nsubj)) for s in range(nsubj): # write the images labs = Pa.label[:,s] LabelImage = os.path.join(swd,"parcel%s.nii" % nbru[s]) JacobImage = os.path.join(swd,"jacob%s.nii" % nbru[s]) Label = np.zeros(ref_dim).astype(np.int) Label[Pa.ijk[:,0],Pa.ijk[:,1],Pa.ijk[:,2]]=labs+1 wim = Nifti1Image (Label, affine) hdr = wim.get_header() hdr['descrip'] = 'individual Label image obtained \ from a parcellation procedure' save(wim, LabelImage) if ((verbose)&(np.size(Jac)>0)): Label = np.zeros(ref_dim) Label[Pa.ijk[:,0],Pa.ijk[:,1],Pa.ijk[:,2]]=Jac[labs,s] wim = Nifti1Image (Label, affine) hdr = wim.get_header() hdr['descrip'] = 'image of the jacobian of the deformation \ associated with the parcellation' save(wim, JacobImage) return Pa
grp_mask = Nifti1Image(mask, load(mask_images[0]).get_affine()) ijk = np.array(np.where(mask)).T nvox = np.sum(mask) # output dir b_smooth = True if b_smooth: print "smoothed data" threshold_path = 'volume_threshold_smooth.con' swd = '/data/home/virgile/virgile_internship/group_analysis/smoothed_FWHM5' else: print "unsmoothed data" threshold_path = 'volume_threshold.con' swd = '/data/home/virgile/virgile_internship/group_analysis/smoothed_FWHM0' save(grp_mask, op.join(swd,'grp_mask.nii')) ################################################################ # Load the effects and variance ################################################################ def load_images(con_images, var_images): """ """ nsubj = len(con_images) beta = [] varbeta = [] tiny = 1.e-15 for s in range(nsubj): rbeta = load(con_images[s]) temp = (rbeta.get_data())[mask]
drift_model='Cosine', hfcut=128, hrf_model=hrf_model, paradigm=paradigm, add_regs=motion, add_reg_names=add_reg_names) ####################################### # Get the FMRI data ####################################### fmri_data = surrogate_4d_dataset(shape=shape, n_scans=n_scans)[0] # if you want to save it as an image data_file = op.join(swd, 'fmri_data.nii') save(fmri_data, data_file) ######################################## # Perform a GLM analysis ######################################## # GLM fit Y = fmri_data.get_data() model = "ar1" method = "kalman" glm = GLM.glm() mp.pcolor(X) mp.show() glm.fit(Y.T, X, method=method, model=model) #explained = np.dot(X,glm.beta.reshape(X.shape[1],-1)).reshape(Y.T.shape).T #residuals = Y - explained
######################################## paradigm = dm.EventRelatedParadigm(conditions, onsets) X, names = dm.dmtx_light(frametimes, drift_model='Cosine', hfcut=128, hrf_model=hrf_model, paradigm=paradigm, add_regs=motion, add_reg_names=add_reg_names) ####################################### # Get the FMRI data ####################################### fmri_data = surrogate_4d_dataset(shape=shape, n_scans=n_scans)[0] # if you want to save it as an image data_file = op.join(swd,'fmri_data.nii') save(fmri_data, data_file) ######################################## # Perform a GLM analysis ######################################## # GLM fit Y = fmri_data.get_data() model = "ar1" method = "kalman" glm = GLM.glm() mp.pcolor(X) mp.show() glm.fit(Y.T, X, method=method, model=model) #explained = np.dot(X,glm.beta.reshape(X.shape[1],-1)).reshape(Y.T.shape).T #residuals = Y - explained
def make_surrogate_array(nbsubj=10, dimx=30, dimy=30, sk=1.0, noise_level=1.0, pos=pos, ampli=ampli, spatial_jitter=1.0, signal_jitter=1.0, width=5.0, out_text_file=None, out_image_file=None, verbose=False, seed=False): """ Create surrogate (simulated) 2D activation data with spatial noise. Parameters ----------- nbsubj: integer, optionnal The number of subjects, ie the number of different maps generated. dimx: integer, optionnal The x size of the array returned. dimy: integer The y size of the array returned. sk: float, optionnal Amount of spatial noise smoothness. noise_level: float, optionnal Amplitude of the spatial noise. amplitude=noise_level) pos: 2D ndarray of integers, optionnal x, y positions of the various simulated activations. ampli: 1D ndarray of floats, optionnal Respective amplitude of each activation spatial_jitter: float, optionnal Random spatial jitter added to the position of each activation, in pixel. signal_jitter: float, optionnal Random amplitude fluctuation for each activation, added to the amplitude specified by ampli width: float or ndarray, optionnal Width of the activations out_text_file: string or None, optionnal If not None, the resulting array is saved as a text file with the given file name out_image_file: string or None, optionnal If not None, the resulting is saved as a nifti file with the given file name. verbose: boolean, optionnal If verbose is true, the data for the last subject is plotted as a 2D image. seed=False: int, optionnal If seed is not False, the random number generator is initialized at a certain value Returns ------- dataset: 3D ndarray The surrogate activation map, with dimensions (nbsubj, dimx, dimy) """ if seed: nr = np.random.RandomState([seed]) else: import numpy.random as nr shape = (dimx, dimy) ij = np.transpose(np.where(np.ones(shape))) dataset = [] for s in range(nbsubj): # make the signal data = np.zeros(shape) lpos = pos + spatial_jitter*nr.randn(1, 2) lampli = ampli + signal_jitter*nr.randn(np.size(ampli)) for k in range(np.size(lampli)): data = np.maximum(data, _cone(shape, ij, lpos[k], lampli[k], width)) # make some noise noise = nr.randn(dimx,dimy) # smooth the noise noise = nd.gaussian_filter(noise, sk) noise = np.reshape(noise, (-1, 1)) noise *= noise_level/np.std(noise) #make the mixture data += np.reshape(noise, shape) dataset.append(data) if verbose: import matplotlib.pylab as mp mp.figure() mp.imshow(data, interpolation='nearest') mp.colorbar() dataset = np.array(dataset) if out_text_file is not None: dataset.tofile(out_text_file) if out_image_file is not None: from nipy.io.imageformats import save, Nifti1Image save(Nifti1Image( dataset, np.eye(4)), out_image_file) return dataset
R.set_source_fov(fixed_npoints=64**3) # Make Gaussian spline transform instance spacing = 16 slices = [slice(0,s.stop,s.step*spacing) for s in R._slices] cp = np.mgrid[slices] cp = np.rollaxis(cp, 0, 4) # Start with an affine registration A0 = Affine() A = R.optimize(A0) ###A = Affine() # Save affinely transformed target Jt = J.transform(A, reference=I) save(asNifti1Image(Jt), 'affine_anubis_to_ammon.nii') # Then add control points... T0 = SplineTransform(I, cp, sigma=20., grid_coords=True, affine=A) """ # Test 1 s = R.eval(T0) sa = R.eval(T0.affine) assert_almost_equal(s, sa) # Test 2 T = SplineTransform(I, cp, sigma=5., grid_coords=True, affine=A) T.param += 1. s0 = R.eval(T0) s = R.eval(T)
label = -np.ones(F.V) nroi = hroi.NROI_from_field(F, affine, shape, xyz, 0, threshold, smin) bmap = -np.zeros(F.V) if nroi!=None: idx = nroi.discrete_features['index'] for k in range(nroi.k): label[idx[k]] = k # saving the blob image,i. e. a label image wlabel = -2*np.ones(shape) wlabel[data!=0] = label blobPath = os.path.join(swd,"blob.nii") wim = Nifti1Image(wlabel, affine) wim.get_header()['descrip'] = 'blob image extracted from %s'%InputImage save(wim, blobPath) # --- 2.b take blob labelled "1" as an ROI roi = DiscreteROI( affine=affine, shape=shape) roi.from_labelled_image(blobPath, 1) roiPath2 = os.path.join(swd, "roi_blob_1.nii") roi.make_image(roiPath2) # --- 2.c take the blob closest to 'position as an ROI' roiPath3 = os.path.join(swd, "blob_closest_to_%d_%d_%d.nii")%\ (position[0], position[1], position[2]) roi.from_position_and_image(blobPath, np.array(position)) roi.make_image(roiPath3) # --- 2.d make a set of ROIs from all the blobs mroi = MultipleROI( affine=affine, shape=shape)
def Parcellation_based_analysis(Pa, test_images, numbeta, swd="/tmp", DMtx=None, verbose=1, method_id=0): """ This function computes parcel averages and RFX at the parcel-level Parameters ---------- Pa Parcellation instance that is updated in this function test_images: double list of paths of functional images used as input to for inference. Normally these are contrast images. double list is [number of subjects [number of contrasts]] numbeta: list of int of the associated ids swd='/tmp': write directory DMtx=None: array od shape (nsubj,ncon) a design matrix for second-level analyses (not implemented yet) verbose=1: verbosity level method_id = 0: an id of the method used. This is useful to compare the outcome of different Parcellation+RFX procedures Results ------- Pa: the updated Parcellation instance """ nsubj = Pa.nb_subj mxyz = Pa.ijk.T mask = Pa.label>-1 nbeta = len(numbeta) # 1. read the test data # fixme: Check that everybody is in the same referential Test = [] for s in range(nsubj): beta = [] lxyz = mxyz[:,mask[:,s]] lxyz = np.array(lxyz) for b in range(nbeta): # the raw contrast images rbeta = load(test_images[s][b]) temp = rbeta.get_data() temp = temp[lxyz[0,:],lxyz[1,:],lxyz[2,:]] temp = np.reshape(temp, np.size(temp)) beta.append(temp) temp[np.isnan(temp)]=0 ## beta = np.array(beta) Test.append(beta.T) # 2. compute the parcel-based stuff # and make inference inference (RFX,...) prfx = np.zeros((Pa.k,nbeta)) vinter = np.zeros(nbeta) for b in range(nbeta): unitest = [np.reshape(Test[s][:,b],(np.size(Test[s][:,b]),1)) \ for s in range(nsubj)] cname = 'contrast_%04d'%(numbeta[b]) Pa.make_feature(unitest, cname) prfx[:,b] = np.reshape(Pa.PRFX(cname,1),Pa.k) vinter[b] = Pa.variance_inter(cname) vintra = Pa.variance_intra(Test) if verbose: print 'average intra-parcel variance', vintra print 'average intersubject variance', vinter.mean() # 3. Write the stuff # write RFX images ref_dim = rbeta.get_shape() affine = rbeta.get_affine() tlabs = Pa.group_labels # write the prfx images for b in range(len(numbeta)): RfxImage = os.path.join(swd,"prfx_%s_%d.nii" % (numbeta[b],method_id)) if ((verbose)&(np.size(prfx)>0)): rfx_map = np.zeros(ref_dim) rfx_map[Pa.ijk[:,0],Pa.ijk[:,1],Pa.ijk[:,2]] = prfx[tlabs,b] wim = Nifti1Image (rfx_map, affine) hdr = wim.get_header() hdr['descrip'] = 'parcel-based eandom effects image (in z-variate)' save(wim, RfxImage) return Pa
######################################### # Estimate the contrasts ######################################### print 'Computing contrasts...' for index, contrast_id in enumerate(contrasts): print ' Contrast % 2i out of %i: %s' % (index+1, len(contrasts), contrast_id) lcontrast = my_glm.contrast(contrasts[contrast_id]) # contrast_path = op.join(swd, '%s_z_map.nii'% contrast_id) write_array = mask_array.astype(np.float) write_array[mask_array] = lcontrast.zscore() contrast_image = Nifti1Image(write_array, fmri_image.get_affine() ) save(contrast_image, contrast_path) affine = fmri_image.get_affine() vmax = max(-write_array.min(), write_array.max()) plot_map(write_array, affine, cmap=cm.cold_hot, vmin=-vmax, vmax=vmax, anat=None, figure=10, threshold=2.5) pylab.savefig(op.join(swd, '%s_z_map.png' % contrast_id)) pylab.clf()
def one_subj_parcellation(MaskImage, betas, nbparcel, nn=6, method='ward', write_dir=None, mu=10., verbose=0, fullpath=None): """ Parcellation of a one-subject dataset Return: a tuple (Parcellation instance, parcellation labels) Parameters ---------- MaskImage: path to the mask-defining_image of the subject betas: list of paths to activation images from the subject nbparcel, int : number fo desired parcels nn=6: number of nearest neighbors to define the image topology (6, 18 or 26) method='ward': clustering method used, to be chosen among 'ward', 'gkm', 'ward_and-gkm' 'ward': Ward's clustering algorithm 'gkm': Geodesic k-means algorithm, random initialization 'gkm_and_ward': idem, initialized by Ward's clustering write_dir=None: write directory. If fullpath is None too, then no file output. mu = 10., float: the relative weight of anatomical information verbose=0: verbosity mode fullpath=None, string, path of the output image If write_dir and fullpath are None then no file output. If only fullpath is None then it is the write dir + a name depending on the method. Note ---- Ward's method takes time (about 6 minutes for a 60K voxels dataset) Geodesic k-means is 'quick and dirty' Ward's + GKM is expensive but quite good To reduce CPU time, rather use nn=6 (especially with Ward) """ import nipy.neurospin.graph as fg import nipy.neurospin.graph.field as ff if method not in ['ward','gkm','ward_and_gkm','kmeans']: raise ValueError, 'unknown method' if nn not in [6,18,26]: raise ValueError, 'nn should be 6,18 or 26' nbeta = len(betas) # step 1: load the data ---------------------------- #1.1 the mask image nim = load(MaskImage) ref_dim = nim.get_shape() affine = nim.get_affine() mask = nim.get_data() xyz = np.array(np.where(mask>0)).T nvox = xyz.shape[0] if method is not 'kmeans': # 1.2 get the main cc of the graph # to remove the small connected components g = fg.WeightedGraph(nvox) g.from_3d_grid(xyz.astype(np.int),nn) aux = np.zeros(g.V).astype('bool') imc = g.main_cc() aux[imc]= True if np.sum(aux)==0: raise ValueError, "empty mask. Cannot proceed" g = g.subgraph(aux) lmask = np.zeros(ref_dim) lmask[xyz[:,0],xyz[:,1],xyz[:,2]]=aux xyz = xyz[aux,:] nvox = xyz.shape[0] # 1.3 from vox to mm xyz2 = np.hstack((xyz,np.ones((nvox,1)))) coord = np.dot(xyz2, affine.T)[:,:3] # 1.4 read the functional data beta = [] for b in range(nbeta): rbeta = load(betas[b]) lbeta = rbeta.get_data() lbeta = lbeta[lmask>0] beta.append(lbeta) beta = np.array(beta).T #step 2: parcel the data --------------------------- feature = np.hstack((beta, mu*coord/np.std(coord))) if method is not 'kmeans': g = ff.Field(nvox, g.edges, g.weights, feature) if method=='kmeans': cent, u, J = kmeans(feature, nbparcel) if method=='ward': u, J0 = g.ward(nbparcel) if method=='gkm': seeds = np.argsort(np.random.rand(g.V))[:nbparcel] seeds, u, J1 = g.geodesic_kmeans(seeds) if method=='ward_and_gkm': w,J0 = g.ward(nbparcel) seeds, u, J1 = g.geodesic_kmeans(label=w) lpa = Parcellation(nbparcel, xyz, np.reshape(u,(nvox,1))) if verbose: pi = np.reshape(lpa.population(), nbparcel) vi = np.sum(lpa.var_feature_intra([beta])[0], 1) vf = np.dot(pi,vi)/nvox va = np.dot(pi,np.sum(lpa.var_feature_intra([coord])[0],1))/nvox print nbparcel, "functional variance", vf, "anatomical variance",va # step3: write the resulting label image Label = -np.ones(ref_dim,'int16') Label[lmask>0] = u if fullpath is not None: LabelImage = fullpath elif write_dir is not None: if method=='kmeans': LabelImage = os.path.join(write_dir,"parcel_kmeans.nii") if method=='ward': LabelImage = os.path.join(write_dir,"parcel_wards.nii") elif method=='gkm': LabelImage = os.path.join(write_dir,"parcel_gkmeans.nii") elif method=='ward_and_gkm': LabelImage = os.path.join(write_dir,"parcel_wgkmeans.nii") else: LabelImage = None if LabelImage is not None: wim = Nifti1Image(Label, affine) hdr = wim.get_header() hdr['descrip'] = 'Intra-subject parcellation image' save(wim, LabelImage) print "Wrote the parcellation images as %s" %LabelImage return lpa, Label
""" print __doc__ import numpy as np import os from nipy.io.imageformats import load, save, Nifti1Image from nipy.neurospin.graph.field import Field import get_data_light import tempfile data_dir = get_data_light.get_it() # paths swd = tempfile.mkdtemp() input_image = os.path.join(data_dir, 'spmT_0029.nii.gz') mask_image = os.path.join(data_dir, 'mask.nii.gz') mask = load(mask_image).get_data()>0 ijk = np.array(np.where(mask)).T nvox = ijk.shape[0] data = load(input_image).get_data()[mask] image_field = Field(nvox) image_field.from_3d_grid(ijk, k=6) image_field.set_field(data) u = image_field.ward(100) label_image = os.path.join(swd, 'label.nii') wdata = mask - 1 wdata[mask] = u save(Nifti1Image(wdata, load(mask_image).get_affine()), label_image) print "Label image written in %s" % label_image
### Extract blobs maps as data arrays blobs_labels = -np.zeros(domain.size) blobs_means = -np.zeros(domain.size) if nroi != None: nroi.make_feature('activation', glm_data.ravel()) bfm = nroi.representative_feature('activation') for k in range(nroi.k): blobs_labels[nroi.label == k] = k blobs_means[nroi.label == k] = bfm[k] # saving the blobs image, i.e. a label image label_data = np.zeros(mask_data.shape) label_data[mask_data != 0] = (blobs_labels + 1) label_image = Nifti1Image(label_data, mask.get_affine()) label_image.get_header()['descrip'] = 'blob image extracted from %s' \ %glm_data_path save(label_image, os.path.join(swd,"blob.nii")) print "Wrote the blobs label image in %s" \ %os.path.join(swd, "blob.nii") # saving the image of the average-signal-per-blob avg_data = np.zeros(mask_data.shape) avg_data[mask_data != 0] = blobs_means avg_image = Nifti1Image(avg_data, mask.get_affine()) avg_image.get_header()['descrip'] = 'blob average signal extracted from %s' \ %glm_data_path save(avg_image, os.path.join(swd,"bmap.nii")) print "Wrote the blobs average signal image in %s" \ %os.path.join(swd, "bmap.nii") #------------------------------------------------------------ ### Extract end-blobs (or leaves) maps as data arrays leaves_labels = -np.zeros(domain.size)
def compute_mask_files(input_filename, output_filename=None, return_mean=False, m=0.2, M=0.9, cc=1): """ Compute a mask file from fMRI nifti file(s) Compute and write the mask of an image based on the grey level This is based on an heuristic proposed by T.Nichols: find the least dense point of the histogram, between fractions m and M of the total image histogram. In case of failure, it is usually advisable to increase m. Parameters ---------- input_filename : string nifti filename (4D) or list of filenames (3D). output_filename : string or None, optional path to save the output nifti image (if not None). return_mean : boolean, optional if True, and output_filename is None, return the mean image also, as a 3D array (2nd return argument). m : float, optional lower fraction of the histogram to be discarded. M: float, optional upper fraction of the histogram to be discarded. cc: boolean, optional if cc is True, only the largest connect component is kept. Returns ------- mask : 3D boolean array The brain mask mean_image : 3d ndarray, optional The main of all the images used to estimate the mask. Only provided if `return_mean` is True. """ if isinstance(input_filename, basestring): # One single filename nim, vol_arr = get_unscaled_img(input_filename) header = nim.get_header() affine = nim.get_affine() if vol_arr.ndim == 4: if isinstance(vol_arr, np.memmap): # Get rid of memmapping: it is faster. mean_volume = np.array(vol_arr, copy=True).mean(axis=-1) else: mean_volume = vol_arr.mean(axis=-1) # Make a copy, to avoid holding a reference on the full array, # and thus polluting the memory. first_volume = vol_arr[:,:,:,0].copy() elif vol_arr.ndim == 3: mean_volume = first_volume = vol_arr else: raise ValueError('Need 4D file for mask') del vol_arr else: # List of filenames if len(input_filename) == 0: raise ValueError('input_filename should be a non-empty ' 'list of file names') # We have several images, we do mean on the fly, # to avoid loading all the data in the memory # We do not use the unscaled data here?: # if the scalefactor is being used to record real # differences in intensity over the run this would break for index, filename in enumerate(input_filename): nim = load(filename) if index == 0: first_volume = nim.get_data().squeeze() mean_volume = first_volume.copy().astype(np.float32) header = nim.get_header() affine = nim.get_affine() else: mean_volume += nim.get_data().squeeze() mean_volume /= float(len(input_filename)) del nim if np.isnan(mean_volume).any(): tmp = mean_volume.copy() tmp[np.isnan(tmp)] = 0 mean_volume = tmp mask = compute_mask(mean_volume, first_volume, m, M, cc) if output_filename is not None: header['descrip'] = 'mask' output_image = nifti1.Nifti1Image(mask.astype(np.uint8), affine=affine, header=header) save(output_image, output_filename) if not return_mean: return mask else: return mask, mean_volume