Beispiel #1
0
def surface_distances(img_expert, img_model):
    surface_distances = surface_distance.compute_surface_distances(
        img_expert, img_model, (0.1, 0.1))
    robust_hausdorff = surface_distance.compute_robust_hausdorff(
        surface_distances, 95)
    dist, dist_inv = surface_distance.compute_average_surface_distance(
        surface_distances)
    dice_at_tolerance = surface_distance.compute_surface_dice_at_tolerance(
        surface_distances, tolerance_mm=1.0)
    tmp = {
        "dist": dist,
        "dist_inv": dist_inv,
        "robust_hausdorff": robust_hausdorff,
        "dice_at_tolerance": dice_at_tolerance,
    }
    return tmp
Beispiel #2
0
    def _assert_metrics(self,
                        surface_distances,
                        mask_gt,
                        mask_pred,
                        expected_average_surface_distance,
                        expected_hausdorff_100,
                        expected_hausdorff_95,
                        expected_surface_overlap_at_1mm,
                        expected_surface_dice_at_1mm,
                        expected_volumetric_dice,
                        places=3):
        actual_average_surface_distance = (
            surface_distance.compute_average_surface_distance(
                surface_distances))
        for i in range(2):
            self._assert_almost_equal(expected_average_surface_distance[i],
                                      actual_average_surface_distance[i],
                                      places=places)

        self._assert_almost_equal(expected_hausdorff_100,
                                  surface_distance.compute_robust_hausdorff(
                                      surface_distances, 100),
                                  places=places)

        self._assert_almost_equal(expected_hausdorff_95,
                                  surface_distance.compute_robust_hausdorff(
                                      surface_distances, 95),
                                  places=places)

        actual_surface_overlap_at_1mm = (
            surface_distance.compute_surface_overlap_at_tolerance(
                surface_distances, tolerance_mm=1))
        for i in range(2):
            self._assert_almost_equal(expected_surface_overlap_at_1mm[i],
                                      actual_surface_overlap_at_1mm[i],
                                      places=places)

        self._assert_almost_equal(
            expected_surface_dice_at_1mm,
            surface_distance.compute_surface_dice_at_tolerance(
                surface_distances, tolerance_mm=1),
            places=places)

        self._assert_almost_equal(expected_volumetric_dice,
                                  surface_distance.compute_dice_coefficient(
                                      mask_gt, mask_pred),
                                  places=places)
Beispiel #3
0
def ASSD_3d(mask_path, pred_path, lobe_index):
    mask_sitk_img = sitk.ReadImage(mask_path)
    mask_img_arr = sitk.GetArrayFromImage(mask_sitk_img)
    pred_sitk_img = sitk.ReadImage(pred_path)
    pred_img_arr = sitk.GetArrayFromImage(pred_sitk_img)

    mask_img_arr[mask_img_arr != lobe_index] = 0
    pred_img_arr[pred_img_arr != lobe_index] = 0

    mask_img_arr[mask_img_arr == lobe_index] = 1
    pred_img_arr[pred_img_arr == lobe_index] = 1

    mask_img_arr = mask_img_arr.astype(np.bool_)
    pred_img_arr = pred_img_arr.astype(np.bool_)

    spacing = mask_sitk_img.GetSpacing()
    surface_distances = surfdist.compute_surface_distances(mask_img_arr,
                                                           pred_img_arr,
                                                           spacing_mm=spacing)
    asd = surfdist.compute_average_surface_distance(surface_distances)
    return np.mean(asd)
Beispiel #4
0
def eval_net(net_spinal_cord,
             net_gm,
             loader,
             writer,
             logger,
             threshold=0.5,
             epoch=None):
    """Evaluation without the densecrf with the dice coefficient"""
    net_gm.eval()
    net_spinal_cord.eval()
    resolution = loader.dataset.info_dict['resolution']
    criterion = nn.BCEWithLogitsLoss()
    metric_dict = {
        'DSC': metrics.DiceSimilarityCoefficient,
        'JI': metrics.JaccardIndex,
        'CC': metrics.ConformityCoefficient,
        'TPR': metrics.Sensitivity,
        'TNR': metrics.Specificity,
        'PPV': metrics.Precision
    }

    transform_eval = T.ComposedTransform([T.CenterCrop(144)])
    eval_result = {key: 0 for key in metric_dict.keys()}
    eval_result['loss_gm'] = 0
    eval_result['loss_spinal_cord'] = 0
    eval_result['auc'] = 0
    eval_result['avg_surface_distance'] = 0
    with torch.no_grad():
        for data3D, gt_list in loader:
            gt_list = torch.cat([gt.byte() for gt in gt_list], 0)
            x, gt = data3D.transpose(0, 1), gt_list.transpose(0, 1)
            x_max = x.max(dim=2)[0].max(dim=2)[0]
            x_max = (x_max + (x_max == 0).float()).view(-1, 1, 1, 1)
            x = x / x_max
            true_masks = gt.cuda()
            spinal_cord_mask = (torch.mean(
                (true_masks > 0).float(), dim=1) > 0.5).unsqueeze(
                    dim=1).float()
            gm_gt_mask = (torch.mean(
                (true_masks == 1).float(), dim=1) > 0.5).unsqueeze(
                    dim=1).float()
            trans_x, trans_cord_mask, trans_gm_mask = [], [], []
            for i in range(x.shape[0]):
                a, b, c = transform_eval(x[i], spinal_cord_mask[i],
                                         gm_gt_mask[i])
                trans_x.append(a), trans_cord_mask.append(
                    b), trans_gm_mask.append(c)

            x, spinal_cord_mask, gm_gt_mask = torch.stack(
                trans_x, dim=0).cuda(), torch.stack(
                    trans_cord_mask, dim=0).cuda(), torch.stack(trans_gm_mask,
                                                                dim=0).cuda()
            spinal_cord_pred, _ = net_spinal_cord(x)
            loss_spinal_cord = criterion(spinal_cord_pred, spinal_cord_mask)

            spinal_mask_pred = (torch.sigmoid(spinal_cord_pred) >
                                0.5).detach().float()
            local_max = (spinal_mask_pred * x).max(dim=2)[0].max(dim=2)[0]
            local_min = ((1 - spinal_mask_pred) * 9999 +
                         spinal_mask_pred * x).min(dim=2)[0].min(dim=2)[0]

            local_max = local_max.view(-1, 1, 1, 1)
            local_min = local_min.view(-1, 1, 1, 1)
            local_min *= (local_min < 9000).float()
            x = torch.clamp(
                (x - local_min) / ((local_max - local_min) +
                                   ((local_max - local_min) == 0).float()), 0,
                1)
            gm_pred, _ = net_gm(x)  # * spinal_mask_pred
            gm_pos_weight = torch.sum(spinal_cord_mask) / torch.sum(
                spinal_cord_mask * gm_gt_mask)
            if torch.isinf(gm_pos_weight) or torch.isnan(gm_pos_weight):
                gm_pos_weight = torch.tensor(1.).cuda()
            loss_gm = F.binary_cross_entropy_with_logits(
                gm_pred * spinal_mask_pred,
                gm_gt_mask,
                pos_weight=gm_pos_weight)
            gm_pred_mask = torch.sigmoid(gm_pred * spinal_mask_pred) > 0.5
            eval_result['loss_gm'] += loss_gm.item()
            eval_result['loss_spinal_cord'] += loss_spinal_cord.item()
            eval_result['auc'] += skmetrics.roc_auc_score(
                gm_gt_mask.view(-1).cpu().numpy(),
                gm_pred.view(-1).cpu().numpy())
            surface_dis = surface_distance.compute_surface_distances(
                gm_gt_mask.cpu().squeeze().numpy().astype(np.bool),
                gm_pred_mask.cpu().squeeze().numpy().astype(np.bool),
                spacing_mm=resolution)
            eval_result['avg_surface_distance'] += np.mean(
                surface_distance.compute_average_surface_distance(surface_dis))
            # gm_pred_full_size = (torch.sigmoid(gm_pred) * spinal_mask_pred) > 0.5

            # writer.add_images('raw_data', x, global_step=epoch)
            # writer.add_images('SpinalList_Pred', spinal_mask_pred, global_step=epoch)
            # writer.add_images('SpinalList_GT', spinal_cord_mask, global_step=epoch)
            # writer.add_images('GmMask_Pred', gm_pred_mask, global_step=epoch)
            # writer.add_images('GmMask_GT', gm_gt_mask, global_step=epoch)
            for key, metric_func in metric_dict.items():
                eval_result[key] += metric_func(gm_pred_mask, gm_gt_mask)

        for key, val in eval_result.items():
            eval_result[key] = val / len(loader)
            # writer.add_scalar('eval/' + key, eval_result[key], global_step=epoch)
        info_list = [{
            'name': key,
            'val': value
        } for key, value in eval_result.items()]
        logger.log_epoch_info(info_list, epoch=epoch)
        return eval_result
Beispiel #5
0
    def test_two_squares_shifted_by_one_pixel(self):
        # We make sure we do not have active pixels on the border of the image,
        # because this will add additional 2D surfaces on the border of the image
        # because the image is padded with background.
        mask_gt = np.asarray([
            [0, 0, 0, 0, 0, 0],
            [0, 1, 1, 0, 0, 0],
            [0, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0],
        ],
                             dtype=np.bool)

        mask_pred = np.asarray([
            [0, 0, 0, 0, 0, 0],
            [0, 1, 1, 0, 0, 0],
            [0, 1, 1, 0, 0, 0],
            [0, 1, 1, 0, 0, 0],
            [0, 0, 0, 0, 0, 0],
            [0, 0, 0, 0, 0, 0],
        ],
                               dtype=np.bool)

        vertical = 2
        horizontal = 1
        diag = 0.5 * math.sqrt(horizontal**2 + vertical**2)
        surface_distances = surface_distance.compute_surface_distances(
            mask_gt, mask_pred, spacing_mm=(vertical, horizontal))

        # We go from top left corner, clockwise to describe the surfaces and
        # distances. The 2 surfaces are:
        #
        #  /-\  /-\
        #  | |  | |
        #  \-/  | |
        #       \-/
        expected_surfel_areas_gt = np.asarray([
            diag, horizontal, diag, vertical, diag, horizontal, diag, vertical
        ])
        expected_surfel_areas_pred = np.asarray([
            diag, horizontal, diag, vertical, vertical, diag, horizontal, diag,
            vertical, vertical
        ])
        expected_distances_gt_to_pred = np.asarray([0] * 5 + [horizontal] +
                                                   [0] * 2)
        expected_distances_pred_to_gt = np.asarray([0] * 5 + [vertical] * 3 +
                                                   [0] * 2)

        # We sort these using the same sorting algorithm
        (expected_distances_gt_to_pred,
         expected_surfel_areas_gt) = (metrics._sort_distances_surfels(
             expected_distances_gt_to_pred, expected_surfel_areas_gt))
        (expected_distances_pred_to_gt,
         expected_surfel_areas_pred) = (metrics._sort_distances_surfels(
             expected_distances_pred_to_gt, expected_surfel_areas_pred))

        expected_distances = {
            'surfel_areas_gt': expected_surfel_areas_gt,
            'surfel_areas_pred': expected_surfel_areas_pred,
            'distances_gt_to_pred': expected_distances_gt_to_pred,
            'distances_pred_to_gt': expected_distances_pred_to_gt,
        }

        self.assertEqual(len(expected_distances), len(surface_distances))
        for key, expected_value in expected_distances.items():
            np.testing.assert_array_equal(expected_value,
                                          surface_distances[key])

        self._assert_metrics(
            surface_distances,
            mask_gt,
            mask_pred,
            expected_average_surface_distance=(
                surface_distance.compute_average_surface_distance(
                    expected_distances)),
            expected_hausdorff_100=(surface_distance.compute_robust_hausdorff(
                expected_distances, 100)),
            expected_hausdorff_95=surface_distance.compute_robust_hausdorff(
                expected_distances, 95),
            expected_surface_overlap_at_1mm=(
                surface_distance.compute_surface_overlap_at_tolerance(
                    expected_distances, tolerance_mm=1)),
            expected_surface_dice_at_1mm=(
                surface_distance.compute_surface_dice_at_tolerance(
                    surface_distances, tolerance_mm=1)),
            expected_volumetric_dice=(
                surface_distance.compute_dice_coefficient(mask_gt, mask_pred)))
Beispiel #6
0
y_true = te_mask.reshape(
    te_mask.shape[0] * te_mask.shape[1] * te_mask.shape[2], 1)

y_pred = np.where(y_scores > 0.8, 1, 0)
y_true = np.where(y_true > 0.5, 1, 0)

# Surface Distance Metrics:
hausdorff_list = np.array([0 for i in range(predictions.shape[0])])
avg_surf_dist = np.array(
    [np.array([0, 0]) for i in range(predictions.shape[0])])
for i in range(len(predictions)):
    surface_dist_dict = sd.compute_surface_distances(
        predictions[i].astype(bool), Estimated_lung[i].astype(bool), [1, 1])
    hausdorff_list[i] = sd.compute_robust_hausdorff(surface_dist_dict, 1)
    tmp_avg = sd.compute_average_surface_distance(surface_dist_dict)
    avg_surf_dist[i, 0] = tmp_avg[0]
    avg_surf_dist[i, 1] = tmp_avg[1]

print("\nMean of Hausdorff distances: " + str(np.mean(hausdorff_list)))
print("\nMean of Average Surface Distances (Original to predicted): " +
      str(np.mean(avg_surf_dist[:, 0])))
print("\nMean of Average Surface Distances (Predicted to original): " +
      str(np.mean(avg_surf_dist[:, 1])))

# Area under the ROC curve
fpr, tpr, thresholds = roc_curve((y_true), y_pred)
AUC_ROC = roc_auc_score(y_true, y_pred)
print("\nArea under the ROC curve: " + str(AUC_ROC))
roc_curve = plt.figure()
plt.plot(fpr, tpr, '-', label='Area Under the Curve (AUC = %0.4f)' % AUC_ROC)