Exemple #1
0
def performance(output, target):
    pos_probs = torch.sigmoid(output)
    pos_preds = (pos_probs > 0.5).float()

    pos_preds = pos_preds.cpu().numpy().squeeze()
    target = target.cpu().numpy().squeeze()

    if target.sum() == 0:  # background patch
        return 0, 0

    try:
        # ACD
        acd_se = binary.assd(pos_preds, target)
        # ASD
        d_sg = np.sqrt(binary.__surface_distances(pos_preds, target, 1))
        d_gs = np.sqrt(binary.__surface_distances(target, pos_preds, 1))
        asd_se = (d_sg.sum() + d_gs.sum()) / (len(d_sg) + len(d_gs))

    except:
        #pred == 0
        acd_se = None
        asd_se = None

    # IoU
    union = ((pos_preds + target) != 0).sum()
    intersection = (pos_preds * target).sum()
    iou = intersection / union

    # dice
    dice = (2 * intersection) / (pos_preds.sum() + target.sum())

    return iou, dice, acd_se, asd_se
Exemple #2
0
def performance_by_slice(output_list, target_list,img_name_list):

    assert len(output_list) == len(target_list), 'not same list lenths'

    performance = {}
    for i in range(len(output_list)):
        preds =  output_list[i]
        slice_pred = (preds > 0.5).astype('float')
        slice_target = target_list[i]

        # slice-level classification performance
        tp = fp = tn = fn = 0
        is_gt_positive = slice_target.max()
        is_pred_positive = slice_pred.max()
        if is_gt_positive:
            if is_pred_positive:
                tp = 1
            else:
                fn = 1
        else:
            if is_pred_positive:
                fp = 1
            else:
                tn = 1

        # slice-level segmentation performance
        iou = dice = -1
        if is_gt_positive:
            union = ((slice_pred + slice_target) != 0).sum()
            intersection = (slice_pred * slice_target).sum()

            iou = intersection / union
            dice = (2 * intersection) / (slice_pred.sum() + slice_target.sum())

            try:
                # ACD
                acd_se = binary.assd(slice_pred, slice_target)

                # ASD
                d_sg = np.sqrt(binary.__surface_distances(slice_pred, slice_target, 1))
                d_gs = np.sqrt(binary.__surface_distances(slice_target, slice_pred, 1))
                asd_se = (d_sg.sum() + d_gs.sum()) / (len(d_sg) + len(d_gs))

            except:
                # pred == 0
                acd_se = None
                asd_se = None

        # TODO: not need to store gt and pred
        performance[str(i)] = {'cls': [tp, fp, tn, fn],
                                  'seg': [iou, dice],
                                  'gt': slice_target,
                                  'pred': slice_pred,
                               'img':img_name_list[i],
                               'acd_se':acd_se,
                               'asd_se': asd_se,
                               }
        #'pixel': [gt_pixel, pred_pixel],

    return performance
Exemple #3
0
def mod_hausdorff_distance(data1, data2, voxelspacing=None, percentile=95):
    data1, data2 = to_numpy(data1), to_numpy(data2)
    hd1 = __surface_distances(data1, data2, voxelspacing, connectivity=1)
    hd2 = __surface_distances(data2, data1, voxelspacing, connectivity=1)
    hd95_1 = np.percentile(hd1, percentile)
    hd95_2 = np.percentile(hd2, percentile)
    mhd = max(hd95_1, hd95_2)
    return mhd
Exemple #4
0
 def _hd_percentile(result: np.ndarray,
                    reference: np.ndarray,
                    voxelspacing: np.ndarray = None,
                    connectivity: int = 1) -> float:
     hd1 = mp.__surface_distances(result, reference, voxelspacing,
                                  connectivity)
     hd2 = mp.__surface_distances(reference, result, voxelspacing,
                                  connectivity)
     return np.percentile(np.hstack((hd1, hd2)), percentile)
Exemple #5
0
def getHd95(pred, target):
    pred = pred.cpu().numpy()
    target = target.cpu().numpy()
    if np.count_nonzero(pred) > 0 and np.count_nonzero(target):
        surDist1 = medpyMetrics.__surface_distances(pred, target)
        surDist2 = medpyMetrics.__surface_distances(target, pred)
        hd95 = np.percentile(np.hstack((surDist1, surDist2)), 95)
        return hd95
    else:
        # Edge cases that medpy cannot handle
        return -1
def normalized_surface_dice(a: np.ndarray,
                            b: np.ndarray,
                            threshold: float,
                            spacing: tuple = None,
                            connectivity=1):
    """
	This implementation differs from the official surface dice implementation! These two are not comparable!!!!!

	The normalized surface dice is symmetric, so it should not matter whether a or b is the reference image

	This implementation natively supports 2D and 3D images. Whether other dimensions are supported depends on the
	__surface_distances implementation in medpy

	:param a: image 1, must have the same shape as b
	:param b: image 2, must have the same shape as a
	:param threshold: distances below this threshold will be counted as true positives. Threshold is in mm, not voxels!
	(if spacing = (1, 1(, 1)) then one voxel=1mm so the threshold is effectively in voxels)
	must be a tuple of len dimension(a)
	:param spacing: how many mm is one voxel in reality? Can be left at None, we then assume an isotropic spacing of 1mm
	:param connectivity: see scipy.ndimage.generate_binary_structure for more information. I suggest you leave that
	one alone
	:return:
	"""
    assert all([i == j for i, j in zip(a.shape, b.shape)]), "a and b must have the same shape. a.shape= %s, " \
                  "b.shape= %s" % (str(a.shape), str(b.shape))
    if spacing is None:
        spacing = tuple([1 for _ in range(len(a.shape))])
    a_to_b = __surface_distances(a, b, spacing, connectivity)
    b_to_a = __surface_distances(b, a, spacing, connectivity)

    numel_a = len(a_to_b)
    numel_b = len(b_to_a)

    tp_a = np.sum(a_to_b <= threshold) / numel_a
    tp_b = np.sum(b_to_a <= threshold) / numel_b

    fp = np.sum(a_to_b > threshold) / numel_a
    fn = np.sum(b_to_a > threshold) / numel_b

    dc = (tp_a + tp_b) / (tp_a + tp_b + fp + fn + 1e-8
                          )  # 1e-8 just so that we don't get div by 0
    return dc
Exemple #7
0
def hausdorff_distance(data1, data2, voxelspacing=None):
    data1, data2 = to_numpy(data1), to_numpy(data2)
    hd1 = __surface_distances(data1, data2, voxelspacing, connectivity=1)
    hd2 = __surface_distances(data2, data1, voxelspacing, connectivity=1)
    hd = max(hd1.max(), hd2.max())
    return hd
Exemple #8
0
def getNSD(pred, target):
    surDist1 = medpyMetrics.__surface_distances(pred, target)
    surDist2 = medpyMetrics.__surface_distances(target, pred)
    hd95 = np.percentile(np.hstack((surDist1, surDist2)), 95)
    return hd95