Ejemplo n.º 1
0
    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 get_grafting(self,
                     pfi_input_hosting_mould,
                     pfi_input_patch,
                     pfi_output_grafted,
                     pfi_input_patch_mask=None):
        """
        :param pfi_input_hosting_mould: base image where the grafting should happen
        :param pfi_input_patch: patch to be grafted in the hosting_mould
        :param pfi_output_grafted: output image with the grafting
        :param pfi_input_patch_mask: optional additional mask, where the grafting will take place.
        :return:
        """
        pfi_hosting = connect_path_tail_head(self.pfo_in,
                                             pfi_input_hosting_mould)
        pfi_patch = connect_path_tail_head(self.pfo_in, pfi_input_patch)

        im_hosting = nib.load(pfi_hosting)
        im_patch = nib.load(pfi_patch)
        im_mask = None

        if pfi_input_patch_mask is not None:
            pfi_mask = connect_path_tail_head(self.pfo_in,
                                              pfi_input_patch_mask)
            im_mask = nib.load(pfi_mask)

        im_grafted = grafting(im_hosting, im_patch, im_patch_mask=im_mask)

        pfi_output = connect_path_tail_head(self.pfo_out, pfi_output_grafted)
        nib.save(im_grafted, pfi_output)
Ejemplo n.º 3
0
    def global_dist(self,
                    segm_1_filename,
                    segm_2_filename,
                    where_to_save=None,
                    global_metrics=(global_outline_error, global_dice_score)):

        pfi_segm1 = connect_path_tail_head(self.pfo_in, segm_1_filename)
        pfi_segm2 = connect_path_tail_head(self.pfo_in, segm_2_filename)

        assert os.path.exists(pfi_segm1), pfi_segm1
        assert os.path.exists(pfi_segm2), pfi_segm2

        if self.verbose > 0:
            print(
                "\nGlobal distances between segmentations: \n -> {0} \n -> {1} "
                "\nComputations started!".format(pfi_segm1, pfi_segm2))

        im_segm1 = nib.load(pfi_segm1)
        im_segm2 = nib.load(pfi_segm2)

        se_global_distances = pa.Series(
            np.array([d(im_segm1, im_segm2) for d in global_metrics]),
            index=[d.__name__ for d in global_metrics])
        if where_to_save is not None:
            where_to_save = connect_path_tail_head(self.pfo_out, where_to_save)
            se_global_distances.to_pickle(where_to_save)

        return se_global_distances
Ejemplo n.º 4
0
    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
Ejemplo n.º 5
0
    def from_segmentation_and_labels_descriptor_to_rgb(self, path_to_input_segmentation,
                                                       path_to_input_txt_labels_descriptor,
                                                       path_to_output_4d_rgb_image,
                                                       invert_black_white=False, dtype_output=np.int32):
        """
        + Masks of :func:`nilabel.tools.image_colors_manipulations.segmentation_to_rgb.
        get_rgb_image_from_segmentation_and_label_descriptor` using filenames.
        From a segmentation and its label descriptro in itk-snap convention or in fsl convention
        it creates a corresponding 4d image with the 3 R G B channels in the fourth dimension.
        :param path_to_input_segmentation: path to the input segmentation
        :param path_to_input_txt_labels_descriptor: path to the txt labels descriptor
        :param path_to_output_4d_rgb_image: path where to save the output
        :param invert_black_white: changes the background colour, if black to white.
        :param dtype_output: data type of the output np.int32
        :return:
        """
        pfi_segm = connect_path_tail_head(self.pfo_in, path_to_input_segmentation)
        pfi_ld = connect_path_tail_head(self.pfo_in, path_to_input_txt_labels_descriptor)

        im_segm = nib.load(pfi_segm)
        ldm = LdM(pfi_ld, labels_descriptor_convention=self.labels_descriptor_convention)
        im_rgb_4d_image = get_rgb_image_from_segmentation_and_label_descriptor(im_segm, ldm,
                                                                               invert_black_white=invert_black_white,
                                                                               dtype_output=dtype_output)

        pfi_out = connect_path_tail_head(self.pfo_out, path_to_output_4d_rgb_image)
        nib.save(im_rgb_4d_image, pfi_out)
Ejemplo n.º 6
0
    def modify_translational_part(self, filename_in, filename_out, new_translation):
        """
        :param filename_in: path to filename input
        :param filename_out: path to filename output
        :param new_translation: translation that will replace the existing one.
        :return:
        """
        pfi_in, pfi_out = get_pfi_in_pfi_out(filename_in, filename_out, self.pfo_in, self.pfo_out)
        im = nib.load(pfi_in)

        if isinstance(new_translation, str):

            if new_translation.endswith('.txt'):
                tr = np.loadtxt(connect_path_tail_head(self.pfo_in, new_translation))
            else:
                tr = np.load(connect_path_tail_head(self.pfo_in, new_translation))

        elif isinstance(new_translation, np.ndarray):
            tr = new_translation
        elif isinstance(new_translation, list):
            tr = np.array(new_translation)
        else:
            raise IOError('parameter new_translation can be path to an affine matrix .txt or .npy or the numpy array'
                          'corresponding to the new intended translational part.')

        new_im = replace_translational_part(im, tr)
        nib.save(new_im, pfi_out)
Ejemplo n.º 7
0
 def volume(self,
            segmentation_filename,
            labels=None,
            tot_volume_prior=None,
            where_to_save=None):
     """
     :param segmentation_filename: filename of the segmentation S.
     :param labels: list of labels, multi-labels (as sublists, e.g. left right will be considered one label)
     :param tot_volume_prior: as an intra-cranial volume factor.
     :param where_to_save:
     :return:
     """
     pfi_segm = connect_path_tail_head(self.pfo_in, segmentation_filename)
     assert os.path.exists(pfi_segm), pfi_segm
     im_segm = nib.load(pfi_segm)
     labels_list, labels_names = labels_query(labels, im_segm.get_data())
     df_volumes_per_label = get_volumes_per_label(
         im_segm,
         labels=labels_list,
         labels_names=labels_names,
         tot_volume_prior=tot_volume_prior,
         verbose=self.verbose)
     if self.verbose > 0:
         print(df_volumes_per_label)
     if where_to_save is not None:
         pfi_output_table = connect_path_tail_head(self.pfo_out,
                                                   where_to_save)
         df_volumes_per_label.to_pickle(pfi_output_table)
     return df_volumes_per_label
Ejemplo n.º 8
0
    def modify_affine(self, filename_in, affine_in, filename_out, q_form=True, s_form=True,
                      multiplication_side='left'):
        """
        Modify the affine transformation by substitution or by left or right multiplication
        :param filename_in: path to filename input
        :param affine_in: path to affine matrix input, or nd.array or .npy array
        :param filename_out: path to filename output
        :param q_form: affect the q_form (True)
        :param s_form: affect the s_form (True)
        :param multiplication_side: multiplication_side: can be lef, right, or replace.
        :return: save new image with the updated affine transformation

        NOTE: please see the documentation http://nipy.org/nibabel/nifti_images.html#choosing-image-affine for more on the
        relationships between s_form affine, q_form affine and fall-back header affine.
        """
        pfi_in, pfi_out = get_pfi_in_pfi_out(filename_in, filename_out, self.pfo_in, self.pfo_out)

        if isinstance(affine_in, str):

            if affine_in.endswith('.txt'):
                aff = np.loadtxt(connect_path_tail_head(self.pfo_in, affine_in))
            else:
                aff = np.load(connect_path_tail_head(self.pfo_in, affine_in))

        elif isinstance(affine_in, np.ndarray):
            aff = affine_in
        else:
            raise IOError('parameter affine_in can be path to an affine matrix .txt or .npy or the numpy array'
                          'corresponding to the affine transformation.')

        im = nib.load(pfi_in)
        new_im = modify_affine_transformation(im, aff, q_form=q_form, s_form=s_form,
                                              multiplication_side=multiplication_side)
        nib.save(new_im, pfi_out)
def test_connect_tail_head_path():
    # Case 1:
    assert connect_path_tail_head('as/df/gh', 'lm.txt') == 'as/df/gh/lm.txt'
    # Case 2:
    assert connect_path_tail_head('as/df/gh', 'as/df/gh/lm/nb.txt') == 'as/df/gh/lm/nb.txt'
    # Case 3:
    assert connect_path_tail_head('as/df/gh', 'lm/nb.txt') == 'as/df/gh/lm/nb.txt'
Ejemplo n.º 10
0
    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)
Ejemplo n.º 11
0
    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)
Ejemplo n.º 12
0
    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
Ejemplo n.º 13
0
    def dist(self,
             segm_1_filename,
             segm_2_filename,
             labels_list=None,
             labels_names=None,
             metrics=(dice_score, covariance_distance, hausdorff_distance,
                      normalised_symmetric_contour_distance),
             where_to_save=None):

        pfi_segm1 = connect_path_tail_head(self.pfo_in, segm_1_filename)
        pfi_segm2 = connect_path_tail_head(self.pfo_in, segm_2_filename)
        assert os.path.exists(pfi_segm1), pfi_segm1
        assert os.path.exists(pfi_segm2), pfi_segm2

        if self.verbose > 0:
            print(
                "Distances between segmentations: \n -> {0} \n -> {1} \n...started!"
                .format(pfi_segm1, pfi_segm2))

        im_segm1 = nib.load(pfi_segm1)
        im_segm2 = nib.load(pfi_segm2)
        if labels_list is None:
            labels_list1, labels_names1 = labels_query('all',
                                                       im_segm1.get_data())
            labels_list2, labels_names2 = labels_query('all',
                                                       im_segm2.get_data())
            labels_list = list(set(labels_list1) & set(labels_list2))
            labels_list.sort(key=int)
            labels_names = None

        if labels_names is None:
            labels_names = labels_list

        dict_distances_per_label = {}

        for d in metrics:
            if self.verbose > 0:
                print('{} computation started'.format(d.func_name))
            pa_se = d(
                im_segm1, im_segm2, labels_list, labels_names, self.return_mm3
            )  # TODO get as function with variable number of arguments
            dict_distances_per_label.update({d.func_name: pa_se})

        df_distances_per_label = pa.DataFrame(
            dict_distances_per_label, columns=dict_distances_per_label.keys())

        # df_distances_per_label.loc['mean'] = df_distances_per_label.mean()
        # df_distances_per_label.loc['std'] = df_distances_per_label.std()

        if self.verbose > 0:
            print(df_distances_per_label)

        if where_to_save is not None:
            pfi_output_table = connect_path_tail_head(self.pfo_out,
                                                      where_to_save)
            df_distances_per_label.to_pickle(pfi_output_table)

        return df_distances_per_label
Ejemplo n.º 14
0
    def stack_list_pfi_images(self, list_pfi_input, pfi_output):
        list_pfi_in = [
            connect_path_tail_head(self.pfo_in, p) for p in list_pfi_input
        ]
        pfi_out = connect_path_tail_head(self.pfo_out, pfi_output)

        list_im = [nib.load(p) for p in list_pfi_in]
        stack_im = stack_images(list_im)

        nib.save(stack_im, pfi_out)
Ejemplo n.º 15
0
 def missing_labels(self,
                    path_input_segmentation,
                    path_input_labels_descriptor,
                    pfi_where_to_save_the_log_file=None):
     pfi_segm = connect_path_tail_head(self.pfo_in, path_input_segmentation)
     pfi_ld = connect_path_tail_head(self.pfo_in,
                                     path_input_labels_descriptor)
     ldm = LabelsDescriptorManager(pfi_ld)
     im_se = nib.load(pfi_segm)
     in_descriptor_not_delineated, delineated_not_in_descriptor = \
         check_missing_labels(im_se, ldm, pfi_where_log=pfi_where_to_save_the_log_file)
     return in_descriptor_not_delineated, delineated_not_in_descriptor
Ejemplo n.º 16
0
    def normalise_below_label(self,
                              filename_image_in,
                              filename_image_out,
                              filename_segm,
                              labels,
                              stats=np.median):
        """

        :param filename_image_in: path to image input
        :param filename_image_out: path to image output
        :param filename_segm: path to segmentation
        :param labels: list of labels below which the voxels are collected
        :param stats: a statistics (by default the median).
        :return: a new image with the intensites normalised according to the proposed statistics computed on the
        intensities below the provided labels.
        """
        pfi_in, pfi_out = get_pfi_in_pfi_out(filename_image_in,
                                             filename_image_out, self.pfo_in,
                                             self.pfo_out)
        pfi_segm = connect_path_tail_head(self.pfo_in, filename_segm)

        im_input = nib.load(pfi_in)
        im_segm = nib.load(pfi_segm)

        labels_list, labels_names = labels_query(labels, im_segm.get_data())
        im_out = normalise_below_labels(im_input,
                                        labels_list,
                                        labels,
                                        stats=stats,
                                        exclude_first_label=True)

        nib.save(im_out, pfi_out)
Ejemplo n.º 17
0
    def values_below_labels(self,
                            segmentation_filename,
                            anatomy_filename,
                            labels=None):
        """
        :param segmentation_filename:
        :param anatomy_filename:
        :param labels:
        :return: pandas series with label names and corresponding vectors of labels values
        """
        pfi_anat = connect_path_tail_head(self.pfo_in, anatomy_filename)
        pfi_segm = connect_path_tail_head(self.pfo_in, segmentation_filename)
        assert os.path.exists(pfi_anat)
        assert os.path.exists(pfi_segm)
        im_anat = nib.load(pfi_anat)
        im_segm = nib.load(pfi_segm)

        labels_list, labels_names = labels_query(
            labels, segmentation_array=im_segm.get_data())
        labels_values = get_values_below_labels_list(im_segm, im_anat,
                                                     labels_list)
        return pa.Series(labels_values, index=labels_names)
Ejemplo n.º 18
0
    def assign_all_other_labels_the_same_value(self, path_to_input_segmentation, path_to_output_segmentation=None,
                                               labels_to_keep=(), same_value_label=255,
                                               path_to_input_labels_descriptor=None,
                                               path_to_output_labels_descriptor=None):
        """
        :param path_to_input_segmentation:
        :param path_to_output_segmentation:
        :param labels_to_keep:
        :param same_value_label:
        :param path_to_input_labels_descriptor:
        :param path_to_output_labels_descriptor:
        :return:
        """
        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_reassigned = assign_all_other_labels_the_same_value(data_labels,
                                labels_to_keep=labels_to_keep, same_value_label=same_value_label)

        im_reassigned = set_new_data(im_labels, data_reassigned)
        nib.save(im_reassigned, 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.assign_all_other_labels_the_same_value(labels_to_keep=labels_to_keep,
                                                                              same_value_label=same_value_label)

            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('Reassigned labels from image {0} saved in {1}.'.format(pfi_in, pfi_out))
        return pfi_out
Ejemplo n.º 19
0
    def crop_outside_mask(self, filename_input_image, filename_mask,
                          filename_output_image_masked):
        """
        Set to zero all the values outside the mask.
        Adaptative - if the mask is 3D and the image is 4D, will create a temporary mask,
        generate the stack of masks, and apply the stacks to the image.
        :param filename_input_image: path to file 3d x T image
        :param filename_mask: 3d mask same dimension as the 3d of the pfi_input
        :param filename_output_image_masked: apply the mask to each time point T in the fourth dimension if any.
        :return: None, it saves the output in pfi_output.
        """
        pfi_in, pfi_out = get_pfi_in_pfi_out(filename_input_image,
                                             filename_output_image_masked,
                                             self.pfo_in, self.pfo_out)

        pfi_mask = connect_path_tail_head(self.pfo_in, filename_mask)

        im_in, im_mask = nib.load(pfi_in), nib.load(pfi_mask)
        im_masked = apply_a_mask_nib(im_in, im_mask)

        pfi_output = connect_path_tail_head(self.pfo_out,
                                            filename_output_image_masked)
        nib.save(im_masked, pfi_output)
Ejemplo n.º 20
0
    def cut_4d_volume_with_a_1_slice_mask(self,
                                          pfi_input,
                                          filename_mask,
                                          pfi_output=None):
        pfi_in, pfi_out = get_pfi_in_pfi_out(pfi_input, pfi_output,
                                             self.pfo_in, self.pfo_out)
        pfi_mask = connect_path_tail_head(self.pfo_in, filename_mask)

        im_dwi = nib.load(pfi_in)
        im_mask = nib.load(pfi_mask)

        im_masked = cut_4d_volume_with_a_1_slice_mask_nib(im_dwi, im_mask)

        nib.save(im_masked, pfi_out)
Ejemplo n.º 21
0
 def number_connected_components_per_label(self,
                                           input_segmentation,
                                           where_to_save_the_log_file=None):
     pfi_segm = connect_path_tail_head(self.pfo_in, input_segmentation)
     im = nib.load(pfi_segm)
     msg = 'Labels check number of connected components for segmentation {} \n\n'.format(
         pfi_segm)
     labs_list, cc_list = [], []
     for lab in sorted(list(set(im.get_data().flat))):
         cc = ndimage.label(im.get_data() == lab)[1]
         msg_l = 'Label {} has {} connected components'.format(lab, cc)
         print(msg_l)
         msg += msg_l + '\n'
         labs_list.append(lab)
         cc_list.append(cc)
     if where_to_save_the_log_file is not None:
         f = open(where_to_save_the_log_file, 'w')
         f.write(msg)
         f.close()
     return labs_list, cc_list
Ejemplo n.º 22
0
    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
Ejemplo n.º 23
0
 def compare_two_nifti_images(self, path_first_image, path_second_image):
     pfi_first = connect_path_tail_head(self.pfo_in, path_first_image)
     pfi_second = connect_path_tail_head(self.pfo_in, path_second_image)
     im1 = nib.load(pfi_first)
     im2 = nib.load(pfi_second)
     return compare_two_nib(im1, im2)
Ejemplo n.º 24
0
    def mixture_of_gaussians(self,
                             path_to_input_image,
                             path_to_output_segmentation_crisp,
                             path_to_output_segmentation_prob,
                             K=None,
                             mask_im=None,
                             pre_process_median_filter=False,
                             pre_process_only_interquartile=False,
                             see_histogram=None,
                             reorder_mus=True,
                             output_dtype_crisp=np.uint16,
                             output_dtype_prob=np.float32):
        """
        Wrap of MoG_array for nibabel images.
        -----
        :param path_to_input_image: path to input image format to be segmented with a MOG method.
        :param path_to_output_segmentation_crisp: path to output crisp segmentation
        :param path_to_output_segmentation_prob: path to probabilistic output segmentation
        :param K: number of classes, if None, it is estimated with a BIC criterion (may take a while)
        :param mask_im: nibabel mask if you want to consider only a subset of the masked data.
        :param pre_process_median_filter: apply a median filter before pre-processing (reduce salt and pepper noise).
        :param pre_process_only_interquartile: set to zero above and below interquartile in the data.
        :param see_histogram: can be True, False (or None) or a string (with a path where to save the plotted
                              histogram).
        :param reorder_mus: only if output_gmm_class=False, reorder labels from smallest to bigger means.
        :param output_dtype_crisp: data type output crisp segmentation (uint16)
        :param output_dtype_prob: data type output probabilistic segmentation (float32)
        :return: save crisp and probabilistic segmentation at the specified files after sklearn.mixture.GaussianMixture
        """

        pfi_input_image = connect_path_tail_head(self.pfo_in,
                                                 path_to_input_image)

        input_im = nib.load(pfi_input_image)
        if mask_im is not None:
            mask_array = mask_im.get_data()
        else:
            mask_array = None

        ans = MoG_array(
            input_im.get_data(),
            K=K,
            mask_array=mask_array,
            pre_process_median_filter=pre_process_median_filter,
            pre_process_only_interquartile=pre_process_only_interquartile,
            output_gmm_class=False,
            see_histogram=see_histogram,
            reorder_mus=reorder_mus)

        crisp, prob = ans[0], ans[1]

        im_crisp = set_new_data(input_im, crisp, new_dtype=output_dtype_crisp)
        im_prob = set_new_data(input_im, prob, new_dtype=output_dtype_prob)

        pfi_im_crisp = connect_path_tail_head(
            self.pfo_out, path_to_output_segmentation_crisp)
        pfi_im_prob = connect_path_tail_head(self.pfo_out,
                                             path_to_output_segmentation_prob)

        nib.save(im_crisp, pfi_im_crisp)
        nib.save(im_prob, pfi_im_prob)
Ejemplo n.º 25
0
    def symmetrise_with_registration(self,
                                     filename_anatomy,
                                     filename_segmentation,
                                     list_labels_input,
                                     result_img_path,
                                     results_folder_path=None,
                                     list_labels_transformed=None,
                                     coord='z',
                                     reuse_registration=False):
        """
        Symmetrise a segmentation with registration: it uses NiftyReg.
        The old side is symmetrised in the new side, with new relabelling.
        Method based on paths even if in tools
        :param filename_anatomy: Path to File anatomical image
        :param filename_segmentation: Path to File segmentation of the anatomical image
        :param results_folder_path: Path to FOlder where intermediate results are stored
        :param result_img_path: Path to File symmetrised segmentation
        :param list_labels_input: labels that will be taken into account in the symmetrisation from the old side.
        :param list_labels_transformed: corresponding labels in the same order. If None, labels of the new side
        will be kept with the same numbering in the new side.
        :param reuse_registration: if a registration is already present in the pfo_results, and you only need to change the
        labels value, it will spare you some time when set to True.
        :param coord: coordinate of the registration: in RAS, 'z' will symmetrise Left on Right.
        :return: symmetrised segmentation.
        ---
        NOTE: requires niftyreg.
        """

        pfi_in_anatomy = connect_path_tail_head(self.pfo_in, filename_anatomy)
        pfi_in_segmentation = connect_path_tail_head(self.pfo_in, filename_segmentation)

        if results_folder_path is None:
            if self.pfo_out is not None:
                results_folder_path = self.pfo_out
            else:
                results_folder_path = self.pfo_in
        else:
            results_folder_path = os.path.dirname(pfi_in_segmentation)

        pfi_out_segmentation = connect_path_tail_head(results_folder_path, result_img_path)

        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)

        # side A is the input, side B is the one where we want to symmetrise.
        # --- Initialisation  --- #

        # check input:
        if not os.path.isfile(pfi_in_anatomy):
            raise IOError('input image file {} does not exist.'.format(pfi_in_anatomy))
        if not os.path.isfile(pfi_in_segmentation):
            raise IOError('input segmentation file {} does not exist.'.format(pfi_in_segmentation))

        # erase labels that are not in the list from image and descriptor

        out_labels_side_A_path = os.path.join(results_folder_path, 'z_labels_side_A.nii.gz')
        labels_im = nib.load(pfi_in_segmentation)
        labels_data = labels_im.get_data()
        labels_to_erase = list(set(labels_data.flat) - set(list_labels_input + [0]))

        # Relabel: from pfi_segmentation to out_labels_side_A_path
        im_pfi_segmentation = nib.load(pfi_in_segmentation)

        segmentation_data_relabelled = relabeller(im_pfi_segmentation.get_data(), list_old_labels=labels_to_erase,
                                                  list_new_labels=[0, ] * len(labels_to_erase))
        nib_labels_side_A_path = set_new_data(im_pfi_segmentation, segmentation_data_relabelled)
        nib.save(nib_labels_side_A_path, out_labels_side_A_path)

        # --- Create side B  --- #

        # flip anatomical image and register it over the non flipped
        out_anatomical_flipped_path = os.path.join(results_folder_path, 'z_anatomical_flipped.nii.gz')
        flip_data_path(pfi_in_anatomy, out_anatomical_flipped_path, axis=coord)

        # flip the labels
        out_labels_flipped_path = os.path.join(results_folder_path, 'z_labels_flipped.nii.gz')
        flip_data_path(out_labels_side_A_path, out_labels_flipped_path, axis=coord)

        # register anatomical flipped over non flipped
        out_anatomical_flipped_warped_path = os.path.join(results_folder_path, 'z_anatomical_flipped_warped.nii.gz')
        out_affine_transf_path = os.path.join(results_folder_path, 'z_affine_transformation.txt')

        if not reuse_registration:
            cmd = 'reg_aladin -ref {0} -flo {1} -aff {2} -res {3}'.format(pfi_in_anatomy,
                                                                          out_anatomical_flipped_path,
                                                                          out_affine_transf_path,
                                                                          out_anatomical_flipped_warped_path)
            print('Registration started!\n')
            os.system(cmd)

            # propagate the registration to the flipped labels
            out_labels_side_B_path = os.path.join(results_folder_path, 'z_labels_side_B.nii.gz')
            cmd = 'reg_resample -ref {0} -flo {1} ' \
                  '-res {2} -trans {3} -inter {4}'.format(out_labels_side_A_path,
                                                          out_labels_flipped_path,
                                                          out_labels_side_B_path,
                                                          out_affine_transf_path,
                                                          0)

            print('Resampling started!\n')
            os.system(cmd)
        else:
            out_labels_side_B_path = os.path.join(results_folder_path, 'z_labels_side_B.nii.gz')

        # update labels of the side B if necessarily
        if list_labels_transformed is not None:
            print('relabelling step!')

            assert len(list_labels_transformed) == len(list_labels_input)

            # relabel from out_labels_side_B_path to out_labels_side_B_path
            im_segmentation_side_B = nib.load(out_labels_side_B_path)

            data_segmentation_side_B_new = relabeller(im_segmentation_side_B.get_data(),
                                                      list_old_labels=list_labels_input,
                                                      list_new_labels=list_labels_transformed)
            nib_segmentation_side_B_new = set_new_data(im_segmentation_side_B, data_segmentation_side_B_new)
            nib.save(nib_segmentation_side_B_new, out_labels_side_B_path)

        # --- Merge side A and side B in a single volume according to a criteria --- #
        # out_labels_side_A_path,  out_labels_side_B_path --> result_path.nii.gz

        nib_side_A = nib.load(out_labels_side_A_path)
        nib_side_B = nib.load(out_labels_side_B_path)

        data_side_A = nib_side_A.get_data()
        data_side_B = nib_side_B.get_data()

        symmetrised_data = np.zeros_like(data_side_A)

        # To manage the intersections of labels between old and new side. Vectorize later...
        dims = data_side_A.shape

        print('Pointwise symmetrisation started!')

        for z in range(dims[0]):
            for x in range(dims[1]):
                for y in range(dims[2]):
                    if (data_side_A[z, x, y] == 0 and data_side_B[z, x, y] != 0) or \
                            (data_side_A[z, x, y] != 0 and data_side_B[z, x, y] == 0):
                        symmetrised_data[z, x, y] = np.max([data_side_A[z, x, y], data_side_B[z, x, y]])
                    elif data_side_A[z, x, y] != 0 and data_side_B[z, x, y] != 0:
                        if data_side_A[z, x, y] == data_side_B[z, x, y]:
                            symmetrised_data[z, x, y] = data_side_A[z, x, y]
                        else:
                            symmetrised_data[z, x, y] = 255  # devil label!

        im_symmetrised = set_new_data(nib_side_A, symmetrised_data)
        nib.save(im_symmetrised, pfi_out_segmentation)
Ejemplo n.º 26
0
    def groupwise_global_measures_comparisons(
            self,
            list_path_A,
            list_path_B,
            pfo_where_to_save,
            name_list_path_A=None,
            name_list_path_B=None,
            list_distances=(global_dice_score, global_outline_error),
            prefix_output='distances_comparison',
            save_human_readable=True,
            verbose=1):
        list_path_A = [
            connect_path_tail_head(self.pfo_in, ph) for ph in list_path_A
        ]
        list_path_B = [
            connect_path_tail_head(self.pfo_in, ph) for ph in list_path_B
        ]

        # input sanity check:
        for pfi_im_A in list_path_A:
            assert os.path.exists(pfi_im_A), pfi_im_A
        for pfi_im_B in list_path_B:
            assert os.path.exists(pfi_im_B), pfi_im_B
        if name_list_path_A is None:
            name_list_path_A = [
                os.path.basename(n).replace('.nii', '').replace('.gz', '')
                for n in list_path_A
            ]
        if name_list_path_B is None:
            name_list_path_B = [
                os.path.basename(n).replace('.nii', '').replace('.gz', '')
                for n in list_path_B
            ]

        # Initialise one data-frame for each metric/score selected
        dictionary_of_measurements = {}
        for d in list_distances:
            dictionary_of_measurements.update({
                d.__name__:
                pa.DataFrame(np.zeros([len(list_path_A),
                                       len(list_path_B)]),
                             index=name_list_path_A,
                             columns=name_list_path_B)
            })

        # Fill values in each data-frame
        for pfi_im_A, name_A in zip(list_path_A, name_list_path_A):
            for pfi_im_B, name_B in zip(list_path_B, name_list_path_B):

                im_A = nib.load(pfi_im_A)
                im_B = nib.load(pfi_im_B)
                for d in list_distances:
                    d_A_B = d(im_A, im_B)
                    dictionary_of_measurements[
                        d.__name__][name_B][name_A] = d_A_B
                    if verbose > 0:
                        print('{0:<15} {1:<15} \n{2:<15} : {3}'.format(
                            pfi_im_A, pfi_im_B, d.__name__, d_A_B))
                        print(dictionary_of_measurements[d.__name__])

        # prepare output folder
        os.system('mkdir -p {}'.format(pfo_where_to_save))

        for d in list_distances:
            # Save each dataframe independently
            pfi_df_global_dice_score = os.path.join(
                pfo_where_to_save,
                '{0}_{1}.pickle'.format(prefix_output, d.__name__))
            dictionary_of_measurements[d.__name__].to_pickle(
                pfi_df_global_dice_score)
            if save_human_readable:
                pfi_df_global_dice_score_txt = os.path.join(
                    pfo_where_to_save,
                    '{0}_{1}.txt'.format(prefix_output, d.__name__))
                with open(pfi_df_global_dice_score_txt, 'w') as outfile:
                    dictionary_of_measurements[d.__name__].to_string(outfile)