def clip_plot(self, out_png_folder):
        in_img_obj = ScanWrapper(self._in_img_path)
        in_mask_obj = ScanWrapper(self._in_mask_path)

        in_img_data = in_img_obj.get_data()
        in_mask_data = in_mask_obj.get_data()

        masked_img_data = np.zeros(in_img_data.shape, dtype=float)
        masked_img_data.fill(np.nan)
        masked_img_data[in_mask_data == 1] = in_img_data[in_mask_data == 1]
        # masked_img_data[masked_img_data != masked_img_data] = self._vmin

        self._plot_view(
            self._num_clip,
            self._step_axial,
            masked_img_data,
            'axial',
            out_png_folder
        )

        self._plot_view(
            self._num_clip,
            self._step_sagittal,
            masked_img_data,
            'sagittal',
            out_png_folder
        )

        self._plot_view(
            self._num_clip,
            self._step_coronal,
            masked_img_data,
            'coronal',
            out_png_folder
        )
Exemple #2
0
    def _run_single_scan(self, idx):
        mask1 = ScanWrapper(self._in_data_folder.get_file_path(idx))
        mask2 = ScanWrapper(self._in_folder2_obj.get_file_path(idx))

        mask_union = np.zeros(mask1.get_data().shape, dtype=int)
        mask_union[(mask1.get_data() == 1) | (mask2.get_data() == 1)] = 1

        out_path = self._out_folder_obj.get_file_path(idx)
        mask1.save_scan_same_space(out_path, mask_union)
Exemple #3
0
    def clip_plot_3_view(self, out_png_folder):
        in_img_obj = ScanWrapper(self._in_img_path)
        in_mask_obj = ScanWrapper(self._in_mask_path)

        in_img_data = in_img_obj.get_data()
        in_mask_data = in_mask_obj.get_data()

        masked_img_data = np.zeros(in_img_data.shape, dtype=float)
        masked_img_data.fill(np.nan)
        masked_img_data[in_mask_data == 1] = in_img_data[in_mask_data == 1]
Exemple #4
0
    def _run_single_scan(self, idx):
        test_mask = ScanWrapper(self._in_data_folder.get_file_path(idx))
        effective_mask = ScanWrapper(
            self._effective_mask_folder_obj.get_file_path(idx))

        dice_val = get_dice_with_effective_mask(self._gt_mask.get_data(),
                                                test_mask.get_data(),
                                                effective_mask.get_data())

        result = {'Scan': test_mask.get_file_name(), 'Dice': dice_val}

        return result
    def _run_single_scan(self, idx):
        in_ori_image_obj = ScanWrapper(self._in_data_folder.get_file_path(idx))
        in_affine_image_obj = ScanWrapper(
            self._in_affine_folder.get_file_path(idx))
        in_warped_image_obj = ScanWrapper(
            self._in_warped_folder.get_file_path(idx))

        num_view = 3
        num_clip = 5

        fig = plt.figure(figsize=(num_view * 100, num_clip * 30))
        gs1 = gridspec.GridSpec(num_clip, self._num_plot_per_view * num_view)
        gs1.update(wspace=0.025, hspace=0.05)

        self._plot_view(num_clip,
                        step_clip=self._step_axial,
                        in_ori_data=in_ori_image_obj.get_data(),
                        in_affine_data=in_affine_image_obj.get_data(),
                        in_warped_data=in_warped_image_obj.get_data(),
                        gs=gs1,
                        plot_column=0,
                        view_flag='Axial')

        self._plot_view(num_clip,
                        step_clip=self._step_sagittal,
                        in_ori_data=in_ori_image_obj.get_data(),
                        in_affine_data=in_affine_image_obj.get_data(),
                        in_warped_data=in_warped_image_obj.get_data(),
                        gs=gs1,
                        plot_column=1,
                        view_flag='Sagittal')

        self._plot_view(num_clip,
                        step_clip=self._step_coronal,
                        in_ori_data=in_ori_image_obj.get_data(),
                        in_affine_data=in_affine_image_obj.get_data(),
                        in_warped_data=in_warped_image_obj.get_data(),
                        gs=gs1,
                        plot_column=2,
                        view_flag='Coronal')

        fig.suptitle(f'{self._in_data_folder.get_file_name(idx)}',
                     y=0.9,
                     fontsize=2 * self._sub_title_font_size,
                     va='center')

        out_png = self._out_png_folder.get_file_path(idx)
        logger.info(f'Save png to {out_png}')
        plt.savefig(out_png,
                    bbox_inches='tight',
                    pad_inches=0,
                    dpi=self._out_dpi)
        plt.close(fig=fig)
Exemple #6
0
class CalculateDice(AbstractParallelRoutine):
    def __init__(self, in_folder_obj, effective_mask_folder, num_process,
                 gt_mask):
        super().__init__(in_folder_obj, num_process)
        self._effective_mask_folder_obj = effective_mask_folder
        self._gt_mask = ScanWrapper(gt_mask)
        self._df_dice = None

    def get_dice(self):
        logger.info(f'Calculating dice score')
        result_list = self.run_parallel()
        logger.info(f'Done.')
        self._df_dice = pd.DataFrame(result_list)
        # print(self._df_dice)

    def save_csv(self, csv_file):
        logger.info(f'Save dice table to csv {csv_file}')
        self._df_dice.to_csv(csv_file, index=False)

    def _run_single_scan(self, idx):
        test_mask = ScanWrapper(self._in_data_folder.get_file_path(idx))
        effective_mask = ScanWrapper(
            self._effective_mask_folder_obj.get_file_path(idx))

        dice_val = get_dice_with_effective_mask(self._gt_mask.get_data(),
                                                test_mask.get_data(),
                                                effective_mask.get_data())

        result = {'Scan': test_mask.get_file_name(), 'Dice': dice_val}

        return result
Exemple #7
0
    def _run_chunk_get_variance(self, chunk_list):
        result_list = []
        im_shape = self._ref_img.get_shape()
        sum_image_union = np.zeros(im_shape)
        for idx in chunk_list:
            self._in_data_folder.print_idx(idx)
            img_obj = ScanWrapper(self._in_data_folder.get_file_path(idx))
            img_data = img_obj.get_data()
            valid_mask = np.logical_not(np.isnan(img_data)).astype(int)

            residue_map = np.zeros(img_data.shape)
            np.subtract(img_data,
                        self._average_map,
                        out=residue_map,
                        where=valid_mask > 0)
            residue_map = np.power(residue_map, 2)
            np.add(residue_map,
                   sum_image_union,
                   out=sum_image_union,
                   where=valid_mask > 0)

        result = {'sum_image': sum_image_union}

        result_list.append(result)
        return result_list
Exemple #8
0
class GetDiceEffectiveRegion(AbstractParallelRoutine):
    def __init__(self, in_ori_folder_obj, in_ref_valid_mask, num_process,
                 out_folder_obj, etch_radius):
        super().__init__(in_ori_folder_obj, num_process)
        self._in_ref_valid_mask = ScanWrapper(in_ref_valid_mask)
        self._out_folder_obj = out_folder_obj
        self._etch_radius = etch_radius

    def _run_single_scan(self, idx):
        in_ori_image = ScanWrapper(self._in_data_folder.get_file_path(idx))
        in_ori_data = in_ori_image.get_data()
        in_effective_mask = (in_ori_data == in_ori_data).astype(int)

        effective_region_mask = in_effective_mask * self._in_ref_valid_mask.get_data(
        )

        # We need to make sure the boundary elements are all 0
        boundary_mask = np.zeros(in_ori_image.get_shape())
        boundary_mask[1:-1, 1:-1, 1:-1] = 1
        effective_region_mask = effective_region_mask * boundary_mask
        edt_img = ndi.distance_transform_edt(effective_region_mask)
        effective_region_mask = (edt_img > self._etch_radius).astype(int)

        out_mask_path = self._out_folder_obj.get_file_path(idx)
        in_ori_image.save_scan_same_space(out_mask_path, effective_region_mask)
    def _run_single_scan(self, idx):
        in_img = ScanWrapper(self._in_data_folder.get_file_path(idx))
        in_mask = None
        if self._in_mask_folder_obj is not None:
            in_mask = ScanWrapper(self._in_mask_folder_obj.get_file_path(idx))
        if self._in_mask_file_obj is not None:
            in_mask = self._in_mask_file_obj
        out_path = self._out_folder_obj.get_file_path(idx)

        in_img_data = in_img.get_data()
        in_mask_data = in_mask.get_data()

        new_img_data = np.full(in_img.get_shape(), self._ambient_val)

        np.copyto(new_img_data, in_img_data, where=in_mask_data > 0)

        in_img.save_scan_same_space(out_path, new_img_data)
    def _run_single_scan(self, idx):
        test_mask = ScanWrapper(self._in_data_folder.get_file_path(idx))
        effective_mask = ScanWrapper(self._effective_mask_folder_obj.get_file_path(idx))
        effective_data = effective_mask.get_data()

        test_data = test_mask.get_data()
        gt_data = self._gt_mask.get_data()

        edt_test, surf_test = self._get_edt_full(test_data)
        edt_gt, surf_gt = self._get_edt_full(gt_data)

        effective_surf_test = surf_test * effective_data
        effective_surf_gt = surf_gt * effective_data

        # For debug the effective surface.
        # effective_surf_combine_output_path = test_mask.get_path() + '_effsur.nii.gz'
        # combine_effective = effective_surf_test
        # np.copyto(combine_effective, 2 * effective_surf_gt, where=effective_surf_gt > 0.5)
        # test_mask.save_scan_same_space(effective_surf_combine_output_path, combine_effective)

        surf_dist_map_gt2test = effective_surf_gt * edt_test
        surf_dist_map_test2gt = effective_surf_test * edt_gt

        num_surface_test = effective_surf_test.sum()
        num_surface_gt = effective_surf_gt.sum()

        msd_sym = (surf_dist_map_gt2test.sum() / num_surface_gt) + \
                  (surf_dist_map_test2gt.sum() / num_surface_test)
        msd_sym /= 2
        hd_sym = np.amax(surf_dist_map_gt2test) + np.amax(surf_dist_map_test2gt)
        hd_sym /= 2

        result = {
            'Scan': test_mask.get_file_name(),
            'MSD': msd_sym,
            'HD': hd_sym,
            'effective surface points (test)': effective_surf_test.sum(),
            'effective ratio (test)': effective_surf_test.sum() / surf_test.sum(),
            'effective surface points (gt)': effective_surf_gt.sum(),
            'effective ratio (gt)': effective_surf_gt.sum() / surf_gt.sum()
        }

        return result
    def _run_single_scan(self, idx):
        in_img = ScanWrapper(self._in_data_folder.get_file_path(idx))
        out_path = self._out_mask_folder_obj.get_file_path(idx)

        in_img_data = in_img.get_data()
        non_nan_mask = (in_img_data == in_img_data).astype(int)

        if self._if_reverse:
            non_nan_mask = 1 - non_nan_mask

        in_img.save_scan_same_space(out_path, non_nan_mask)
Exemple #12
0
    def _run_single_scan(self, idx):
        in_ori_path = self._in_data_folder.get_file_path(idx)
        out_path = self._out_folder.get_file_path(idx)

        im_obj = ScanWrapper(in_ori_path)
        im_data = im_obj.get_data()

        logger.info(f'Replace nan to valude {self._replace_val}')

        new_im_data = np.nan_to_num(im_data, nan=self._replace_val)
        im_obj.save_scan_same_space(out_path, new_im_data)
    def clip_plot(self, out_png_folder):
        in_img_obj = ScanWrapper(self._in_img_path)
        in_mask_obj = ScanWrapper(self._in_mask_path)
        in_back_obj = ScanWrapper(self._in_back_img_path)
        in_trans_obj = ScanWrapper(self._in_trans_img_path)

        in_img_data = in_img_obj.get_data()
        in_mask_data = in_mask_obj.get_data()
        in_back_data = in_back_obj.get_data()
        in_trans_data = in_trans_obj.get_data()

        # masked_img_data = np.zeros(in_img_data.shape, dtype=float)
        # masked_img_data.fill(np.nan)
        # masked_img_data[in_mask_data == 1] = in_img_data[in_mask_data == 1]
        # masked_back_data = np.zeros(in_back_data.shape, dtype=float)
        # masked_back_data.fill(np.nan)
        # masked_back_data[in_mask_data == 1] = in_back_data[in_mask_data == 1]

        masked_img_data = in_img_data
        masked_back_data = in_back_data

        masked_trans_data = self._mask_in_trans_data(in_trans_data,
                                                     in_mask_data)
        in_trans_data = masked_trans_data

        self._plot_view(self._num_clip, self._step_axial, masked_img_data,
                        masked_back_data, in_trans_data, 'axial',
                        out_png_folder)

        self._plot_view(self._num_clip, self._step_sagittal, masked_img_data,
                        masked_back_data, in_trans_data, 'sagittal',
                        out_png_folder)

        self._plot_view(self._num_clip, self._step_coronal, masked_img_data,
                        masked_back_data, in_trans_data, 'coronal',
                        out_png_folder)
Exemple #14
0
    def _get_img_data(self, idx):
        img_obj = ScanWrapper(self._in_data_folder.get_file_path(idx))
        img_data = img_obj.get_data()
        img_data = np.abs(img_data)
        np.copyto(img_data, np.nan, where=img_data < 0.01)
        img_data = np.log10(img_data)

        in_omat_path = self._in_omat_folder_obj.get_file_path(idx)
        omat = np.loadtxt(in_omat_path)
        img_data = img_data + np.log10(np.linalg.det(omat))

        save_corrected_path = self._out_corrected_folder_obj.get_file_path(idx)
        img_obj.save_scan_same_space(save_corrected_path, img_data)

        return img_data
Exemple #15
0
    def clip_plot(self, out_png_folder):
        in_img_obj = ScanWrapper(self._in_img_path)
        in_back_obj = ScanWrapper(self._in_back_img_path)

        in_img_data = in_img_obj.get_data()
        in_back_data = in_back_obj.get_data()

        masked_img_data = None
        masked_back_data = None

        if self._in_mask_path is not None:
            in_mask_obj = ScanWrapper(self._in_mask_path)
            in_mask_data = in_mask_obj.get_data()

            masked_img_data = np.zeros(in_img_data.shape, dtype=float)
            masked_img_data.fill(np.nan)
            masked_img_data[in_mask_data == 1] = in_img_data[in_mask_data == 1]

            masked_back_data = np.zeros(in_back_data.shape, dtype=float)
            masked_back_data.fill(np.nan)
            masked_back_data[in_mask_data == 1] = in_back_data[in_mask_data ==
                                                               1]
        else:
            masked_img_data = in_img_data
            masked_back_data = in_back_data

        self._plot_view(self._num_clip, self._step_axial, masked_img_data,
                        masked_back_data, 'axial', out_png_folder, 1)

        self._plot_view(self._num_clip, self._step_sagittal, masked_img_data,
                        masked_back_data, 'sagittal', out_png_folder,
                        5.23438 / 2.28335)

        self._plot_view(self._num_clip, self._step_coronal, masked_img_data,
                        masked_back_data, 'coronal', out_png_folder,
                        5.23438 / 2.17388)
Exemple #16
0
def get_pad_mask2(in_native_nii, out_mask_nii):
    in_native_obj = ScanWrapper(in_native_nii)
    in_native_img = in_native_obj.get_data()

    print(in_native_img.shape)
    z_variance_map = np.var(in_native_img, axis=2)
    print(z_variance_map.shape)

    slice_pad_region = (z_variance_map == 0).astype(int)

    mask_img = np.zeros(in_native_img.shape, dtype=int)
    for z_idx in range(mask_img.shape[2]):
        mask_img[:, :, z_idx] = slice_pad_region

    in_native_obj.save_scan_same_space(out_mask_nii, mask_img)

    return np.sum(slice_pad_region) != 0
Exemple #17
0
    def _run_single_scan(self, idx):
        in_ori_image = ScanWrapper(self._in_data_folder.get_file_path(idx))
        in_ori_data = in_ori_image.get_data()
        in_effective_mask = (in_ori_data == in_ori_data).astype(int)

        effective_region_mask = in_effective_mask * self._in_ref_valid_mask.get_data(
        )

        # We need to make sure the boundary elements are all 0
        boundary_mask = np.zeros(in_ori_image.get_shape())
        boundary_mask[1:-1, 1:-1, 1:-1] = 1
        effective_region_mask = effective_region_mask * boundary_mask
        edt_img = ndi.distance_transform_edt(effective_region_mask)
        effective_region_mask = (edt_img > self._etch_radius).astype(int)

        out_mask_path = self._out_folder_obj.get_file_path(idx)
        in_ori_image.save_scan_same_space(out_mask_path, effective_region_mask)
def get_pad_mask(in_nii, out_nii):
    circle_info = get_ct_pixel_pad_circle_fit(in_nii)
    in_obj = ScanWrapper(in_nii)
    in_img = in_obj.get_data()
    mask_img = np.zeros(in_img.shape, dtype=int)
    if circle_info is not None:
        c_x, c_y, c_r = circle_info
        mask_slice = np.zeros((in_img.shape[0], in_img.shape[1]), dtype=int)
        for i in range(in_img.shape[0]):
            for j in range(in_img.shape[1]):
                dist2center = np.sqrt((i - c_x)**2 + (j - c_y)**2)
                if dist2center > c_r - 1:
                    mask_slice[i, j] = 1
        for k in range(in_img.shape[2]):
            mask_img[:, :, k] = mask_slice

    in_obj.save_scan_same_space(out_nii, mask_img)

    return circle_info is not None
Exemple #19
0
    def _run_chunk_get_average(self, chunk_list):
        result_list = []
        im_shape = self._ref_img.get_shape()
        sum_image_union = np.zeros(im_shape)
        region_mask_count_image = np.zeros(im_shape)
        for idx in chunk_list:
            self._in_data_folder.print_idx(idx)
            img_obj = ScanWrapper(self._in_data_folder.get_file_path(idx))
            img_data = img_obj.get_data()
            valid_mask = np.logical_not(np.isnan(img_data)).astype(int)
            np.add(img_data, sum_image_union, out=sum_image_union, where=valid_mask > 0)
            region_mask_count_image += valid_mask

        result = {
            'sum_image': sum_image_union,
            'region_count': region_mask_count_image
        }

        result_list.append(result)
        return result_list
    def _run_single_scan(self, idx):
        im_obj = ScanWrapper(self._in_data_folder.get_file_path(idx))
        in_img_data = im_obj.get_data()

        out_png_prefix = self._out_folder_obj.get_file_path(idx)

        # self._plot_view(
        #     self._offset_axial,
        #     in_img_data,
        #     'axial',
        #     out_png_prefix
        # )
        #
        # self._plot_view(
        #     self._offset_sagittal,
        #     in_img_data,
        #     'sagittal',
        #     out_png_prefix
        # )

        self._plot_view(self._offset_coronal, in_img_data, 'coronal',
                        out_png_prefix)
 def _run_single_scan(self, idx):
     in_mask = ScanWrapper(self._in_data_folder.get_file_path(idx))
     mask_diff = np.zeros(in_mask.get_shape(), dtype=int)
     mask_diff[in_mask.get_data() != self._ref_mask_obj.get_data()] = 1
     out_path = self._out_folder_obj.get_file_path(idx)
     self._ref_mask_obj.save_scan_same_space(out_path, mask_diff)
def get_ct_pixel_pad_circle_fit(in_nii):
    in_obj = ScanWrapper(in_nii)
    in_data = in_obj.get_data()

    print(in_data.shape)
    middle_slice = in_data[:, :, int(in_data.shape[2] / 2)]
    print(middle_slice.shape)

    # Get 4 walls
    w_x_0 = in_data[0, :, :]
    w_x_1 = in_data[-1, :, :]
    w_y_0 = in_data[:, 0, :]
    w_y_1 = in_data[:, -1, :]

    w_x_0_p = (w_x_0 <= -1024).astype(int)
    w_x_1_p = (w_x_1 <= -1024).astype(int)
    w_y_0_p = (w_y_0 <= -1024).astype(int)
    w_y_1_p = (w_y_1 <= -1024).astype(int)

    w_x_0_acc = np.prod(w_x_0_p, axis=1)
    w_x_1_acc = np.prod(w_x_1_p, axis=1)
    w_y_0_acc = np.prod(w_y_0_p, axis=1)
    w_y_1_acc = np.prod(w_y_1_p, axis=1)

    if (np.sum(w_x_0_acc) + np.sum(w_x_1_acc) + np.sum(w_y_0_acc) + np.sum(w_y_1_acc)) == 0:
        print(f'No padding region detected')
        return None

    # Find the circle center coordinate.
    w_x_0_valid = np.where(w_x_0_acc == 0)
    w_x_1_valid = np.where(w_x_1_acc == 0)
    w_y_0_valid = np.where(w_y_0_acc == 0)
    w_y_1_valid = np.where(w_y_1_acc == 0)

    # Assume the valid region will reach the boundary on 4 sides.
    center_x = None
    center_y = None
    radius = 0

    # Get the set of intersection
    intersect_pos_list = []
    if len(w_x_0_valid) > 0:
        if np.max(w_x_0_valid) < in_data.shape[1] - 1:
            intersect_pos_list.append({
                'x': 0,
                'y': np.max(w_x_0_valid)
            })
        if np.min(w_x_0_valid) > 0:
            intersect_pos_list.append({
                'x': 0,
                'y': np.min(w_x_0_valid)
            })

    if len(w_x_1_valid) > 0:
        if np.max(w_x_1_valid) < in_data.shape[1] - 1:
            intersect_pos_list.append({
                'x': in_data.shape[0] - 1,
                'y': np.max(w_x_1_valid)
            })
        if np.min(w_x_1_valid) > 0:
            intersect_pos_list.append({
                'x': in_data.shape[0] - 1,
                'y': np.min(w_x_1_valid)
            })

    if len(w_y_0_valid) > 0:
        if np.max(w_y_0_valid) < in_data.shape[0] - 1:
            intersect_pos_list.append({
                'x': np.max(w_y_0_valid),
                'y': 0
            })
        if np.min(w_y_0_valid) > 0:
            intersect_pos_list.append({
                'x': np.min(w_y_0_valid),
                'y': 0
            })

    if len(w_y_1_valid) > 0:
        if np.max(w_y_1_valid) < in_data.shape[0] - 1:
            intersect_pos_list.append({
                'x': np.max(w_y_1_valid),
                'y': 0
            })
        if np.min(w_y_1_valid) > 0:
            intersect_pos_list.append({
                'x': np.min(w_y_1_valid),
                'y': 0
            })

    print(len(intersect_pos_list))
    print(intersect_pos_list)

    if len(intersect_pos_list) < 3:
        print(f'Not enough intercept point to fit circle')
        return None

    c_x, c_y, c_r = fit_circle_algebraic(intersect_pos_list)
    print(f'Fitted circle: (x: {c_x}; y: {c_y}; r: {c_r})')

    return c_x, c_y, c_r
class GetMeanSurfaceDist(AbstractParallelRoutine):
    def __init__(self, in_folder_obj, effective_mask_folder_obj, num_process, gt_mask):
        super().__init__(in_folder_obj, num_process)
        self._effective_mask_folder_obj = effective_mask_folder_obj
        self._gt_mask = ScanWrapper(gt_mask)
        self._df_surface_metric = None

    def get_surface_metric(self):
        logger.info('Calculating surface metric')
        result_list = self.run_parallel()
        logger.info('Done')
        self._df_surface_metric = pd.DataFrame(result_list)

    def save_csv(self, csv_file):
        logger.info(f'Save surface metric table to csv {csv_file}')
        self._df_surface_metric.to_csv(csv_file, index=False)

    def _run_single_scan(self, idx):
        test_mask = ScanWrapper(self._in_data_folder.get_file_path(idx))
        effective_mask = ScanWrapper(self._effective_mask_folder_obj.get_file_path(idx))
        effective_data = effective_mask.get_data()

        test_data = test_mask.get_data()
        gt_data = self._gt_mask.get_data()

        edt_test, surf_test = self._get_edt_full(test_data)
        edt_gt, surf_gt = self._get_edt_full(gt_data)

        effective_surf_test = surf_test * effective_data
        effective_surf_gt = surf_gt * effective_data

        # For debug the effective surface.
        # effective_surf_combine_output_path = test_mask.get_path() + '_effsur.nii.gz'
        # combine_effective = effective_surf_test
        # np.copyto(combine_effective, 2 * effective_surf_gt, where=effective_surf_gt > 0.5)
        # test_mask.save_scan_same_space(effective_surf_combine_output_path, combine_effective)

        surf_dist_map_gt2test = effective_surf_gt * edt_test
        surf_dist_map_test2gt = effective_surf_test * edt_gt

        num_surface_test = effective_surf_test.sum()
        num_surface_gt = effective_surf_gt.sum()

        msd_sym = (surf_dist_map_gt2test.sum() / num_surface_gt) + \
                  (surf_dist_map_test2gt.sum() / num_surface_test)
        msd_sym /= 2
        hd_sym = np.amax(surf_dist_map_gt2test) + np.amax(surf_dist_map_test2gt)
        hd_sym /= 2

        result = {
            'Scan': test_mask.get_file_name(),
            'MSD': msd_sym,
            'HD': hd_sym,
            'effective surface points (test)': effective_surf_test.sum(),
            'effective ratio (test)': effective_surf_test.sum() / surf_test.sum(),
            'effective surface points (gt)': effective_surf_gt.sum(),
            'effective ratio (gt)': effective_surf_gt.sum() / surf_gt.sum()
        }

        return result


    @staticmethod
    def _get_edt_full(mask_img_data):
        """
        To get edt on both sides of the boundary, and the boundary itself as a second mask.
        :param img_data:
        :return:
        """
        invert_mask = np.ones(mask_img_data.shape)
        invert_mask = invert_mask - mask_img_data

        edt_img = ndi.distance_transform_edt(mask_img_data)
        edt_invert_img = ndi.distance_transform_edt(invert_mask)

        edt_full = edt_img + edt_invert_img

        boundary_mask = (edt_full < 1.5).astype(int)

        return edt_full, boundary_mask