def test_set_new_data_for_buggy_image_header(): im_0 = nib.Nifti2Image(np.zeros([3, 3, 3]), affine=np.eye(4)) im_0.header['sizeof_hdr'] = 550 with assert_raises(IOError): set_new_data(im_0, np.array([6, 6, 6]))
def exploded_segmentation(im_segm, direction, intercepts, offset, dtype=np.int): """ Damien Hirst-like sectioning of an anatomical segmentation. :param im_segm: nibabel image segmentation :param direction: sectioning direction, can be sagittal, axial or coronal (conventional names for images oriented to standard (diagonal affine transformation)) :param intercepts: list of values of the stack plane in the input segmentation. Needs to include the max plane and the min plane :param offset: voxel to leave empty between one slice and the other :return: nibabel image output as sectioning of the input one. """ if direction.lower() == 'axial': block = np.zeros([im_segm.shape[0], im_segm.shape[1], offset]).astype(dtype) stack = [] for j in range(1, len(intercepts)): stack += [ im_segm.get_data()[:, :, intercepts[j - 1]:intercepts[j]].astype(dtype) ] + [block] return set_new_data(im_segm, np.concatenate(stack, axis=2)) elif direction.lower() == 'sagittal': block = np.zeros([offset, im_segm.shape[1], im_segm.shape[2]]).astype(dtype) stack = [] for j in range(1, len(intercepts)): stack += [ im_segm.get_data()[ intercepts[j - 1]:intercepts[j], :, :].astype(dtype) ] + [block] return set_new_data(im_segm, np.concatenate(stack, axis=0)) elif direction.lower() == 'coronal': block = np.zeros([im_segm.shape[0], offset, im_segm.shape[2]]).astype(dtype) stack = [] for j in range(1, len(intercepts)): stack += [ im_segm.get_data() [:, intercepts[j - 1]:intercepts[j], :].astype(dtype) ] + [block] for st in stack: print(st.shape) return set_new_data(im_segm, np.concatenate(stack, axis=1)) else: raise IOError
def relabel(self, path_to_input_segmentation, path_to_output_segmentation=None, list_old_labels=(), list_new_labels=(), path_to_input_labels_descriptor=None, path_to_output_labels_descriptor=None): """ Masks of :func:`labels_manager.tools.manipulations.relabeller.relabeller` using filenames """ pfi_in, pfi_out = get_pfi_in_pfi_out(path_to_input_segmentation, path_to_output_segmentation, self.pfo_in, self.pfo_out) im_labels = nib.load(pfi_in) data_labels = im_labels.get_data() data_relabelled = relabeller(data_labels, list_old_labels=list_old_labels, list_new_labels=list_new_labels) im_relabelled = set_new_data(im_labels, data_relabelled) nib.save(im_relabelled, pfi_out) if path_to_input_labels_descriptor is not None: pfi_in_ld = connect_path_tail_head(self.pfo_in, path_to_input_labels_descriptor) ldm_input = LdM(pfi_in_ld, labels_descriptor_convention=self.labels_descriptor_convention) ldm_relabelled = ldm_input.relabel(list_old_labels=list_old_labels, list_new_labels=list_new_labels) if path_to_output_labels_descriptor is None: ldm_relabelled.save_label_descriptor(pfi_in_ld) else: pfi_out_ld = connect_path_tail_head(self.pfo_out, path_to_output_labels_descriptor) ldm_relabelled.save_label_descriptor(pfi_out_ld) print('Relabelled image {0} saved in {1}.'.format(pfi_in, pfi_out)) return pfi_out
def simple_intensities_thresholding(self, path_to_input_image, path_to_output_segmentation, number_of_levels=5, output_dtype=np.uint16): """ Simple level intensity-based segmentation. :param path_to_input_image: :param path_to_output_segmentation: :param number_of_levels: number of levels in the output segmentations :param output_dtype: data type output crisp segmentation (uint16) :return: the method saves crisp segmentation based on intensities at the specified path. """ pfi_input_image = connect_path_tail_head(self.pfo_in, path_to_input_image) input_im = nib.load(pfi_input_image) output_array = intensity_segmentation(input_im.get_data(), num_levels=number_of_levels) output_im = set_new_data(input_im, output_array, new_dtype=output_dtype) pfi_output_segm = connect_path_tail_head(self.pfo_out, path_to_output_segmentation) nib.save(output_im, pfi_output_segm)
def clean_segmentation(self, path_to_input_segmentation, path_to_output_cleaned_segmentation, labels_to_clean=(), verbose=1, special_label=None, force_overwriting=False): """ Clean the segmentation merging the small connected components with the surrounding tissue. :param path_to_input_segmentation: path to the input segmentation :param path_to_output_cleaned_segmentation: path to the output cleaned segmentation. For safety this file can not exist before calling this method. :param labels_to_clean: list of binaries lists. [[z_1, zc_1], ... , [z_J, zc_J]] where z_j is the label you want to clean and zc_1 is the number of components you want to keep. If empty tuple, by default cleans all the labels keeping only one component. :param special_label: internal variable for the dummy labels that will be used for the 'holes'. This must not be a label already present in the segmentation. If None, it is the max label + 1. :param verbose: :return: it saves the cleaned segmentation at the specified output path. Note: as a feature (really!) after the holes identification, all labels, and not only the ones indicated in the input dilate iteratively over the 'holes'. """ pfi_in, pfi_out = get_pfi_in_pfi_out(path_to_input_segmentation, path_to_output_cleaned_segmentation, self.pfo_in, self.pfo_out) if not force_overwriting: if os.path.exists(pfi_out): raise IOError('File {} already exists. Cleaner can not overwrite a segmentation'.format(pfi_out)) im_segm = nib.load(pfi_in) if special_label is None: special_label = np.max(im_segm.get_data()) + 1 new_segm_data = clean_semgentation(im_segm.get_data(), labels_to_clean=labels_to_clean, label_for_holes=special_label) im_segm_cleaned = set_new_data(im_segm, new_segm_data.astype(im_segm.get_data_dtype())) nib.save(im_segm_cleaned, pfi_out) if verbose: print('Segmentation {} cleaned saved to {}'.format(pfi_in, pfi_out))
def erase_labels(self, path_to_input_segmentation, path_to_output_segmentation=None, labels_to_erase=(), path_to_input_labels_descriptor=None, path_to_output_labels_descriptor=None): pfi_in, pfi_out = get_pfi_in_pfi_out(path_to_input_segmentation, path_to_output_segmentation, self.pfo_in, self.pfo_out) im_labels = nib.load(pfi_in) data_labels = im_labels.get_data() data_erased = erase_labels(data_labels, labels_to_erase=labels_to_erase) im_erased = set_new_data(im_labels, data_erased) nib.save(im_erased, pfi_out) if path_to_input_labels_descriptor is not None: pfi_in_ld = connect_path_tail_head(self.pfo_in, path_to_input_labels_descriptor) ldm_input = LdM(pfi_in_ld, labels_descriptor_convention=self.labels_descriptor_convention) ldm_relabelled = ldm_input.erase_labels(labels_to_erase, verbose=self.verbose) if path_to_output_labels_descriptor is None: ldm_relabelled.save_label_descriptor(pfi_in_ld) else: pfi_out_ld = connect_path_tail_head(self.pfo_out, path_to_output_labels_descriptor) ldm_relabelled.save_label_descriptor(pfi_out_ld) print('Erased labels from image {0} saved in {1}.'.format(pfi_in, pfi_out)) return pfi_out
def get_zebra_midplane(im_segm, direction, intercepts, offset, foreground=0, background=254): midplane = np.zeros_like(im_segm.get_data()) if direction.lower() == 'axial': midplane[int(midplane.shape[0] / 2), :, :] = background * np.ones_like( midplane[int(midplane.shape[0] / 2), :, :]) for j in range(1, len(intercepts) - 1): midplane[int(midplane.shape[0]/2), :, intercepts[j]:intercepts[j]+offset] = \ foreground * np.ones_like(midplane[int(midplane.shape[0]/2), :, intercepts[j]:intercepts[j]+offset]) elif direction.lower() == 'sagittal': midplane[:, int(midplane.shape[1] / 2), :] = background * np.ones_like( midplane[:, int(midplane.shape[1] / 2), :]) for j in range(1, len(intercepts) - 1): midplane[intercepts[j]:intercepts[j] + offset, int(midplane.shape[1]/2), :] = \ foreground * np.ones_like(midplane[intercepts[j]:intercepts[j] + offset, int(midplane.shape[1]/2), :]) elif direction.lower() == 'coronal': midplane[int(midplane.shape[0] / 2), :, :] = background * np.ones_like( midplane[int(midplane.shape[0] / 2), :, :]) for j in range(1, len(intercepts) - 1): midplane[int(midplane.shape[0]/2), intercepts[j]:intercepts[j]+offset, :] = \ foreground * np.ones_like(midplane[int(midplane.shape[0]/2), intercepts[j]:intercepts[j]+offset, :]) else: raise IOError return set_new_data(im_segm, midplane)
def get_rgb_image_from_segmentation_and_label_descriptor( im_segm, ldm, invert_black_white=False, dtype_output=np.int32): """ From the labels descriptor and a nibabel segmentation image. :param im_segm: nibabel segmentation whose labels corresponds to the input labels descriptor. :param ldm: instance of class label descriptor manager. :param dtype_output: data type of the output image. :param invert_black_white: to swap black with white (improving background visualisation). :return: a 4d image, where at each voxel there is the [r, g, b] vector in the fourth dimension. """ labels_in_image = list(np.sort(list(set(im_segm.get_data().flatten())))) if not len(im_segm.shape) == 3: raise IOError('input segmentation must be 3D.') rgb_image_arr = np.ones(list(im_segm.shape) + [3]) for l in ldm.dict_label_descriptor.keys(): if l not in labels_in_image: msg = 'get_corresponding_rgb_image: Label {} present in the label descriptor and not in ' \ 'selected image'.format(l) print(msg) pl = im_segm.get_data() == l rgb_image_arr[pl, :] = ldm.dict_label_descriptor[l][0] if invert_black_white: pl = im_segm.get_data() == 0 rgb_image_arr[pl, :] = np.array([255, 255, 255]) return set_new_data(im_segm, rgb_image_arr, new_dtype=dtype_output)
def normalise_below_labels(im_input, im_segm, labels_list=None, stats=np.median, exclude_first_label=True): """ Normalise the intensities of im_input for the stats obtained of the values found under input labels. :param im_input: nibabel image :param im_segm: nibabel segmentation :param labels_list: list of labels you want to normalise below :param stats: required statistic e.g. np.median :param exclude_first_label: remove the first label from the labels list. :return: divide for the statistics required for only the non-zero values below. """ if labels_list is not None: if exclude_first_label: labels_list = labels_list[1:] mask_data = np.zeros_like(im_segm.get_data(), dtype=np.bool) for label_k in labels_list: mask_data += im_segm.get_data() == label_k else: mask_data = np.zeros_like(im_segm.get_data(), dtype=np.bool) mask_data[im_segm.get_data() > 0] = 1 masked_im_data = np.nan_to_num((mask_data.astype(np.float64) * im_input.get_data().astype(np.float64)).flatten()) non_zero_masked_im_data = masked_im_data[np.where(masked_im_data > 1e-6)] s = stats(non_zero_masked_im_data) assert isinstance(s, float) output_im = set_new_data(im_input, (1 / float(s)) * im_input.get_data()) return output_im
def otsu_thresholding(self, path_to_input_image, path_to_output_segmentation, side='above', return_as_mask=True): """ Binary segmentation with Otsu thresholding parameters from skimage filters. :param path_to_input_image: :param path_to_output_segmentation: :param side: can be 'above' or 'below' if the user requires to mask the values above the Otsu threshold or below. :param return_as_mask: if False it returns the thresholded input image. :return: the method saves the crisp binary segmentation (or the thresholded input image) according to Otsu threshold. """ pfi_input_image = connect_path_tail_head(self.pfo_in, path_to_input_image) input_im = nib.load(pfi_input_image) output_array = otsu_threshold(input_im.get_data(), side=side, return_as_mask=return_as_mask) output_im = set_new_data(input_im, output_array, new_dtype=output_array.dtype) pfi_output_segm = connect_path_tail_head(self.pfo_out, path_to_output_segmentation) nib.save(output_im, pfi_output_segm)
def keep_one_label(self, path_to_input_segmentation, path_to_output_segmentation=None, label_to_keep=1, path_to_input_labels_descriptor=None, path_to_output_labels_descriptor=None): pfi_in, pfi_out = get_pfi_in_pfi_out(path_to_input_segmentation, path_to_output_segmentation, self.pfo_in, self.pfo_out) im_labels = nib.load(pfi_in) data_labels = im_labels.get_data() data_one_label = keep_only_one_label(data_labels, label_to_keep) im_one_label = set_new_data(im_labels, data_one_label) nib.save(im_one_label, pfi_out) if path_to_input_labels_descriptor is not None: pfi_in_ld = connect_path_tail_head(self.pfo_in, path_to_input_labels_descriptor) ldm_input = LdM(pfi_in_ld, labels_descriptor_convention=self.labels_descriptor_convention) ldm_relabelled = ldm_input.keep_one_label(label_to_keep) if path_to_output_labels_descriptor is None: ldm_relabelled.save_label_descriptor(pfi_in_ld) else: pfi_out_ld = connect_path_tail_head(self.pfo_out, path_to_output_labels_descriptor) ldm_relabelled.save_label_descriptor(pfi_out_ld) print('Label {0} kept from image {1} and saved in {2}.'.format(label_to_keep, pfi_in, pfi_out)) return pfi_out
def set_new_data_path(pfi_target_im, pfi_image_where_the_new_data, pfi_result, new_dtype=None, remove_nan=True): # if pfi_image_where_the_new_data == pfi_result: # raise IOError('pfi_image_where_the_new_data must be different from pfi_result to avoid bugs') image = nib.load(pfi_target_im) new_data = nib.load(pfi_image_where_the_new_data).get_data() new_image = set_new_data(image, new_data, new_dtype=new_dtype, remove_nan=remove_nan) nib.save(new_image, filename=pfi_result)
def segmentation_separator(pfi_segm_input, pfi_segm_output): im_seg = nib.load(pfi_segm_input) data_seg_new = relabel_half_side_one_label(im_seg.get_data(), 213, 214, 'above', 'x', 159) im_seg_new = set_new_data(im_seg, data_seg_new) nib.save(im_seg_new, pfi_segm_output)
def test_set_new_data_for_nifti2(): im_0 = nib.Nifti2Image(np.zeros([3, 3, 3]), affine=np.eye(4)) new_data = np.ones([5, 5, 5]) new_im_nifti2 = set_new_data(im_0, new_data) hd = new_im_nifti2.header assert hd['sizeof_hdr'] == 540
def create_stack_for_labels_fusion(self, pfi_target, pfi_result, list_pfi_segmentations, list_pfi_warped=None, seg_output_name='res_4d_seg', warp_output_name='res_4d_warp', output_tag=''): """ Stack and fuse anatomical images and segmentations in a single command. :param pfi_target: path to file to the target of the segmentation :param pfi_result: path to file where to store the result. :param list_pfi_segmentations: list of the segmentations to fuse :param list_pfi_warped: list of the warped images to fuse :param seg_output_name: :param warp_output_name: :param output_tag: additional tag output. :return: if prepare_data_only is True it returns the path to files prepared to be provided to nifty_seg, in the following order [pfi_target, pfi_result, pfi_4d_seg, pfi_4d_warp] """ pfi_target = connect_path_tail_head(self.pfo_in, pfi_target) pfi_result = connect_path_tail_head(self.pfo_out, pfi_result) # save 4d segmentations in stack_seg list_pfi_segmentations = [connect_path_tail_head(self.pfo_in, j) for j in list_pfi_segmentations] # list_stack_seg = [nib.load(pfi).get_data() for pfi in list_pfi_segmentations] stack_seg = np.stack(list_stack_seg, axis=3) del list_stack_seg im_4d_seg = set_new_data(nib.load(list_pfi_segmentations[0]), stack_seg) pfi_4d_seg = connect_path_tail_head(self.pfo_out, '{0}_{1}.nii.gz'.format(seg_output_name, output_tag)) nib.save(im_4d_seg, pfi_4d_seg) # save 4d warped if available if list_pfi_warped is None: pfi_4d_warp = None else: list_pfi_warped = [connect_path_tail_head(self.pfo_in, j) for j in list_pfi_warped] # list_stack_warp = [nib.load(pfi).get_data() for pfi in list_pfi_warped] stack_warp = np.stack(list_stack_warp, axis=3) del list_stack_warp im_4d_warp = set_new_data(nib.load(list_pfi_warped[0]), stack_warp) pfi_4d_warp = connect_path_tail_head(self.pfo_out, '{0}_{1}.nii.gz'.format(warp_output_name, output_tag)) nib.save(im_4d_warp, pfi_4d_warp) return pfi_target, pfi_result, pfi_4d_seg, pfi_4d_warp
def reproduce_slice_fourth_dimension(nib_image, num_slices=10, repetition_axis=3): im_sh = nib_image.shape if not (len(im_sh) == 2 or len(im_sh) == 3): raise IOError('Methods can be used only for 2 or 3 dim images. No conflicts with existing multi, slices') new_data = np.stack([nib_image.get_data(), ] * num_slices, axis=repetition_axis) output_im = set_new_data(nib_image, new_data) return output_im
def flip_data_path(input_im_path, output_im_path, axis='x'): # wrap flip data, having path for inputs and outputs. if not os.path.isfile(input_im_path): raise IOError('input image file does not exist.') im_labels = nib.load(input_im_path) data_labels = im_labels.get_data() data_flipped = flip_data(data_labels, axis_direction=axis) im_relabelled = set_new_data(im_labels, data_flipped) nib.save(im_relabelled, output_im_path)
def cut_dwi_image_from_first_slice_mask(input_dwi, input_mask): data_masked_dw = np.zeros(input_dwi.shape, dtype=input_dwi.get_data_dtype()) print data_masked_dw.shape for t in range(input_dwi.shape[-1]): print 'cut_dwi_image_from_first_slice_mask, slice processed: ' + str(t) data_masked_dw[..., t] = np.multiply(input_mask.get_data(), input_dwi.get_data()[..., t]) # image with header of the dwi and values under the mask for each slice: return set_new_data(input_dwi, data_masked_dw)
def test_set_new_data_new_data_type(): im_0 = nib.Nifti1Image(np.zeros([3, 3, 3], dtype=np.uint8), affine=np.eye(4)) assert im_0.get_data_dtype() == 'uint8' # check again the original had not changed new_data = np.zeros([3, 3, 3], dtype=np.float64) new_im = set_new_data(im_0, new_data) assert new_im.get_data_dtype() == '<f8' new_data = np.zeros([3, 3, 3], dtype=np.uint8) new_im_update_data = set_new_data(im_0, new_data, new_dtype=np.float64) assert new_im_update_data.get_data_dtype() == '<f8' new_data = np.zeros([3, 3, 3], dtype=np.float64) new_im_update_data = set_new_data(im_0, new_data, new_dtype=np.float64) assert new_im_update_data.get_data_dtype() == '<f8' # check again the original had not changed assert im_0.get_data_dtype() == 'uint8'
def filter_connected_components_by_volume(im_input, num_cc_to_filter=10): """ Given a mask image (volex values are integers from 1 to something), it takes the num_cc_to_filter with maximal volume and it relabels them from 1 to num_cc_to_filter, where 1 is the component with the biggest volume. If components are connected then it will provides the first num_cc_to_filter connected components divided by volumes. :param im_input: mask :param num_cc_to_filter: :return: """ im_data = im_input.get_data().astype(np.int32) new_data = np.zeros_like(im_data) volumes_per_label = [ 0, ] * np.max(im_data) print np.max(im_data) dim_x, dim_y, dim_z = list(im_data.shape) for i in xrange(dim_x): for j in xrange(dim_y): for k in xrange(dim_z): if im_data[i, j, k] > 0: volumes_per_label[im_data[i, j, k] - 1] += 1 list_volumes_copy = volumes_per_label[:] max_volumes = [] max_labels = [] for m in range(num_cc_to_filter): max_value = max(list_volumes_copy) max_index = list_volumes_copy.index(max_value) max_volumes += [max_value] max_labels += [max_index + 1] list_volumes_copy[max_index] = 0 print print m print list_volumes_copy for i in xrange(dim_x): for j in xrange(dim_y): for k in xrange(dim_z): if im_data[i, j, k] in max_labels: new_data[i, j, k] = max_labels.index(im_data[i, j, k]) + 1 im_output = set_new_data(im_input, new_data) return im_output
def mahalanobis_distance_map(im, im_mask=None, trim=False): """ From an image to its Mahalanobis distance map :param im: input image acquired with some modality. :param im_mask: considering only the data below the given mask. :param trim: if mask is provided the output image is masked with zeros values outside the mask. :return: nibabel image same shape as im, with the corresponding Mahalanobis map """ if im_mask is None: mu = np.mean(im.get_data().flatten()) sigma2 = np.std(im.get_data().flatten()) return set_new_data(im, np.sqrt((im.get_data() - mu) * sigma2 * (im.get_data() - mu))) else: np.testing.assert_array_equal(im.affine, im_mask.affine) np.testing.assert_array_equal(im.shape, im_mask.shape) mu = np.mean(im.get_data().flatten() * im_mask.get_data().flatten()) sigma2 = np.std(im.get_data().flatten() * im_mask.get_data().flatten()) new_data = np.sqrt((im.get_data() - mu) * sigma2**(-1) * (im.get_data() - mu)) if trim: new_data = new_data * im_mask.get_data().astype(np.bool) return set_new_data(im, new_data)
def segmentation_disjoint_union(im_segm1, im_segm2): assert im_segm1.shape == im_segm2.shape where_segmentation_1 = im_segm1.get_data() > 0 where_segmentation_2 = im_segm2.get_data() > 0 where_segmentation_1_and_2 = where_segmentation_1 * where_segmentation_2 new_data = copy.deepcopy(im_segm1.get_data()) new_data = new_data * np.logical_not(where_segmentation_1_and_2).astype( np.int) new_data = new_data + im_segm2.get_data() return set_new_data(im_segm1, new_data)
def stack_images(list_images): """ From a list of images of the same shape, the stack of these images in the new dimension. :param list_images: :return: stack image of the input list """ msg = 'input images shapes are not all of the same dimension' assert False not in [ list_images[0].shape == im.shape for im in list_images[1:] ], msg new_data = np.stack([nib_image.get_data() for nib_image in list_images], axis=len(list_images[0].shape)) stack_im = set_new_data(list_images[0], new_data) return stack_im
def merge_from_4d(self, pfi_input, pfi_output=None): pfi_in, pfi_out = get_pfi_in_pfi_out(pfi_input, pfi_output, self.pfo_in, self.pfo_out) im_labels_4d = nib.load(pfi_in) data_labels_4d = im_labels_4d.get_data() assert len(data_labels_4d.shape) == 4 data_merged_in_3d = merge_labels_from_4d(data_labels_4d) im_merged_in_3d = set_new_data(im_labels_4d, data_merged_in_3d) nib.save(im_merged_in_3d, pfi_out) print('Merged labels from 4d image {0} saved in {1}.'.format( pfi_in, pfi_out)) return pfi_out
def binarise_and_adjust_mask_from_segmentation_path(pfi_segm_input, pfi_mask_output, pfo_temp, subject_name, labels_to_exclude=(), dil_factor=1, ero_factor=1): """ Sequence of topological operation to pass from the manual segmentation to a single binary mask covering the brain tissue and excluding the skull. :param pfi_segm_input: :param pfi_mask_output: :param pfo_temp: :param subject_name: :param labels_to_exclude: :param dil_factor: dilation factor before erosion :param ero_factor: erosion factor after dilation :return: """ pfi_intermediate = jph(pfo_temp, '{}_tmp_binarisation.nii.gz'.format(subject_name)) print_and_run('cp {} {}'.format(pfi_segm_input, pfi_intermediate)) if len(labels_to_exclude) > 0: im_segm = nib.load(pfi_intermediate) array_segm_new_data = relabeller(im_segm.get_data(), list_old_labels=labels_to_exclude, list_new_labels=[ 0, ] * len(labels_to_exclude)) im_segm_new = set_new_data(im_segm, array_segm_new_data) nib.save(im_segm_new, pfi_intermediate) print_and_run('seg_maths {0} -bin {0}'.format(pfi_intermediate)) # fill and dil the binarised segmentation print_and_run('seg_maths {0} -fill {1}'.format(pfi_intermediate, pfi_intermediate)) print_and_run('seg_maths {0} -dil {1} {0}'.format(pfi_intermediate, dil_factor)) print_and_run('seg_maths {0} -ero {1} {0}'.format(pfi_intermediate, ero_factor)) # print_and_run('seg_maths {0} -fill {0}'.format(pfi_intermediate)) print_and_run('seg_maths {0} -fill {1}'.format(pfi_intermediate, pfi_mask_output))
def symmetrise_axial(self, filename_in, filename_out=None, axis='x', plane_intercept=10, side_to_copy='below', keep_in_data_dimensions=True): pfi_in, pfi_out = get_pfi_in_pfi_out(filename_in, filename_out, self.pfo_in, self.pfo_out) im_segm = nib.load(pfi_in) data_labels = im_segm.get_data() data_symmetrised = symmetrise_data(data_labels, axis_direction=axis, plane_intercept=plane_intercept, side_to_copy=side_to_copy, keep_in_data_dimensions_boundaries=keep_in_data_dimensions) im_symmetrised = set_new_data(im_segm, data_symmetrised) nib.save(im_symmetrised, pfi_out) print('Symmetrised axis {0}, plane_intercept {1}, image of {2} saved in {3}.'.format(axis, plane_intercept, pfi_in, pfi_out)) return pfi_out
def substitute_volume_at_timepoint(im_input_4d, im_input_3d, timepoint): """ Substitute the im_input_3d image at the time point timepoint of the im_input_4d. :param im_input_4d: 4d image :param im_input_3d: 3d image whose shape is compatible with the fist 3 dimensions of im_input_4d :param timepoint: a timepoint in the 4th dimension of the im_input_4d :return: im_input_4d whose at the timepoint-th time point the data of im_input_3d are stored. Handle base case: If the input 4d volume is actually a 3d and timepoint is 0, then just return the same volume. """ if len(im_input_4d.shape) == 3 and timepoint == 0: return im_input_3d elif len(im_input_4d.shape) == 4 and timepoint < im_input_4d.shape[-1]: new_data = im_input_4d.get_data()[:] new_data[..., timepoint] = im_input_3d.get_data()[:] return set_new_data(im_input_4d, new_data) else: raise IOError('Incompatible shape input volume.')
def test_set_new_data_simple_modifications(): aff = np.eye(4) aff[2, 1] = 42.0 im_0 = nib.Nifti1Image(np.zeros([3, 3, 3]), affine=aff) im_0_header = im_0.header # default intent_code assert im_0_header['intent_code'] == 0 # change intento code im_0_header['intent_code'] = 5 # generate new nib from the old with new data im_1 = set_new_data(im_0, np.ones([3, 3, 3])) im_1_header = im_1.header # see if the infos are the same as in the modified header assert_array_equal(im_1.get_data()[:], np.ones([3, 3, 3])) assert im_1_header['intent_code'] == 5 assert_array_equal(im_1.affine, aff)
def get_probabilistic_prior_from_stack_segmentations(self, path_to_stack_crisp_segm, path_to_fuzzy_output): pfi_in, pfi_out = get_pfi_in_pfi_out(path_to_stack_crisp_segm, path_to_fuzzy_output, self.pfo_in, self.pfo_out) im_stack_crisp = nib.load(path_to_stack_crisp_segm) dims = im_stack_crisp.shape vec = [np.prod(im_stack_crisp.shape[:3])] + [dims[3]] array_output = from_segmentations_stack_to_probabilistic_segmentation( im_stack_crisp.get_data().reshape(vec).T).T data_output = array_output.reshape(list(im_stack_crisp.shape[:3]) + [array_output.shape[1]]) new_im = set_new_data(im_stack_crisp, data_output, new_dtype=np.float64) nib.save(new_im, pfi_out) return pfi_out
def extend_slice_new_dimension(self, pfi_input, pfi_output=None, new_axis=3, num_slices=10): pfi_in, pfi_out = get_pfi_in_pfi_out(pfi_input, pfi_output, self.pfo_in, self.pfo_out) im_slice = nib.load(pfi_in) data_slice = im_slice.get_data() data_extended = np.stack([ data_slice, ] * num_slices, axis=new_axis) im_extended = set_new_data(im_slice, data_extended) nib.save(im_extended, pfi_out) print('Extended image of {0} saved in {1}.'.format(pfi_in, pfi_out)) return pfi_out