def test_write_annotation(self): file_path = get_data_file( self.subject, self.annot_path, "lh.aparc.annot") annotation = IOUtils.read_annotation(file_path) out_annotation_path = self.temp_file_path("lh-test.aparc.annot") IOUtils.write_annotation(out_annotation_path, annotation) new_annotation = IOUtils.read_annotation(out_annotation_path) self.assertEqual(annotation.region_names, new_annotation.region_names)
def aseg_surf_conc_annot(self, surf_path, out_surf_path, annot_path, label_indices, lut_path=None): """ Concatenate surfaces of one specific label of interest each, to create a single annotated surface. """ lut_path = lut_path or default_lut_path() label_names, color_table = self.annotation_service.lut_to_annot_names_ctab( lut_path=lut_path, labels=label_indices) label_indices = numpy.array(label_indices.split()).astype('i') # verts tri area_mask cras surfaces = [] out_annotation = Annotation([], [], []) label_number = -1 for label_index in label_indices: this_surf_path = surf_path + "-%06d" % int(label_index) if os.path.exists(this_surf_path): ind_l, = numpy.where(label_indices == label_index) out_annotation.add_region_names_and_colors( numpy.array(label_names)[ind_l], color_table[ind_l, :]) label_number += 1 surfaces.append(IOUtils.read_surface(this_surf_path, False)) out_annotation.add_region_mapping(label_number * numpy.ones( (surfaces[-1].n_vertices, ), dtype='int64')) out_surface = self.merge_surfaces(surfaces) #out_annotation.regions_color_table = numpy.squeeze(numpy.array(out_annotation.regions_color_table).astype('i')) IOUtils.write_surface(out_surf_path, out_surface) IOUtils.write_annotation(annot_path, out_annotation)
def aseg_surf_conc_annot(self, surf_path: str, out_surf_path: str, annot_path: str, label_indices: Union[numpy.ndarray, list], lut_path: Optional[str]=None) -> Surface: """ Concatenate surfaces of one specific label of interest each, to create a single annotated surface. """ lut_path = lut_path or default_lut_path() label_names, color_table = self.annotation_service.lut_to_annot_names_ctab(lut_path=lut_path, labels=label_indices) label_indices = numpy.array(label_indices.split()).astype('i') # verts tri area_mask cras surfaces = [] out_annotation = Annotation([], [], []) label_number = -1 for label_index in label_indices: # TODO: This is hardcoded: /aseg-%06d here and also in pegasus dax generator this_surf_path = surf_path + "/aseg-%06d" % int(label_index) if os.path.exists(this_surf_path): ind_l, = numpy.where(label_indices == label_index) out_annotation.add_region_names_and_colors( label_names[int(ind_l)], color_table[ind_l, :]) label_number += 1 surfaces.append(IOUtils.read_surface(this_surf_path, False)) out_annotation.add_region_mapping( label_number * numpy.ones((surfaces[-1].n_vertices,), dtype='int64')) out_surface = self.merge_surfaces(surfaces) # out_annotation.regions_color_table = numpy.squeeze(numpy.array(out_annotation.regions_color_table).astype('i')) IOUtils.write_surface(out_surf_path, out_surface) IOUtils.write_annotation(annot_path, out_annotation) return out_surface
def sample_vol_on_surf(self, surf_path, vol_path, annot_path, out_surf_path, cras_path, add_string='', vertex_neighbourhood=1, add_lbl=[], lut_path=None): """ Sample a volume of a specific label on a surface, by keeping only those surface vertices, the nearest voxel of which is of the given label (+ of possibly additional target labels, such as white matter). Allow optionally for vertices within a given voxel distance vn from the target voxels. """ lut_path = lut_path or default_lut_path() # Read the inputs surface = IOUtils.read_surface(surf_path, False) annotation = IOUtils.read_annotation(annot_path) labels = self.annotation_service.annot_names_to_labels( annotation.region_names, add_string=add_string, lut_path=lut_path) region_mapping_indexes = numpy.unique(annotation.region_mapping) volume_parser = VolumeIO() volume = volume_parser.read(vol_path) ras2vox_affine_matrix = numpy.linalg.inv(volume.affine_matrix) cras = numpy.loadtxt(cras_path) grid, n_grid = self.__prepare_grid(vertex_neighbourhood) # Initialize the output mask: verts_out_mask = numpy.repeat([False], surface.vertices.shape[0]) for label_index in range(len(region_mapping_indexes)): self.logger.info("%s", add_string + annotation.region_names[label_index]) # Get the indexes of the vertices corresponding to this label: verts_indices_of_label, = numpy.where( annotation.region_mapping[:] == region_mapping_indexes[label_index]) verts_indices_of_label_size = verts_indices_of_label.size if verts_indices_of_label_size == 0: continue # Add any additional labels all_labels = [labels[label_index]] + add_lbl # get the vertices for current label and add cras to take them to # scanner ras verts_of_label = surface.vertices[verts_indices_of_label, :] verts_of_label += numpy.repeat(numpy.expand_dims(cras, 1).T, verts_indices_of_label_size, axis=0) # Compute the nearest voxel coordinates using the affine transform ijk = numpy.round( ras2vox_affine_matrix.dot(numpy.c_[verts_of_label, numpy.ones(verts_indices_of_label_size)].T)[:3].T) \ .astype('i') # Get the labels of these voxels: surf_vxls = volume.data[ijk[:, 0], ijk[:, 1], ijk[:, 2]] # Vertex mask to keep: those that correspond to voxels of one of # the target labels # surf_vxls==lbl if only one target label verts_keep, = numpy.where(numpy.in1d(surf_vxls, all_labels)) verts_out_mask[verts_indices_of_label[verts_keep]] = True if vertex_neighbourhood > 0: # These are now the remaining indexes to be checked for # neighboring voxels verts_indices_of_label = numpy.delete(verts_indices_of_label, verts_keep) ijk = numpy.delete(ijk, verts_keep, axis=0) for vertex_index in range(verts_indices_of_label.size): # Generate the specific grid centered at the voxel ijk ijk_grid = grid + \ numpy.tile(ijk[vertex_index, :], (n_grid, 1)) # Remove voxels outside the volume indexes_within_limits = numpy.all( [(ijk_grid[:, 0] >= 0), (ijk_grid[:, 0] < volume.dimensions[0]), (ijk_grid[:, 1] >= 0), (ijk_grid[:, 1] < volume.dimensions[1]), (ijk_grid[:, 2] >= 0), (ijk_grid[:, 2] < volume.dimensions[2])], axis=0) ijk_grid = ijk_grid[indexes_within_limits, :] surf_vxls = volume.data[ijk_grid[:, 0], ijk_grid[:, 1], ijk_grid[:, 2]] # If any of the neighbors is of the target labels include # the current vertex # surf_vxls==lbl if only one target label if numpy.any(numpy.in1d(surf_vxls, all_labels)): verts_out_mask[ verts_indices_of_label[vertex_index]] = True # Vertex indexes and vertices to keep: verts_out_indices, = numpy.where(verts_out_mask) verts_out = surface.vertices[verts_out_indices] # TODO maybe: make sure that all voxels of this label correspond to at least one vertex. # Create a similar mask for faces by picking only triangles of which # all 3 vertices are included face_out_mask = numpy.c_[verts_out_mask[surface.triangles[:, 0]], verts_out_mask[surface.triangles[:, 1]], verts_out_mask[surface.triangles[:, 2]]].all( axis=1) faces_out = surface.triangles[face_out_mask] # The old vertices' indexes of faces have to be transformed to the new # vrtx_out_inds: for iF in range(faces_out.shape[0]): for vertex_index in range(3): faces_out[iF, vertex_index], = numpy.where( faces_out[iF, vertex_index] == verts_out_indices) surface.vertices = verts_out surface.triangles = faces_out # Write the output surfaces and annotations to files. Also write files # with the indexes of vertices to keep. IOUtils.write_surface(out_surf_path, surface) annotation.set_region_mapping( annotation.get_region_mapping_by_indices([verts_out_indices])) IOUtils.write_annotation(out_surf_path + ".annot", annotation) numpy.save(out_surf_path + "-idx.npy", verts_out_indices) numpy.savetxt(out_surf_path + "-idx.txt", verts_out_indices, fmt='%d')
def sample_vol_on_surf(self, surf_path: str, vol_path: str, annot_path: str, out_surf_path: str, cras_path: str, add_string: str='', vertex_neighbourhood: int=1, add_lbl: list=[], lut_path: Optional[str]=None) -> (Surface, Annotation): """ Sample a volume of a specific label on a surface, by keeping only those surface vertices, the nearest voxel of which is of the given label (+ of possibly additional target labels, such as white matter). Allow optionally for vertices within a given voxel distance vn from the target voxels. """ lut_path = lut_path or default_lut_path() # Read the inputs surface = IOUtils.read_surface(surf_path, False) annotation = IOUtils.read_annotation(annot_path) labels = self.annotation_service.annot_names_to_labels(annotation.region_names, add_string=add_string, lut_path=lut_path) region_mapping_indexes = numpy.unique(annotation.region_mapping) volume_parser = VolumeIO() volume = volume_parser.read(vol_path) ras2vox_affine_matrix = numpy.linalg.inv(volume.affine_matrix) cras = numpy.loadtxt(cras_path) grid, n_grid = self.__prepare_grid(vertex_neighbourhood) # Initialize the output mask: verts_out_mask = numpy.repeat([False], surface.vertices.shape[0]) for label_index in range(len(region_mapping_indexes)): self.logger.info("%s", add_string + annotation.region_names[label_index]) # Get the indexes of the vertices corresponding to this label: verts_indices_of_label, = numpy.where( annotation.region_mapping[:] == region_mapping_indexes[label_index]) verts_indices_of_label_size = verts_indices_of_label.size if verts_indices_of_label_size == 0: continue # Add any additional labels all_labels = [labels[label_index]] + add_lbl # get the vertices for current label and add cras to take them to # scanner ras verts_of_label = surface.vertices[verts_indices_of_label, :] verts_of_label += numpy.repeat(numpy.expand_dims( cras, 1).T, verts_indices_of_label_size, axis=0) # Compute the nearest voxel coordinates using the affine transform ijk = numpy.round( ras2vox_affine_matrix.dot(numpy.c_[verts_of_label, numpy.ones(verts_indices_of_label_size)].T)[:3].T) \ .astype('i') # Get the labels of these voxels: surf_vxls = volume.data[ijk[:, 0], ijk[:, 1], ijk[:, 2]] # Vertex mask to keep: those that correspond to voxels of one of # the target labels # surf_vxls==lbl if only one target label verts_keep, = numpy.where(numpy.in1d(surf_vxls, all_labels)) verts_out_mask[verts_indices_of_label[verts_keep]] = True if vertex_neighbourhood > 0: # These are now the remaining indexes to be checked for # neighboring voxels verts_indices_of_label = numpy.delete( verts_indices_of_label, verts_keep) ijk = numpy.delete(ijk, verts_keep, axis=0) for vertex_index in range(verts_indices_of_label.size): # Generate the specific grid centered at the voxel ijk ijk_grid = grid + \ numpy.tile(ijk[vertex_index, :], (n_grid, 1)) # Remove voxels outside the volume indexes_within_limits = numpy.all([(ijk_grid[:, 0] >= 0), (ijk_grid[:, 0] < volume.dimensions[0]), (ijk_grid[:, 1] >= 0), (ijk_grid[ :, 1] < volume.dimensions[1]), (ijk_grid[:, 2] >= 0), (ijk_grid[:, 2] < volume.dimensions[2])], axis=0) ijk_grid = ijk_grid[indexes_within_limits, :] surf_vxls = volume.data[ ijk_grid[:, 0], ijk_grid[:, 1], ijk_grid[:, 2]] # If any of the neighbors is of the target labels include # the current vertex # surf_vxls==lbl if only one target label if numpy.any(numpy.in1d(surf_vxls, all_labels)): verts_out_mask[ verts_indices_of_label[vertex_index]] = True # Vertex indexes and vertices to keep: verts_out_indices, = numpy.where(verts_out_mask) verts_out = surface.vertices[verts_out_indices] # TODO maybe: make sure that all voxels of this label correspond to at least one vertex. # Create a similar mask for faces by picking only triangles of which # all 3 vertices are included face_out_mask = numpy.c_[ verts_out_mask[surface.triangles[:, 0]], verts_out_mask[surface.triangles[:, 1]], verts_out_mask[ surface.triangles[:, 2]]].all(axis=1) faces_out = surface.triangles[face_out_mask] # The old vertices' indexes of faces have to be transformed to the new # vrtx_out_inds: for iF in range(faces_out.shape[0]): for vertex_index in range(3): faces_out[iF, vertex_index], = numpy.where( faces_out[iF, vertex_index] == verts_out_indices) surface.vertices = verts_out surface.triangles = faces_out # Write the output surfaces and annotations to files. Also write files # with the indexes of vertices to keep. IOUtils.write_surface(out_surf_path, surface) annotation.set_region_mapping( annotation.get_region_mapping_by_indices([verts_out_indices])) IOUtils.write_annotation(out_surf_path + ".annot", annotation) numpy.save(out_surf_path + "-idx.npy", verts_out_indices) numpy.savetxt(out_surf_path + "-idx.txt", verts_out_indices, fmt='%d') return surface, annotation