def _optim_hparcel(feature, domain, graphs, nb_parcel, lamb=1., dmax=10., niter=5, initial_mask=None, chunksize=1.e5, verbose=0): """ Core function of the heirrachical parcellation procedure. Parameters ---------- feature: list of subject-related feature arrays Pa : parcellation instance that is updated graphs: graph that represents the topology of the parcellation anat_coord: array of shape (nvox,3) space defining set of coordinates nb_parcel: int the number of desrired parcels lamb=1.0: parameter to weight position and feature impact on the algorithm dmax = 10: locality parameter (in the space of anat_coord) to limit surch volume (CPU save) chunksize = int, optional niter = 5: number of iterations in the algorithm verbose=0: verbosity level Returns ------- U: list of arrays of length nsubj subject-dependent parcellations Proto_anat: array of shape (nvox) labelling of the common space (template parcellation) """ nb_subj = len(feature) # a1. perform a rough clustering of the data to make prototype indiv_coord = np.array([domain.coord[initial_mask[:, s] > - 1] for s in range(nb_subj)]) reduced_anat, reduced_feature = _reduce_and_concatenate( indiv_coord, feature, chunksize) _, labs, _ = kmeans(reduced_feature, nb_parcel, Labels=None, maxiter=10) proto_anat = [np.mean(reduced_anat[labs == k], 0) for k in range(nb_parcel)] proto_anat = np.array(proto_anat) proto = [np.mean(reduced_feature[labs == k], 0) for k in range(nb_parcel)] proto = np.array(proto) # a2. topological model of the parcellation # group-level part spatial_proto = Field(nb_parcel) spatial_proto.set_field(proto_anat) spatial_proto.voronoi_diagram(proto_anat, domain.coord) spatial_proto.set_gaussian(proto_anat) spatial_proto.normalize() for git in range(niter): LP = [] LPA = [] U = [] Energy = 0 for s in range(nb_subj): # b.subject-specific instances of the model # b.0 subject-specific information Fs = feature[s] lac = indiv_coord[s] target = proto_anat.copy() lseeds = np.zeros(nb_parcel, np.int) aux = np.argsort(rand(nb_parcel)) toto = np.zeros(lac.shape[0]) for j in range(nb_parcel): # b.1 speed-up :only take a small ball i = aux[j] dx = lac - target[i] iz = np.nonzero(np.sum(dx ** 2, 1) < dmax ** 2) iz = np.reshape(iz, np.size(iz)) if np.size(iz) == 0: iz = np.array([np.argmin(np.sum(dx ** 2, 1))]) # b.2: anatomical constraints lanat = np.reshape(lac[iz], (np.size(iz), domain.coord.shape[1])) pot = np.zeros(np.size(iz)) JM, rmin = _exclusion_map(i, spatial_proto, target, lanat) pot[JM < 0] = np.inf pot[JM >= 0] = - JM[JM >= 0] # b.3: add feature discrepancy df = Fs[iz] - proto[i] df = np.reshape(df, (np.size(iz), proto.shape[1])) pot += lamb * np.sum(df ** 2, 1) # b.4: solution if np.sum(np.isinf(pot)) == np.size(pot): pot = np.sum(dx[iz] ** 2, 1) sol = iz[np.argmin(pot)] target[i] = lac[sol] lseeds[i] = sol toto[sol] = 1 if verbose > 1: jm = _field_gradient_jac(spatial_proto, target) print jm.min(), jm.max(), np.sum(toto > 0) # c.subject-specific parcellation g = graphs[s] f = Field(g.V, g.edges, g.weights, Fs) U.append(f.constrained_voronoi(lseeds)) Energy += np.sum((Fs - proto[U[-1]]) ** 2) / \ np.sum(initial_mask[:, s] > - 1) # recompute the prototypes # (average in subject s) lproto = [np.mean(Fs[U[-1] == k], 0) for k in range(nb_parcel)] lproto = np.array(lproto) lproto_anat = np.array([np.mean(lac[U[-1] == k], 0) for k in range(nb_parcel)]) LP.append(lproto) LPA.append(lproto_anat) # recompute the prototypes across subjects proto_mem = proto.copy() proto = np.mean(np.array(LP), 0) proto_anat = np.mean(np.array(LPA), 0) displ = np.sqrt(np.sum((proto_mem - proto) ** 2, 1).max()) if verbose: print 'energy', Energy, 'displacement', displ # recompute the topological model spatial_proto.set_field(proto_anat) spatial_proto.voronoi_diagram(proto_anat, domain.coord) spatial_proto.set_gaussian(proto_anat) spatial_proto.normalize() if displ < 1.e-4 * dmax: break return U, proto_anat
# Local import from get_data_light import DATA_DIR, get_second_level_dataset # paths input_image = path.join(DATA_DIR, 'spmT_0029.nii.gz') mask_image = path.join(DATA_DIR, 'mask.nii.gz') if (not path.exists(mask_image)) or (not path.exists(input_image)): get_second_level_dataset() # write directory write_dir = path.join(getcwd(), 'results') if not path.exists(write_dir): mkdir(write_dir) # read the data 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) # write the results label_image = path.join(write_dir, '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)
from scipy.ndimage import gaussian_filter try: import matplotlib.pyplot as plt except ImportError: raise RuntimeError("This script needs the matplotlib library") from nipy.algorithms.graph.field import Field dx = 50 dy = 50 dz = 1 nbseeds = 10 data = gaussian_filter(np.random.randn(dx, dy), 2) F = Field(dx * dy * dz) xyz = np.reshape(np.indices((dx, dy, dz)), (3, dx * dy * dz)).T.astype(np.int) F.from_3d_grid(xyz, 6) F.set_field(data) seeds = np.argsort(nr.rand(F.V))[:nbseeds] seeds, label, J0 = F.geodesic_kmeans(seeds) wlabel, J1 = F.ward(nbseeds) seeds, label, J2 = F.geodesic_kmeans(seeds, label=wlabel.copy(), eps=1.e-7) print('Inertia values for the 3 algorithms: ') print('Geodesic k-means: ', J0, 'Wards: ', J1, 'Wards + gkm: ', J2) plt.figure(figsize=(8, 4)) plt.subplot(1, 3, 1) plt.imshow(np.reshape(data, (dx, dy)), interpolation='nearest')
def _optim_hparcel(feature, domain, graphs, nb_parcel, lamb=1., dmax=10., niter=5, initial_mask=None, chunksize=1.e5, verbose=0): """ Core function of the heirrachical parcellation procedure. Parameters ---------- feature: list of subject-related feature arrays Pa : parcellation instance that is updated graphs: graph that represents the topology of the parcellation anat_coord: array of shape (nvox,3) space defining set of coordinates nb_parcel: int the number of desrired parcels lamb=1.0: parameter to weight position and feature impact on the algorithm dmax = 10: locality parameter (in the space of anat_coord) to limit surch volume (CPU save) chunksize = int, optional niter = 5: number of iterations in the algorithm verbose=0: verbosity level Returns ------- U: list of arrays of length nsubj subject-dependent parcellations Proto_anat: array of shape (nvox) labelling of the common space (template parcellation) """ nb_subj = len(feature) # a1. perform a rough clustering of the data to make prototype indiv_coord = np.array( [domain.coord[initial_mask[:, s] > -1] for s in range(nb_subj)]) reduced_anat, reduced_feature = _reduce_and_concatenate( indiv_coord, feature, chunksize) _, labs, _ = kmeans(reduced_feature, nb_parcel, Labels=None, maxiter=10) proto_anat = [ np.mean(reduced_anat[labs == k], 0) for k in range(nb_parcel) ] proto_anat = np.array(proto_anat) proto = [np.mean(reduced_feature[labs == k], 0) for k in range(nb_parcel)] proto = np.array(proto) # a2. topological model of the parcellation # group-level part spatial_proto = Field(nb_parcel) spatial_proto.set_field(proto_anat) spatial_proto.voronoi_diagram(proto_anat, domain.coord) spatial_proto.set_gaussian(proto_anat) spatial_proto.normalize() for git in range(niter): LP = [] LPA = [] U = [] Energy = 0 for s in range(nb_subj): # b.subject-specific instances of the model # b.0 subject-specific information Fs = feature[s] lac = indiv_coord[s] target = proto_anat.copy() lseeds = np.zeros(nb_parcel, np.int) aux = np.argsort(rand(nb_parcel)) toto = np.zeros(lac.shape[0]) for j in range(nb_parcel): # b.1 speed-up :only take a small ball i = aux[j] dx = lac - target[i] iz = np.nonzero(np.sum(dx**2, 1) < dmax**2) iz = np.reshape(iz, np.size(iz)) if np.size(iz) == 0: iz = np.array([np.argmin(np.sum(dx**2, 1))]) # b.2: anatomical constraints lanat = np.reshape(lac[iz], (np.size(iz), domain.coord.shape[1])) pot = np.zeros(np.size(iz)) JM, rmin = _exclusion_map(i, spatial_proto, target, lanat) pot[JM < 0] = np.inf pot[JM >= 0] = -JM[JM >= 0] # b.3: add feature discrepancy df = Fs[iz] - proto[i] df = np.reshape(df, (np.size(iz), proto.shape[1])) pot += lamb * np.sum(df**2, 1) # b.4: solution if np.sum(np.isinf(pot)) == np.size(pot): pot = np.sum(dx[iz]**2, 1) sol = iz[np.argmin(pot)] target[i] = lac[sol] lseeds[i] = sol toto[sol] = 1 if verbose > 1: jm = _field_gradient_jac(spatial_proto, target) print jm.min(), jm.max(), np.sum(toto > 0) # c.subject-specific parcellation g = graphs[s] f = Field(g.V, g.edges, g.weights, Fs) U.append(f.constrained_voronoi(lseeds)) Energy += np.sum((Fs - proto[U[-1]]) ** 2) / \ np.sum(initial_mask[:, s] > - 1) # recompute the prototypes # (average in subject s) lproto = [np.mean(Fs[U[-1] == k], 0) for k in range(nb_parcel)] lproto = np.array(lproto) lproto_anat = np.array( [np.mean(lac[U[-1] == k], 0) for k in range(nb_parcel)]) LP.append(lproto) LPA.append(lproto_anat) # recompute the prototypes across subjects proto_mem = proto.copy() proto = np.mean(np.array(LP), 0) proto_anat = np.mean(np.array(LPA), 0) displ = np.sqrt(np.sum((proto_mem - proto)**2, 1).max()) if verbose: print 'energy', Energy, 'displacement', displ # recompute the topological model spatial_proto.set_field(proto_anat) spatial_proto.voronoi_diagram(proto_anat, domain.coord) spatial_proto.set_gaussian(proto_anat) spatial_proto.normalize() if displ < 1.e-4 * dmax: break return U, proto_anat
[20, 20], [30, 20]]) ampli = np.array([3, 4, 4]) nbvox = dimx * dimy x = simul.surrogate_2d_dataset(nbsubj=1, dimx=dimx, dimy=dimy, pos=pos, ampli=ampli, width=10.0) x = np.reshape(x, (dimx, dimy, 1)) beta = np.reshape(x, (nbvox, 1)) xyz = np.array(np.where(x)) nbvox = np.size(xyz, 1) th = 2.36 # compute the field structure and perform the watershed Fbeta = Field(nbvox) Fbeta.from_3d_grid(xyz.T.astype(np.int), 18) Fbeta.set_field(beta) idx, label = Fbeta.custom_watershed(0, th) #compute the region-based signal average bfm = np.array([np.mean(beta[label == k]) for k in range(label.max() + 1)]) bmap = np.zeros(nbvox) if label.max() > - 1: bmap[label > - 1] = bfm[label[label > - 1]] label = np.reshape(label, (dimx, dimy)) bmap = np.reshape(bmap, (dimx, dimy)) ############################################################################### # plot the input image
from scipy.ndimage import gaussian_filter try: import matplotlib.pyplot as plt except ImportError: raise RuntimeError("This script needs the matplotlib library") from nipy.algorithms.graph.field import Field dx = 50 dy = 50 dz = 1 nbseeds = 10 data = gaussian_filter(np.random.randn(dx, dy), 2) F = Field(dx * dy * dz) xyz = np.reshape(np.indices((dx, dy, dz)), (3, dx * dy * dz)).T.astype(np.int) F.from_3d_grid(xyz, 6) F.set_field(data) seeds = np.argsort(nr.rand(F.V))[:nbseeds] seeds, label, J0 = F.geodesic_kmeans(seeds) wlabel, J1 = F.ward(nbseeds) seeds, label, J2 = F.geodesic_kmeans(seeds, label=wlabel.copy(), eps=1.0e-7) print "Inertia values for the 3 algorithms: " print "Geodesic k-means: ", J0, "Wards: ", J1, "Wards + gkm: ", J2 plt.figure(figsize=(8, 4)) plt.subplot(1, 3, 1) plt.imshow(np.reshape(data, (dx, dy)), interpolation="nearest")
from nipy.algorithms.graph.field import Field # Local import from get_data_light import DATA_DIR, get_second_level_dataset # paths swd = os.getcwd() input_image = os.path.join(DATA_DIR, 'spmT_0029.nii.gz') mask_image = os.path.join(DATA_DIR, 'mask.nii.gz') if (not os.path.exists(mask_image)) or (not os.path.exists(input_image)): get_second_level_dataset() # read the data 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) # write the results 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