def test_matrix(): m = ci.Cifti2Matrix() assert_raises(TypeError, m, setattr, 'metadata', ci.Cifti2Parcel()) assert_raises(TypeError, m.__setitem__, 0, ci.Cifti2Parcel()) assert_raises(TypeError, m.insert, 0, ci.Cifti2Parcel()) mim_none = ci.Cifti2MatrixIndicesMap(None, 'CIFTI_INDEX_TYPE_LABELS') mim_0 = ci.Cifti2MatrixIndicesMap(0, 'CIFTI_INDEX_TYPE_LABELS') mim_1 = ci.Cifti2MatrixIndicesMap(1, 'CIFTI_INDEX_TYPE_LABELS') mim_01 = ci.Cifti2MatrixIndicesMap([0, 1], 'CIFTI_INDEX_TYPE_LABELS') assert_raises(ci.Cifti2HeaderError, m.insert, 0, mim_none) assert_equal(m.mapped_indices, []) h = ci.Cifti2Header(matrix=m) assert_equal(m.mapped_indices, []) m.insert(0, mim_0) assert_equal(h.mapped_indices, [0]) assert_equal(h.number_of_mapped_indices, 1) assert_raises(ci.Cifti2HeaderError, m.insert, 0, mim_0) assert_raises(ci.Cifti2HeaderError, m.insert, 0, mim_01) m[0] = mim_1 assert_equal(list(m.mapped_indices), [1]) m.insert(0, mim_0) assert_equal(list(sorted(m.mapped_indices)), [0, 1]) assert_equal(h.number_of_mapped_indices, 2) assert_equal(h.get_index_map(0), mim_0) assert_equal(h.get_index_map(1), mim_1) assert_raises(ci.Cifti2HeaderError, h.get_index_map, 2)
def yeo_to_91k(dlabel, medial_wall, reference, out): """Convert Yeo-style dlabels (Yeo and Schaefer parcellations) to 91k grayordinate space The Yeo lab generates dlabel's inclusive of medial wall vertices and only for the cortical surfaces. This is different from how typical dlabels are formatted, which exclude medial wall vertices and include voxels from all subcortical and cerebellar structures (i.e. the full 91k grayordinate space). This function corrects Yeo dlabels to proper 91k grayordinates. Parameters ---------- dlabel : str A Yeo-style .dlabel.nii atlas medial_wall : str HCP medial wall mask (.dlabel.nii) reference : str A reference .dlabel.nii file with 91k grayordinates and all brain models included out : str Output 91k grayordinate .dlabel.nii file """ dlabel = nib.load(dlabel) medial_wall = nib.load(medial_wall) ref = nib.load(reference) # remove medial wall vertices array = dlabel.get_fdata() corrected_array = array[np.logical_not(medial_wall.get_fdata())] # expand to 91k grayordinates = np.zeros(ref.shape) grayordinates[0, :corrected_array.shape[0]] = corrected_array # make header labels = dlabel.header.get_axis(index=0).label[0] label_table = ci.Cifti2LabelTable() for key, (tag, rgba) in labels.items(): label_table[key] = ci.Cifti2Label(key, tag, *rgba) maps = [ci.Cifti2NamedMap('labels', ci.Cifti2MetaData({}), label_table)] label_map = ci.Cifti2MatrixIndicesMap( applies_to_matrix_dimension=(0, ), indices_map_to_data_type='CIFTI_INDEX_TYPE_LABELS', maps=maps) model_map = ci.Cifti2MatrixIndicesMap( applies_to_matrix_dimension=(1, ), indices_map_to_data_type='CIFTI_INDEX_TYPE_BRAIN_MODELS', maps=list(ref.header.get_index_map(1).brain_models)) model_map.volume = ref.header.get_index_map(1).volume matrix = ci.Cifti2Matrix() matrix.append(label_map) matrix.append(model_map) hdr = ci.Cifti2Header(matrix) out_dtseries = ci.Cifti2Image(grayordinates, hdr) out_dtseries.to_filename(out) return out
def dlabel_to_dtseries(dlabel, out, n=10): """Create a mock .dtseries.nii from an .dlabel file All timepoints (rows) in .dtseries.nii are duplicates of the .dlabel array. This enables a way to verify that expected data is correctly extracted (e.g., label 1 should extract a timeseries of all 1's, etc). Parameters ---------- dlabel : str File name of a .dlabel.nii file out : str File name of output .dtseries.nii n : int, optional Number of timepoints to generate, by default 100 """ dlabel = nib.load(dlabel) # imitate data with TR=2 label_array = dlabel.get_fdata().ravel() tseries = np.tile(label_array, (n, 1)) data_map = ci.Cifti2MatrixIndicesMap( applies_to_matrix_dimension=(0, ), indices_map_to_data_type='CIFTI_INDEX_TYPE_SERIES', number_of_series_points=tseries.shape[0], series_start=0, series_step=2, series_exponent=0, series_unit='SECOND') # take brain models from dlabel model_map = ci.Cifti2MatrixIndicesMap( applies_to_matrix_dimension=(1, ), indices_map_to_data_type='CIFTI_INDEX_TYPE_BRAIN_MODELS', maps=list(dlabel.header.get_index_map(1).brain_models)) volume = dlabel.header.get_index_map(1).volume if volume is not None: model_map.volume = dlabel.header.get_index_map(1).volume # make header matrix = ci.Cifti2Matrix() matrix.append(data_map) matrix.append(model_map) hdr = ci.Cifti2Header(matrix) out_dtseries = ci.Cifti2Image(tseries, hdr) out_dtseries.to_filename(out) return out
def create_geometry_map(applies_to_matrix_dimension): voxels = ci.Cifti2VoxelIndicesIJK(brain_models[0][1]) left_thalamus = ci.Cifti2BrainModel(index_offset=0, index_count=4, model_type='CIFTI_MODEL_TYPE_VOXELS', brain_structure=brain_models[0][0], voxel_indices_ijk=voxels) vertices = ci.Cifti2VertexIndices(np.array(brain_models[1][1])) left_cortex = ci.Cifti2BrainModel(index_offset=4, index_count=5, model_type='CIFTI_MODEL_TYPE_SURFACE', brain_structure=brain_models[1][0], vertex_indices=vertices) left_cortex.surface_number_of_vertices = number_of_vertices vertices = ci.Cifti2VertexIndices(np.array(brain_models[2][1])) right_cortex = ci.Cifti2BrainModel(index_offset=9, index_count=1, model_type='CIFTI_MODEL_TYPE_SURFACE', brain_structure=brain_models[2][0], vertex_indices=vertices) right_cortex.surface_number_of_vertices = number_of_vertices volume = ci.Cifti2Volume( dimensions, ci.Cifti2TransformationMatrixVoxelIndicesIJKtoXYZ(-3, affine)) return ci.Cifti2MatrixIndicesMap( applies_to_matrix_dimension, 'CIFTI_INDEX_TYPE_BRAIN_MODELS', maps=[left_thalamus, left_cortex, right_cortex, volume])
def to_mapping(self, dim): """ Converts the parcels to a MatrixIndicesMap for storage in CIFTI format Parameters ---------- dim : int which dimension of the CIFTI vector/matrix is described by this dataset (zero-based) Returns ------- cifti2.Cifti2MatrixIndicesMap """ mim = cifti2.Cifti2MatrixIndicesMap([dim], 'CIFTI_INDEX_TYPE_PARCELS') if self.affine is not None: affine = cifti2.Cifti2TransformationMatrixVoxelIndicesIJKtoXYZ(-3, matrix=self.affine) mim.volume = cifti2.Cifti2Volume(self.volume_shape, affine) for name, nvertex in self.nvertices.items(): mim.append(cifti2.Cifti2Surface(name, nvertex)) for name, voxels, vertices in self.arr: cifti_voxels = cifti2.Cifti2VoxelIndicesIJK(voxels) element = cifti2.Cifti2Parcel(name, cifti_voxels) for name, idx_vertices in vertices.items(): element.vertices.append(cifti2.Cifti2Vertices(name, idx_vertices)) mim.append(element) return mim
def to_mapping(self, dim): """ Converts the brain model axis to a MatrixIndicesMap for storage in CIFTI format Parameters ---------- dim : int which dimension of the CIFTI vector/matrix is described by this dataset (zero-based) Returns ------- cifti2.Cifti2MatrixIndicesMap """ mim = cifti2.Cifti2MatrixIndicesMap([dim], 'CIFTI_INDEX_TYPE_BRAIN_MODELS') for name, to_slice, bm in self.iter_structures(): is_surface = name in self.nvertices.keys() if is_surface: voxels = None vertices = cifti2.Cifti2VertexIndices(bm.vertex) nvertex = self.nvertices[name] else: voxels = cifti2.Cifti2VoxelIndicesIJK(bm.voxel) vertices = None nvertex = None if mim.volume is None: affine = cifti2.Cifti2TransformationMatrixVoxelIndicesIJKtoXYZ(-3, matrix=self.affine) mim.volume = cifti2.Cifti2Volume(self.volume_shape, affine) cifti_bm = cifti2.Cifti2BrainModel(to_slice.start, len(bm), 'CIFTI_MODEL_TYPE_SURFACE' if is_surface else 'CIFTI_MODEL_TYPE_VOXELS', name, nvertex, voxels, vertices) mim.append(cifti_bm) return mim
def test_matrixindicesmap(): mim = ci.Cifti2MatrixIndicesMap(0, 'CIFTI_INDEX_TYPE_LABELS') volume = ci.Cifti2Volume() volume2 = ci.Cifti2Volume() parcel = ci.Cifti2Parcel() assert mim.volume is None mim.append(volume) mim.append(parcel) assert mim.volume == volume with pytest.raises(ci.Cifti2HeaderError): mim.insert(0, volume) with pytest.raises(ci.Cifti2HeaderError): mim[1] = volume mim[0] = volume2 assert mim.volume == volume2 del mim.volume assert mim.volume is None with pytest.raises(ValueError): del mim.volume mim.volume = volume assert mim.volume == volume mim.volume = volume2 assert mim.volume == volume2 with pytest.raises(ValueError): mim.volume = parcel
def test_matrixindicesmap(): mim = ci.Cifti2MatrixIndicesMap(0, 'CIFTI_INDEX_TYPE_LABELS') volume = ci.Cifti2Volume() volume2 = ci.Cifti2Volume() parcel = ci.Cifti2Parcel() assert_is_none(mim.volume) mim.append(volume) mim.append(parcel) assert_equal(mim.volume, volume) assert_raises(ci.Cifti2HeaderError, mim.insert, 0, volume) assert_raises(ci.Cifti2HeaderError, mim.__setitem__, 1, volume) mim[0] = volume2 assert_equal(mim.volume, volume2) del mim.volume assert_is_none(mim.volume) assert_raises(ValueError, delattr, mim, 'volume') mim.volume = volume assert_equal(mim.volume, volume) mim.volume = volume2 assert_equal(mim.volume, volume2) assert_raises(ValueError, setattr, mim, 'volume', parcel)
def create_series_map(): return ci.Cifti2MatrixIndicesMap((0, ), 'CIFTI_INDEX_TYPE_SERIES', number_of_series_points=timepoints, series_exponent=0, series_start=0, series_step=1, series_unit='SECOND')
def create_series_map(applies_to_matrix_dimension): return ci.Cifti2MatrixIndicesMap(applies_to_matrix_dimension, 'CIFTI_INDEX_TYPE_SERIES', number_of_series_points=13, series_exponent=-3, series_start=18.2, series_step=10.5, series_unit='SECOND')
def create_scalar_map(applies_to_matrix_dimension): maps = [ ci.Cifti2NamedMap(name, ci.Cifti2MetaData(meta)) for name, meta in scalars ] return ci.Cifti2MatrixIndicesMap(applies_to_matrix_dimension, 'CIFTI_INDEX_TYPE_SCALARS', maps=maps)
def make_imaker(self, arr, header=None, ni_header=None): for idx, sz in enumerate(arr.shape): maps = [ci.Cifti2NamedMap(str(value)) for value in range(sz)] mim = ci.Cifti2MatrixIndicesMap((idx, ), 'CIFTI_INDEX_TYPE_SCALARS', maps=maps) header.matrix.append(mim) return lambda: self.image_maker(arr.copy(), header, ni_header)
def test_matrix(): m = ci.Cifti2Matrix() with pytest.raises(ValueError): m.metadata = ci.Cifti2Parcel() with pytest.raises(TypeError): m[0] = ci.Cifti2Parcel() with pytest.raises(TypeError): m.insert(0, ci.Cifti2Parcel()) mim_none = ci.Cifti2MatrixIndicesMap(None, 'CIFTI_INDEX_TYPE_LABELS') mim_0 = ci.Cifti2MatrixIndicesMap(0, 'CIFTI_INDEX_TYPE_LABELS') mim_1 = ci.Cifti2MatrixIndicesMap(1, 'CIFTI_INDEX_TYPE_LABELS') mim_01 = ci.Cifti2MatrixIndicesMap([0, 1], 'CIFTI_INDEX_TYPE_LABELS') with pytest.raises(ci.Cifti2HeaderError): m.insert(0, mim_none) assert m.mapped_indices == [] h = ci.Cifti2Header(matrix=m) assert m.mapped_indices == [] m.insert(0, mim_0) assert h.mapped_indices == [0] assert h.number_of_mapped_indices == 1 with pytest.raises(ci.Cifti2HeaderError): m.insert(0, mim_0) with pytest.raises(ci.Cifti2HeaderError): m.insert(0, mim_01) m[0] = mim_1 assert list(m.mapped_indices) == [1] m.insert(0, mim_0) assert list(sorted(m.mapped_indices)) == [0, 1] assert h.number_of_mapped_indices == 2 assert h.get_index_map(0) == mim_0 assert h.get_index_map(1) == mim_1 with pytest.raises(ci.Cifti2HeaderError): h.get_index_map(2)
def create_label_map(applies_to_matrix_dimension): maps = [] for name, meta, label in labels: label_table = ci.Cifti2LabelTable() for key, (tag, rgba) in label.items(): label_table[key] = ci.Cifti2Label(key, tag, *rgba) maps.append( ci.Cifti2NamedMap(name, ci.Cifti2MetaData(meta), label_table)) return ci.Cifti2MatrixIndicesMap(applies_to_matrix_dimension, 'CIFTI_INDEX_TYPE_LABELS', maps=maps)
def create_parcel_map(applies_to_matrix_dimension, surfaces, volume, pinfo): """Creaters a pracel map PARAMETERS --------- applies_to_matrix_dimension : tuple surfaces : list of Cifti2Surface volume : Cifti2Volume pinfo : list of ParcelInfo """ mapping = ci.Cifti2MatrixIndicesMap(applies_to_matrix_dimension, Map.PARCELS) for p in pinfo: mapping.append(create_parcel(p)) mapping.extend(surfaces) mapping.volume = volume return mapping
def to_mapping(self, dim): """ Converts the hcp_labels to a MatrixIndicesMap for storage in CIFTI format Parameters ---------- dim : int which dimension of the CIFTI vector/matrix is described by this dataset (zero-based) Returns ------- cifti2.Cifti2MatrixIndicesMap """ mim = cifti2.Cifti2MatrixIndicesMap([dim], 'CIFTI_INDEX_TYPE_SCALARS') for elem in self.arr: meta = None if len(elem['meta']) == 0 else elem['meta'] named_map = cifti2.Cifti2NamedMap(elem['name'], cifti2.Cifti2MetaData(meta)) mim.append(named_map) return mim
def to_mapping(self, dim): """ Converts the series to a MatrixIndicesMap for storage in CIFTI format Parameters ---------- dim : int which dimension of the CIFTI vector/matrix is described by this dataset (zero-based) Returns ------- cifti2.Cifti2MatrixIndicesMap """ mim = cifti2.Cifti2MatrixIndicesMap([dim], 'CIFTI_INDEX_TYPE_SERIES') mim.series_exponent = 0 mim.series_start = self.start mim.series_step = self.step mim.number_of_series_points = self.size return mim
def create_parcel_map(applies_to_matrix_dimension): mapping = ci.Cifti2MatrixIndicesMap(applies_to_matrix_dimension, 'CIFTI_INDEX_TYPE_PARCELS') for name, elements in parcels: surfaces = [] volume = None for element in elements: if isinstance(element[0], str): surfaces.append(ci.Cifti2Vertices(element[0], element[1])) else: volume = ci.Cifti2VoxelIndicesIJK(element) mapping.append(ci.Cifti2Parcel(name, volume, surfaces)) mapping.extend([ ci.Cifti2Surface('CIFTI_STRUCTURE_CORTEX_%s' % orientation, number_of_vertices) for orientation in ['LEFT', 'RIGHT'] ]) mapping.volume = ci.Cifti2Volume( dimensions, ci.Cifti2TransformationMatrixVoxelIndicesIJKtoXYZ(-3, affine)) return mapping
def to_mapping(self, dim): """ Converts the hcp_labels to a MatrixIndicesMap for storage in CIFTI format Parameters ---------- dim : int which dimension of the CIFTI vector/matrix is described by this dataset (zero-based) Returns ------- cifti2.Cifti2MatrixIndicesMap """ mim = cifti2.Cifti2MatrixIndicesMap([dim], 'CIFTI_INDEX_TYPE_LABELS') for elem in self.arr: label_table = cifti2.Cifti2LabelTable() for key, value in elem['label'].items(): label_table[key] = (value[0],) + tuple(value[1]) meta = None if len(elem['meta']) == 0 else elem['meta'] named_map = cifti2.Cifti2NamedMap(elem['name'], cifti2.Cifti2MetaData(meta), label_table) mim.append(named_map) return mim
def create_geometry_map(): index_offset = 0 brain_models = [] timeseries = np.zeros((timepoints, 0)) for name, data in models: if "CORTEX" in name: model_type = "CIFTI_MODEL_TYPE_SURFACE" attr = "vertex_indices" indices = ci.Cifti2VertexIndices(np.arange(len(data))) else: model_type = "CIFTI_MODEL_TYPE_VOXELS" attr = "voxel_indices_ijk" indices = ci.Cifti2VoxelIndicesIJK(np.arange(len(data))) bm = ci.Cifti2BrainModel( index_offset=index_offset, index_count=len(data), model_type=model_type, brain_structure=name, ) setattr(bm, attr, indices) index_offset += len(data) brain_models.append(bm) timeseries = np.column_stack((timeseries, data.T)) brain_models.append( ci.Cifti2Volume( (4, 4, 4), ci.Cifti2TransformationMatrixVoxelIndicesIJKtoXYZ( -3, np.eye(4)), )) return ci.Cifti2MatrixIndicesMap( (1, ), "CIFTI_INDEX_TYPE_BRAIN_MODELS", maps=brain_models, ), timeseries
def create_geometry_map(applies_to_matrix_dimension, brain_models): """Creates a geometry map""" return ci.Cifti2MatrixIndicesMap(applies_to_matrix_dimension, Map.BRAIN_MODELS, maps=brain_models)
def create_scalar_map(applies_to_matrix_dimension, info): """Creates a scalar map form a list of NamedMapInfo""" maps = [ci.Cifti2NamedMap(i.name, ci.Cifti2MetaData(i.meta)) for i in info] return ci.Cifti2MatrixIndicesMap(applies_to_matrix_dimension, Map.SCALARS, maps=maps)
indices=cortex_left_indices, model_type=ch.ModelType.SURFACE, surface_number_of_vertices=ch.HCP_32K_FS_L) right_thalamus = ch.MapInfo(brain_structure=ch.Structure.THALAMUS_LEFT, indices=voxels, model_type=ch.ModelType.VOXEL, surface_number_of_vertices=None) volume = ch.create_volume([50, 50, 50], affine, -3) # create scalar maps wrong_scalar_map = ch.create_scalar_map((0,), [ch.NamedMapInfo(name="wrong", meta={})]) correct_scalar_map = ch.create_scalar_map((0,), [ch.NamedMapInfo(name="right", meta={})]) # create series maps series_map = ci.Cifti2MatrixIndicesMap((0, ), ch.Map.SERIES, number_of_series_points=40, series_exponent=0, series_start=0, series_step=0.5, series_unit="SECOND") # create brain models wrong_brain_models = ch.create_brain_models([wrong_right_cortex, left_cortex, right_thalamus]) wrong_brain_models.append(volume) correct_brain_models = ch.create_brain_models([right_cortex, left_cortex, right_thalamus]) correct_brain_models.append(volume) no_volume_brain_models = ch.create_brain_models([right_cortex, left_cortex]) # create geometry maps wrong_geometry_map = ch.create_geometry_map((1,), wrong_brain_models) correct_geometry_map = ch.create_geometry_map((1, ), correct_brain_models) no_volume_geometry_map = ch.create_geometry_map((1, ), no_volume_brain_models)
def _create_cifti_image(bold_file, label_file, bold_surfs, annotation_files, tr, targets): """ Generate CIFTI image in target space. Parameters ---------- bold_file : str BOLD volumetric timeseries label_file : str Subcortical label file bold_surfs : list BOLD surface timeseries [L,R] annotation_files : list Surface label files used to remove medial wall tr : float BOLD repetition time targets : tuple or list Surface and volumetric output spaces Returns ------- out : BOLD data saved as CIFTI dtseries """ bold_img = nb.load(bold_file) label_img = nb.load(label_file) if label_img.shape != bold_img.shape[:3]: warnings.warn("Resampling bold volume to match label dimensions") bold_img = resample_to_img(bold_img, label_img) bold_data = bold_img.get_fdata(dtype='float32') timepoints = bold_img.shape[3] label_data = np.asanyarray(label_img.dataobj).astype('int16') # Create brain models idx_offset = 0 brainmodels = [] bm_ts = np.empty((timepoints, 0)) for structure, labels in CIFTI_STRUCT_WITH_LABELS.items(): if labels is None: # surface model model_type = "CIFTI_MODEL_TYPE_SURFACE" # use the corresponding annotation hemi = structure.split('_')[-1] # currently only supports L/R cortex surf = nb.load(bold_surfs[hemi == "RIGHT"]) surf_verts = len(surf.darrays[0].data) if annotation_files[0].endswith('.annot'): annot = nb.freesurfer.read_annot( annotation_files[hemi == "RIGHT"]) # remove medial wall medial = np.nonzero(annot[0] != annot[2].index(b'unknown'))[0] else: annot = nb.load(annotation_files[hemi == "RIGHT"]) medial = np.nonzero(annot.darrays[0].data)[0] # extract values across volumes ts = np.array([tsarr.data[medial] for tsarr in surf.darrays]) vert_idx = ci.Cifti2VertexIndices(medial) bm = ci.Cifti2BrainModel(index_offset=idx_offset, index_count=len(vert_idx), model_type=model_type, brain_structure=structure, vertex_indices=vert_idx, n_surface_vertices=surf_verts) idx_offset += len(vert_idx) bm_ts = np.column_stack((bm_ts, ts)) else: model_type = "CIFTI_MODEL_TYPE_VOXELS" vox = [] ts = None for label in labels: ijk = np.nonzero(label_data == label) if ijk[0].size == 0: # skip label if nothing matches continue ts = (bold_data[ijk] if ts is None else np.concatenate( (ts, bold_data[ijk]))) vox += [[ijk[0][ix], ijk[1][ix], ijk[2][ix]] for ix, row in enumerate(ts)] vox = ci.Cifti2VoxelIndicesIJK(vox) bm = ci.Cifti2BrainModel(index_offset=idx_offset, index_count=len(vox), model_type=model_type, brain_structure=structure, voxel_indices_ijk=vox) idx_offset += len(vox) bm_ts = np.column_stack((bm_ts, ts.T)) # add each brain structure to list brainmodels.append(bm) # add volume information brainmodels.append( ci.Cifti2Volume( bold_img.shape[:3], ci.Cifti2TransformationMatrixVoxelIndicesIJKtoXYZ( -3, bold_img.affine))) # generate Matrix information series_map = ci.Cifti2MatrixIndicesMap((0, ), 'CIFTI_INDEX_TYPE_SERIES', number_of_series_points=timepoints, series_exponent=0, series_start=0.0, series_step=tr, series_unit='SECOND') geometry_map = ci.Cifti2MatrixIndicesMap((1, ), 'CIFTI_INDEX_TYPE_BRAIN_MODELS', maps=brainmodels) # provide some metadata to CIFTI matrix meta = { "surface": targets[0], "volume": targets[1], } # generate and save CIFTI image matrix = ci.Cifti2Matrix() matrix.append(series_map) matrix.append(geometry_map) matrix.metadata = ci.Cifti2MetaData(meta) hdr = ci.Cifti2Header(matrix) img = ci.Cifti2Image(bm_ts, hdr) img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES') out_file = "{}.dtseries.nii".format(split_filename(bold_file)[1]) ci.save(img, out_file) return os.path.join(os.getcwd(), out_file)
def _create_cifti_image(bold_file, label_file, annotation_files, gii_files, volume_target, surface_target, tr): """ Generate CIFTI image in target space Parameters bold_file : 4D BOLD timeseries label_file : label atlas annotation_files : FreeSurfer annotations gii_files : 4D BOLD surface timeseries in GIFTI format volume_target : label atlas space surface_target : gii_files space tr : repetition timeseries Returns out_file : BOLD data as CIFTI dtseries """ label_img = nb.load(label_file) bold_img = resample_to_img(bold_file, label_img) bold_data = bold_img.get_data() timepoints = bold_img.shape[3] label_data = label_img.get_data() # set up CIFTI information series_map = ci.Cifti2MatrixIndicesMap( (0, ), 'CIFTI_INDEX_TYPE_SERIES', number_of_series_points=timepoints, series_exponent=0, series_start=0.0, series_step=tr, series_unit='SECOND') # Create CIFTI brain models idx_offset = 0 brainmodels = [] bm_ts = np.empty((timepoints, 0)) for structure, labels in CIFTI_STRUCT_WITH_LABELS.items(): if labels is None: # surface model model_type = "CIFTI_MODEL_TYPE_SURFACE" # use the corresponding annotation hemi = structure.split('_')[-1] annot = nb.freesurfer.read_annot( annotation_files[hemi == "RIGHT"]) # currently only supports L/R cortex gii = nb.load(gii_files[hemi == "RIGHT"]) # calculate total number of vertices surf_verts = len(annot[0]) # remove medial wall for CIFTI format vert_idx = np.nonzero( annot[0] != annot[2].index(b'unknown'))[0] # extract values across volumes ts = np.array([tsarr.data[vert_idx] for tsarr in gii.darrays]) vert_idx = ci.Cifti2VertexIndices(vert_idx) bm = ci.Cifti2BrainModel(index_offset=idx_offset, index_count=len(vert_idx), model_type=model_type, brain_structure=structure, vertex_indices=vert_idx, n_surface_vertices=surf_verts) bm_ts = np.column_stack((bm_ts, ts)) idx_offset += len(vert_idx) brainmodels.append(bm) else: model_type = "CIFTI_MODEL_TYPE_VOXELS" vox = [] ts = None for label in labels: ijk = np.nonzero(label_data == label) ts = (bold_data[ijk] if ts is None else np.concatenate( (ts, bold_data[ijk]))) vox += [[ijk[0][ix], ijk[1][ix], ijk[2][ix]] for ix, row in enumerate(ts)] bm_ts = np.column_stack((bm_ts, ts.T)) vox = ci.Cifti2VoxelIndicesIJK(vox) bm = ci.Cifti2BrainModel(index_offset=idx_offset, index_count=len(vox), model_type=model_type, brain_structure=structure, voxel_indices_ijk=vox) idx_offset += len(vox) brainmodels.append(bm) volume = ci.Cifti2Volume( bold_img.shape[:3], ci.Cifti2TransformationMatrixVoxelIndicesIJKtoXYZ( -3, bold_img.affine)) brainmodels.append(volume) # create CIFTI geometry based on brainmodels geometry_map = ci.Cifti2MatrixIndicesMap( (1, ), 'CIFTI_INDEX_TYPE_BRAIN_MODELS', maps=brainmodels) # provide some metadata to CIFTI matrix meta = { "target_surface": surface_target, "target_volume": volume_target, } # generate and save CIFTI image matrix = ci.Cifti2Matrix() matrix.append(series_map) matrix.append(geometry_map) matrix.metadata = ci.Cifti2MetaData(meta) hdr = ci.Cifti2Header(matrix) img = ci.Cifti2Image(bm_ts, hdr) img.nifti_header.set_intent('NIFTI_INTENT_CONNECTIVITY_DENSE_SERIES') _, out_base, _ = split_filename(bold_file) out_file = "{}.dtseries.nii".format(out_base) ci.save(img, out_file) return os.path.join(os.getcwd(), out_file)