示例#1
0
def Hausdorf(pred, gt, replace_NaN=100):
    HD95_dict = {}

    bg_hd = hd(pred == 0, gt == 0)
    if 1 in np.unique(pred):
        csf_hd = hd(pred == 1, gt == 1)
    else:
        csf_hd = replace_NaN
    if 2 in np.unique(pred):
        gm_hd = hd(pred == 2, gt == 2)
    else:
        gm_hd = replace_NaN
    if 3 in np.unique(pred):
        wm_hd = hd(pred == 3, gt == 3)
    else:
        wm_hd = replace_NaN
    if 4 in np.unique(pred):
        tm_hd = hd(pred == 4, gt == 4)
    else:
        tm_hd = replace_NaN

    HD95_dict['avg'] = (csf_hd + gm_hd + wm_hd + tm_hd) / 4
    HD95_dict['bg'] = bg_hd
    HD95_dict['csf'] = csf_hd
    HD95_dict['gm'] = gm_hd
    HD95_dict['wm'] = wm_hd
    HD95_dict['tm'] = tm_hd

    return HD95_dict
示例#2
0
def get_results(prediction, reference):
    results = {}
    for c, key in enumerate(["", "RV_", "MYO_", "LV_"]):
        ref = np.copy(reference)
        pred = np.copy(prediction)

        ref = ref if c == 0 else np.where(ref != c, 0, ref)
        pred = pred if c == 0 else np.where(np.rint(pred) != c, 0, pred)

        results[key + "SED"] = np.sum((ref - pred)**2)
        results[key + "SED_rint"] = np.sum((ref - np.rint(pred))**2)
        results[key + "maxSED"] = np.sum(
            ((ref - pred)**2).reshape(ref.shape[0], -1), axis=1).max()
        results[key + "maxSED_rint"] = np.sum(
            ((ref - np.rint(pred))**2).reshape(ref.shape[0],
                                               -1), axis=1).max()
        results[key +
                "Dice"] = 2 * np.sum(pred * np.where(ref != 0, 1, 0)) / np.sum(
                    pred + np.where(ref != 0, 1, 0)) if np.sum(
                        pred + np.where(ref != 0, 1, 0)) != 0 else 0
        results[key + "Dice_rint"] = binary.dc(
            np.where(ref != 0, 1, 0), np.where(np.rint(pred) != 0, 1, 0))
        try:
            results[key + "HD_rint"] = binary.hd(
                np.where(ref != 0, 1, 0), np.where(np.rint(pred) != 0, 1, 0))
        except Exception:
            results[key + "HD_rint"] = np.nan
    return results
示例#3
0
def update_eval_metrics(preds, labels, eval_metrics):

    if len(labels.shape) == 2:
        preds = np.expand_dims(preds, axis=0)
        labels = np.expand_dims(labels, axis=0)

    N = labels.shape[0]

    for i in range(N):
        pred = preds[i, :, :]
        label = labels[i, :, :]
        eval_metrics['dice score'].append(dc(pred, label))
        eval_metrics['precision'].append(precision(pred, label))
        eval_metrics['recall'].append(recall(pred, label))
        eval_metrics['sensitivity'].append(sensitivity(pred, label))
        eval_metrics['specificity'].append(specificity(pred, label))

        if np.sum(pred) > 0 and np.sum(label) > 0:
            eval_metrics['hausdorff'].append(hd(pred, label))
            eval_metrics['hausdorff 95%'].append(hd95(pred, label))
            eval_metrics['asd'].append(asd(pred, label))
            eval_metrics['assd'].append(assd(pred, label))
            eval_metrics['jaccard'].append(jc(pred, label))
        else:
            eval_metrics['hausdorff'].append('nan')
            eval_metrics['hausdorff 95%'].append('nan')
            eval_metrics['asd'].append('nan')
            eval_metrics['assd'].append('nan')
            eval_metrics['jaccard'].append('nan')

    return eval_metrics
示例#4
0
def hausdorff(preds: Tensor, target: Tensor, spacing: Tensor = None) -> Tensor:
    assert preds.shape == target.shape
    assert one_hot(preds)
    assert one_hot(target)

    B, K, *img_shape = preds.shape

    if not spacing:
        D: int = len(img_shape)
        spacing = torch.ones((B, D), dtype=torch.float32)

    assert spacing.shape == (B, len(img_shape))

    res = torch.zeros((B, K), dtype=torch.float32, device=preds.device)
    n_pred = preds.cpu().numpy()
    n_target = target.cpu().numpy()
    n_spacing = spacing.cpu().numpy()

    for b in range(B):
        # if K == 2:
        #     res[b, :] = hd(n_pred[b, 1], n_target[b, 1], voxelspacing=n_spacing[b])
        #     continue

        for k in range(K):
            if not n_pred[b, k].any() and not n_target[b, k].any():
                res[b, k] = 0
                continue
            elif not n_pred[b, k].any() or not n_target[b, k].any():
                res[b, k] = 0
                continue

            res[b, k] = hd(n_pred[b, k], n_target[b, k], voxelspacing=n_spacing[b])

    return res
def metrics(img_gt, img_pred, ifhd=True, ifasd=True):
    from medpy.metric.binary import hd, dc, asd
    if img_gt.ndim != img_pred.ndim:
        raise ValueError("The arrays 'img_gt' and 'img_pred' should have the "
                         "same dimension, {} against {}".format(
                             img_gt.ndim, img_pred.ndim))

    res = []
    cat = {'Myo', 'LA-blood', 'LV-blood', 'AA'}
    for c in range(len(cat)):
        # Copy the gt image to not alterate the input
        gt_c_i = np.where(img_gt == c + 1, 1, 0)
        # Copy the pred image to not alterate the input
        pred_c_i = np.where(img_pred == c + 1, 1, 0)
        # Clip the value to compute the volumes
        gt_c_i = np.clip(gt_c_i, 0, 1)
        pred_c_i = np.clip(pred_c_i, 0, 1)

        # Compute the Dice
        dice = dc(gt_c_i, pred_c_i)
        try:
            h_d = hd(gt_c_i, pred_c_i) if ifhd else -1
        except:
            h_d = -1
        try:
            a_sd = asd(gt_c_i, pred_c_i) if ifasd else -1
        except:
            a_sd = -1
        res += [dice, h_d, a_sd]

    return res
示例#6
0
def metrics2(img_gt, img_pred, apply_hd=False, apply_asd=False):
    """
    evaluate the models on mmwhs data in batches
    :param img_gt: the ground truth
    :param img_pred: the prediction
    :param apply_hd: whether to evaluate Hausdorff Distance
    :param apply_asd: whether to evaluate Average Surface Distance
    :return:
    """
    if img_gt.ndim != img_pred.ndim:
        raise ValueError("The arrays 'img_gt' and 'img_pred' should have the "
                         "same dimension, {} against {}".format(img_gt.ndim,
                                                                img_pred.ndim))
    res = {}
    class_name = ["myo", "la", "lv", "aa"]
    # Loop on each classes of the input images
    for c, cls_name in zip([1, 2, 3, 4], class_name) :

        gt_c_i = np.where(img_gt == c, 1, 0)
        pred_c_i = np.where(img_pred == c, 1, 0)

        # Compute the Dice
        dice = dc(gt_c_i, pred_c_i)
        h_d, a_sd = 0, 0
        if apply_hd:
            h_d = hd(gt_c_i, pred_c_i)
        if apply_asd:
            a_sd = asd (gt_c_i, pred_c_i)
        res[cls_name] = [dice, h_d, a_sd]
    return res
示例#7
0
def get_outputs(seg, seg_truth):
    print seg.shape, seg_truth.shape
    seg_thresh = utility.threshold(seg,THRESHOLD)
    print seg_thresh.shape
    contour = utility.listSegToContours(seg_thresh, meta_test[1,:],
        meta_test[0,:], ISOVALUE)
    errs = utility.listAreaOverlapError(contour, contours_test)
    thresh,ts = utility.cum_error_dist(errs,DX)
    roc = roc_curve(np.ravel(seg_truth),np.ravel(seg), pos_label=1)
    pr = precision_recall_curve(np.ravel(seg_truth),np.ravel(seg), pos_label=1)
    dorf = []
    emd = []
    asdl = []
    dice = []
    prec = []
    for i in range(len(seg_truth)):
        if np.sum(seg_thresh[i,:,:]) > 0.1 and np.sum(seg_truth[i,:,:,0]) > 0.1:
            e= hd(seg_thresh[i,:,:],seg_truth[i,:,:,0],meta_test[0,i][0])
            dorf.append(e)

            e_asd= assd(seg_thresh[i,:,:],seg_truth[i,:,:,0],meta_test[0,i][0])
            asdl.append(e_asd)
            # if np.sum(seg_thresh[i,:,:]) < 600 and np.sum(seg_truth[i,:,:,0]) < 600:
            #     print i,np.sum(seg_thresh[i,:,:]),np.sum(seg_truth[i,:,:,0])
            #     e_emd = utility.EMDSeg(seg_truth[i,:,:,0],seg_thresh[i,:,:], meta_test[0,i][0])
            #     emd.append(e_emd)

        edc = dc(seg_thresh[i,:,:],seg_truth[i,:,:,0])
        dice.append(edc)
        prec.append(precision(seg_thresh[i,:,:],seg_truth[i,:,:,0]))
    acc,mean_acc = calc_accuracy(seg, seg_truth)
    return (contour,errs,thresh,roc,pr,acc,mean_acc,dorf,dice, prec,asdl)
示例#8
0
def compute_metrics_on_directories_raw(dir_gt, dir_pred):
    """
    Calculates all possible metrics (the ones from the metrics script as well as
    hausdorff and average symmetric surface distances)

    :param dir_gt: Directory of the ground truth segmentation maps.
    :param dir_pred: Directory of the predicted segmentation maps.
    :return:
    """

    lst_gt = sorted(glob(os.path.join(dir_gt, '*')), key=natural_order)
    lst_pred = sorted(glob(os.path.join(dir_pred, '*')), key=natural_order)

    res = []
    cardiac_phase = []
    file_names = []

    measure_names = [
        'Dice LV', 'Volume LV', 'Err LV(ml)', 'Dice RV', 'Volume RV',
        'Err RV(ml)', 'Dice MYO', 'Volume MYO', 'Err MYO(ml)', 'Hausdorff LV',
        'Hausdorff RV', 'Hausdorff Myo', 'ASSD LV', 'ASSD RV', 'ASSD Myo'
    ]

    res_mat = np.zeros((len(lst_gt), len(measure_names)))

    ind = 0
    for p_gt, p_pred in zip(lst_gt, lst_pred):
        if os.path.basename(p_gt) != os.path.basename(p_pred):
            raise ValueError("The two files don't have the same name"
                             " {}, {}.".format(os.path.basename(p_gt),
                                               os.path.basename(p_pred)))

        gt, _, header = load_nii(p_gt)
        pred, _, _ = load_nii(p_pred)
        zooms = header.get_zooms()
        res.append(metrics(gt, pred, zooms))
        cardiac_phase.append(
            os.path.basename(p_gt).split('.nii.gz')[0].split('_')[-1])

        file_names.append(os.path.basename(p_pred))

        res_mat[ind, :9] = metrics(gt, pred, zooms)

        for ii, struc in enumerate([3, 1, 2]):

            gt_binary = (gt == struc) * 1
            pred_binary = (pred == struc) * 1

            res_mat[ind, 9 + ii] = hd(gt_binary,
                                      pred_binary,
                                      voxelspacing=zooms,
                                      connectivity=1)
            res_mat[ind, 12 + ii] = assd(pred_binary,
                                         gt_binary,
                                         voxelspacing=zooms,
                                         connectivity=1)

        ind += 1

    return res_mat, cardiac_phase, measure_names, file_names
def metrics(img_gt, img_pred, voxel_size):
    """
    Function to compute the metrics between two segmentation maps given as input.

    Parameters
    ----------
    img_gt: np.array
    Array of the ground truth segmentation map.

    img_pred: np.array
    Array of the predicted segmentation map.

    voxel_size: list, tuple or np.array
    The size of a voxel of the images used to compute the volumes.

    Return
    ------
    A list of metrics in this order, [Dice LV, Volume LV, Err LV(ml),
    Dice RV, Volume RV, Err RV(ml), Dice MYO, Volume MYO, Err MYO(ml)]
    """

    if img_gt.ndim != img_pred.ndim:
        raise ValueError("The arrays 'img_gt' and 'img_pred' should have the "
                         "same dimension, {} against {}".format(
                             img_gt.ndim, img_pred.ndim))

    res = []
    # Loop on each classes of the input images
    for c in [3, 1, 2]:
        # Copy the gt image to not alterate the input
        gt_c_i = np.copy(img_gt)
        gt_c_i[gt_c_i != c] = 0

        # Copy the pred image to not alterate the input
        pred_c_i = np.copy(img_pred)
        pred_c_i[pred_c_i != c] = 0

        # Clip the value to compute the volumes
        gt_c_i = np.clip(gt_c_i, 0, 1)
        pred_c_i = np.clip(pred_c_i, 0, 1)

        # Compute the Dice
        dice = dc(gt_c_i, pred_c_i)
        try:
            hausdorff = hd(pred_c_i, gt_c_i)
        except Exception as e:
            hausdorff = np.NaN
            #hausdorff = img_gt.shape[0]/4 # mark this hausdorff as a really huge error
            print(str(e))
        # Compute volume
        volpred = pred_c_i.sum() * np.prod(voxel_size) / 1000.
        volgt = gt_c_i.sum() * np.prod(voxel_size) / 1000.

        res += [dice, volpred, volpred - volgt, hausdorff]

    return res
def numpy_haussdorf(pred: np.ndarray,
                    target: np.ndarray,
                    voxelspacing: Union[float, List[float]] = None) -> float:
    assert len(pred.shape) == 2
    assert pred.shape == target.shape

    # h = max(directed_hausdorff(pred, target)[0], directed_hausdorff(target, pred)[0])
    try:
        h = hd(pred, target, voxelspacing)
    except RuntimeError:
        h = 0
    return h
示例#11
0
def compute_hausdorff(pred_label, gt_label, mode='max'):
    assert (pred_label.shape == gt_label.shape)
    hdf_dist = 0.0
    n = 0
    max_slice = 0
    hd_list = []
    #hausdorff_distance_filter = sitk.HausdorffDistanceImageFilter()
    for ii in range(pred_label.shape[0]):
        if (pred_label[ii].sum() == 0 or gt_label[ii].sum() == 0):
            hd_list.append(0)
            continue
        #print(ii,hd(pred_label[ii], gt_label[ii]))
        if mode == 'max':
            # hausdorff_distance_filter.Execute(sitk.GetImageFromArray(pred_label[ii]), sitk.GetImageFromArray(gt_label[ii]))
            # dist = hausdorff_distance_filter.GetHausdorffDistance()
            # hdf_dist = max(hdf_dist, dist)
            dist_i = hd(pred_label[ii], gt_label[ii])
            if dist_i > hdf_dist:
                hdf_dist = dist_i
                max_slice = ii
        elif mode == 'avg':
            # hausdorff_distance_filter.Execute(sitk.GetImageFromArray(pred_label[ii]), sitk.GetImageFromArray(gt_label[ii]))
            # dist = hausdorff_distance_filter.GetHausdorffDistance()
            # hdf_dist += dist
            hdf_dist += hd(pred_label[ii], gt_label[ii])
            n += 1
        elif mode == 'every':
            dist_i = hd(pred_label[ii], gt_label[ii])
            hd_list.append(dist_i)

    if mode == 'max':
        return hdf_dist, max_slice
    elif mode == 'avg':
        final_dist = hdf_dist / n if n != 0 else hdf_dist
        return final_dist
    else:
        return hd_list
示例#12
0
def hausdorff(preds: Tensor, target: Tensor, spacing: Tensor = None) -> Tensor:
    assert preds.shape == target.shape
    assert one_hot(preds)
    assert one_hot(target)

    B, K, *img_shape = preds.shape

    if spacing is None:
        D: int = len(img_shape)
        spacing = torch.ones((B, D), dtype=torch.float32)

    assert spacing.shape == (B, len(img_shape))

    res = torch.zeros((B, K), dtype=torch.float32, device=preds.device)
    n_pred = preds.cpu().numpy()
    n_target = target.cpu().numpy()
    n_spacing = spacing.cpu().numpy()

    for b in range(B):
        # print(spacing[b])
        # if K == 2:
        #     res[b, :] = hd(n_pred[b, 1], n_target[b, 1], voxelspacing=n_spacing[b])
        #     continue

        for k in range(K):
            if not n_target[b, k].any():  # No object to predict
                if n_pred[b, k].any():  # Predicted something nonetheless
                    res[b, k] = sum(
                        (dd * d)**2
                        for (dd, d) in zip(n_spacing[b], img_shape))**0.5
                    continue
                else:
                    res[b, k] = 0
                    continue
            if not n_pred[b, k].any():
                if n_target[b, k].any():
                    res[b, k] = sum(
                        (dd * d)**2
                        for (dd, d) in zip(n_spacing[b], img_shape))**0.5
                    continue
                else:
                    res[b, k] = 0
                    continue

            res[b, k] = hd(n_pred[b, k],
                           n_target[b, k],
                           voxelspacing=n_spacing[b])

    return res
def binary_measures_numpy(result, target, binary_threshold=0.5):
    result_binary = (result > binary_threshold).astype(numpy.uint8)
    target_binary = (target > binary_threshold).astype(numpy.uint8)

    result = BinaryMeasuresDto(mpm.dc(result_binary, target_binary), numpy.Inf,
                               numpy.Inf,
                               mpm.precision(result_binary, target_binary),
                               mpm.sensitivity(result_binary, target_binary),
                               mpm.specificity(result_binary, target_binary))

    if result_binary.any() and target_binary.any():
        result.hd = mpm.hd(result_binary, target_binary)
        result.assd = mpm.assd(result_binary, target_binary)

    return result
示例#14
0
def process_model(c,files,mhas):
    errs = []
    dorf = []
    asd = []
    ravd_arr = []
    dc_arr = []
    vols = []
    for f in files:
        mod = f.replace('truth',c)

        img_name = f.split('.')[0]
        img_file = [i for i in mhas if img_name in i][0]

        print f, mod, img_file

        ref_img = sitk.ReadImage(img_file)

        p1 = utility.readVTKPD(vtk_dir+f)
        p2 = utility.readVTKPD(vtk_dir+mod)
        e = utility.jaccard3D_pd_to_itk(p1,p2,ref_img)
        errs.append(e)

        np1 = utility.pd_to_numpy_vol(p1, spacing=ref_img.GetSpacing(), shape=ref_img.GetSize(), origin=ref_img.GetOrigin() )
        np2 = utility.pd_to_numpy_vol(p2, spacing=ref_img.GetSpacing(), shape=ref_img.GetSize(), origin=ref_img.GetOrigin() )
        if np.sum(np1) > 0 and np.sum(np2) > 0:
            e = hd(np1,np2, ref_img.GetSpacing()[0])
            dorf.append(e)

            e_asd = assd(np1,np2, ref_img.GetSpacing()[0])
            asd.append(e_asd)

            e_ravd = abs(ravd(np1,np2))
            ravd_arr.append(e_asd)

            e_dc = dc(np1,np2)
            dc_arr.append(e_dc)
        vols.append(np.sum(np1)*ref_img.GetSpacing()[0])
    np.save(output_dir+'{}.jaccard.npy'.format(c),errs)
    np.save(output_dir+'{}.dorf.npy'.format(c),dorf)
    np.save(output_dir+'{}.assd.npy'.format(c),asd)
    np.save(output_dir+'{}.ravd.npy'.format(c),ravd_arr)
    np.save(output_dir+'{}.dc.npy'.format(c),dc_arr)
    np.save(output_dir+'{}.vols.npy'.format(c),vols)

    return '{} , {}, {}, {}, {}, {}, {}, {}, {}, {}, {}\n'.format(\
    c,np.mean(errs),np.std(errs),np.mean(dorf),np.std(dorf),np.mean(asd),\
    np.std(asd), np.mean(ravd_arr),np.std(ravd_arr),np.mean(dc_arr),np.std(dc_arr))
示例#15
0
def evaluate_metrics(prediction, reference):
    results = {}
    for c,key in enumerate(["_RV", "_MYO", "_LV"],start=1):
        ref = np.copy(reference)
        pred = np.copy(prediction)

        ref = ref if c==0 else np.where(ref!=c, 0, ref)
        pred = pred if c==0 else np.where(np.rint(pred)!=c, 0, pred)

        try:
            results["DSC" + key] = binary.dc(np.where(ref!=0, 1, 0), np.where(np.rint(pred)!=0, 1, 0))
        except:
            results["DSC" + key] = 0
        try:
            results["HD" + key] = binary.hd(np.where(ref!=0, 1, 0), np.where(np.rint(pred)!=0, 1, 0))
        except:
            results["HD" + key] = np.nan
    return results
示例#16
0
def hausdorff_multilabel(y_true, y_pred, numLabels=4, channel='channel_first'):
    """
    :param y_true:
    :param y_pred:
    :param numLabels:
    :return:
    """
    assert channel=='channel_first' or channel=='channel_last', r"channel has to be either 'channel_first' or 'channel_last'"
    hd_score = 0
    if channel == 'channel_first':
        y_true = np.moveaxis(y_true, 1, -1)
        y_pred = np.moveaxis(y_pred, 1, -1)
    for index in range(1, numLabels):
        temp = hd(reference=y_true[:, :, :, index], result=y_pred[:, :, :, index])
        hd_score += temp

    hd_score = hd_score / (numLabels - 1)
    return hd_score
示例#17
0
def evaluate(img_gt, img_pred, apply_hd=False, apply_asd=False):
    """
    Function to compute the metrics between two segmentation maps given as input.
    :param img_gt: Array of the ground truth segmentation map.
    :param img_pred: Array of the predicted segmentation map.
    :param apply_hd: whether to compute Hausdorff Distance.
    :param apply_asd: Whether to compute Average Surface Distance.
    :return: A list of metrics in this order, [dice myo, hd myo, asd myo, dice lv, hd lv asd lv, dice rv, hd rv, asd rv]
    """

    if img_gt.ndim != img_pred.ndim:
        raise ValueError("The arrays 'img_gt' and 'img_pred' should have the "
                         "same dimension, {} against {}".format(img_gt.ndim,
                                                                img_pred.ndim))

    res = {}
    class_name = ["myo", "lv", "rv"]
    # Loop on each classes of the input images
    for c, cls_name in zip([1, 2, 3], class_name) :
        # Copy the gt image to not alterate the input
        gt_c_i = np.copy(img_gt)
        gt_c_i[gt_c_i != c] = 0

        # Copy the pred image to not alterate the input
        pred_c_i = np.copy(img_pred)
        pred_c_i[pred_c_i != c] = 0

        # Clip the value to compute the volumes
        gt_c_i = np.clip(gt_c_i, 0, 1)
        pred_c_i = np.clip(pred_c_i, 0, 1)

        # Compute the Dice
        dice = dc(gt_c_i, pred_c_i)
        h_d, a_sd = 0, 0
        if apply_hd:
            h_d = hd(gt_c_i, pred_c_i)
        if apply_asd:
            a_sd = asd (gt_c_i, pred_c_i)

        # Compute volume
        res[cls_name] = [dice, h_d, a_sd]

    return res
示例#18
0
    def metrics(img_gt, img_pred, ifhd=True, ifasd=True):
        """
        Function to compute the metrics between two segmentation maps given as input.

        img_gt: Array of the ground truth segmentation map.

        img_pred: Array of the predicted segmentation map.
        Return: A list of metrics in this order, [Dice endo, HD endo, ASD endo, Dice RV, HD RV, ASD RV, Dice MYO, HD MYO, ASD MYO]
        """

        if img_gt.ndim != img_pred.ndim:
            raise ValueError("The arrays 'img_gt' and 'img_pred' should have the "
                             "same dimension, {} against {}".format(img_gt.ndim,
                                                                    img_pred.ndim))
        res = []
        # cat = {500: 'endo', 600: 'rv', 200: 'myo'}
        for c in [500, 600, 200]:
            # Copy the gt image to not alterate the input
            gt_c_i = np.copy(img_gt)
            gt_c_i[gt_c_i != c] = 0

            # Copy the pred image to not alterate the input
            pred_c_i = np.copy(img_pred)
            pred_c_i[pred_c_i != c] = 0

            # Clip the value to compute the volumes
            gt_c_i = np.clip(gt_c_i, 0, 1)
            pred_c_i = np.clip(pred_c_i, 0, 1)
            # Compute the Dice
            dice = dc(gt_c_i, pred_c_i)

            h_d, a_sd = -1, -1
            if ifhd or ifasd:
                if np.sum(gt_c_i) == 0 or np.sum(pred_c_i) == 0:
                    dice = -1
                    h_d = -1
                    a_sd = -1
                else:
                    h_d = hd(gt_c_i, pred_c_i) if ifhd else h_d
                    a_sd = asd(gt_c_i, pred_c_i) if ifasd else a_sd
            res += [dice, h_d, a_sd]

        return res
示例#19
0
def hd_3D(img_pred, img_gt, labels=[3, 1, 2]):
    res = []
    for c in labels:
        gt_c_i = np.copy(img_gt)
        gt_c_i[gt_c_i != c] = 0

        pred_c_i = np.copy(img_pred)
        pred_c_i[pred_c_i != c] = 0

        gt_c_i = np.clip(gt_c_i, 0, 1)
        pred_c_i = np.clip(pred_c_i, 0, 1)

        if np.sum(pred_c_i) == 0 or np.sum(gt_c_i) == 0:
            hausdorff = 0
        else:
            hausdorff = hd(pred_c_i, gt_c_i)

        res += [hausdorff]

    return res
示例#20
0
def run_hd(image1, image2, mode='max'):

    image1_data, hd1 = nrrd.read(image1)
    space_x = np.abs(hd1['space directions'][0, 0])
    space_y = np.abs(hd1['space directions'][1, 1])
    space_z = np.abs(hd1['space directions'][2, 2])
    image2_data, hd2 = nrrd.read(image2)
    if (hd1['space origin'] == hd2['space origin']).all():
        if mode == 'max':
            hd_val = hd(image1_data, image2_data, (space_x, space_y, space_z))
        elif mode == '95':
            hd_val = hd95(image1_data, image2_data,
                          (space_x, space_y, space_z))
        else:
            raise Exception(
                'Unknown mode "{}". Possible values are "max" or "95".'.format(
                    mode))
    else:
        hd_val = None
    return hd_val
示例#21
0
def hausdorff_eval(y_true,
                   y_pred,
                   voxelspacing=None,
                   connectivity=1,
                   threshold=0.5):

    if not isinstance(y_true, (np.ndarray, np.generic)):
        y_true = np.asarray(y_true)

    if not isinstance(y_pred, (np.ndarray, np.generic)):
        y_pred = np.asarray(y_pred)

    y_pred = np.where(np.array(y_pred) > threshold, 1, 0)
    try:
        hd_score = hd(y_true,
                      y_pred,
                      voxelspacing=voxelspacing,
                      connectivity=connectivity)
    except:
        hd_score = 0
    return hd_score
示例#22
0
def compute_scores(preds, labels):
    preds_data = preds.data.cpu().numpy()
    labels_data = labels.data.cpu().numpy()

    dice_score = dc(preds_data, labels_data)
    jaccard_coef = jc(preds_data, labels_data)
    hausdorff_dist = hd(preds_data, labels_data)
    asd_score = asd(preds_data, labels_data)
    assd_score = assd(preds_data, labels_data)
    precision_value = precision(preds_data, labels_data)
    recall_value = recall(preds_data, labels_data)
    sensitivity_value = sensitivity(preds_data, labels_data)
    specificity_value = specificity(preds_data, labels_data)
    return {
        'dice score': dice_score,
        'jaccard': jaccard_coef,
        'hausdorff': hausdorff_dist,
        'asd': asd_score,
        'assd': assd_score,
        'precision': precision_value,
        'recall': recall_value,
        'sensitivity': sensitivity_value,
        'specificity': specificity_value
    }
示例#23
0
def get_hd_metric(batch_result, batch_reference, pixel_size_mm=1,
                  by_label=True):
    """Computes the Hausdorff Distance (HD) between two masks
    from two batches."""
    if batch_result.shape != batch_reference.shape:
        raise ValueError('The input batches must be the same size')

    batch_result = get_one_hot_encoding_from_hard_segm(
        np.asarray(batch_result),
        labels=np.unique(batch_reference)).astype(np.bool)
    batch_reference = get_one_hot_encoding_from_hard_segm(
        np.asarray(batch_reference)).astype(np.bool)

    dims = batch_result.shape
    hd_values = np.ndarray(shape=(dims[0], dims[-1] - 1), dtype=np.float32)
    for i in range(dims[0]):
        for l in range(1, dims[-1]):
            hd_values[i, l - 1] = hd(
                batch_result[i, :, :, l], batch_reference[i, :, :, l])

    if not by_label:
        hd_values = np.mean(hd_values, axis=1)

    return hd_values * float(pixel_size_mm)
示例#24
0
def main(_):
  if not FLAGS.dataset_dir:
    raise ValueError('You must supply the dataset directory with --dataset_dir')

  tf.logging.set_verbosity(tf.logging.INFO)
  with tf.Graph().as_default():
    tf_global_step = slim.get_or_create_global_step()
    ######################
    # Gnerate the tfRecorder data #
    ######################
    datareader,Volshape,rindex,spmap,labelOrg,imgOrg=EvalSample_Gnerate(FLAGS.dataset_dir, 'Glabel.nrrd')
    Patchsize=len(rindex)
    ######################
    # Select the dataset #
    ######################

    dataset = dataset_factory.get_dataset(
        FLAGS.dataset_name, FLAGS.dataset_split_name, FLAGS.dataset_dir,file_pattern=FLAGS.file_name,Datasize=Patchsize)

    ####################
    # Select the model #
    ####################
    #num_classes=2

    with tf.Graph().as_default():
        network_fn = nets_factory.get_network_fn(
                FLAGS.model_name,
                num_classes=(dataset.num_classes - FLAGS.labels_offset),
                is_training=False)

    ##############################################################
    # Create a dataset provider that loads data from the dataset #
    ##############################################################

    provider = slim.dataset_data_provider.DatasetDataProvider(
        dataset,
        shuffle=False,
        common_queue_capacity=2 * FLAGS.batch_size,
        common_queue_min=FLAGS.batch_size)
    [image, label] = provider.get(['image', 'label'])
    # label -= FLAGS.labels_offset

    #####################################
    # Select the preprocessing function #
    #####################################
    preprocessing_name = FLAGS.preprocessing_name or FLAGS.model_name
    image_preprocessing_fn = preprocessing_factory.get_preprocessing(
                 preprocessing_name,
                 is_training=False)

    eval_image_size = FLAGS.eval_image_size or network_fn.default_image_size
    image = image_preprocessing_fn(image, eval_image_size, eval_image_size)

    images, labels = tf.train.batch(
             [image, label],
             batch_size=FLAGS.batch_size,
             num_threads=FLAGS.num_preprocessing_threads,
             capacity=5 * FLAGS.batch_size)

     ###################
    # Define the model #
    ####################

    logits, end_points = network_fn(images)
    probabilities = tf.nn.softmax(logits)
    pred = tf.argmax(logits, dimension=1)
    # if FLAGS.moving_average_decay:
    #   variable_averages = tf.train.ExponentialMovingAverage(
    #       FLAGS.moving_average_decay, tf_global_step)
    #   variables_to_restore = variable_averages.variables_to_restore(
    #       slim.get_model_variables())
    #   variables_to_restore[tf_global_step.op.name] = tf_global_step
    # else:
    #   variables_to_restore = slim.get_variables_to_restore()

    # #predictions = tf.argmax(logits, 1)
    # labels = tf.squeeze(labels)
    #
    # # Define the metrics:
    # names_to_values, names_to_updates = slim.metrics.aggregate_metric_map({
    #     'Accuracy': slim.metrics.streaming_accuracy(predictions, labels),
    #     'Recall@5': slim.metrics.streaming_recall_at_k(
    #         logits, labels, 5),
    # })
    #
    # # Print the summaries to screen.
    # summary_ops = []
    # for name, value in names_to_values.items():
    #   summary_name = 'eval/%s' % name
    #   op = tf.scalar_summary(summary_name, value, collections=[])
    #   op = tf.Print(op, [value], summary_name)
    #   tf.add_to_collection(tf.GraphKeys.SUMMARIES, op)
    #   summary_ops.append(op)
    # # TODO(sguada) use num_epochs=1
    # if FLAGS.max_num_batches:
    #   num_batches = FLAGS.max_num_batches
    # else:
    #   # This ensures that we make a single pass over all of the data.
    #   num_batches = math.ceil(dataset.num_samples / float(FLAGS.batch_size))

    if tf.gfile.IsDirectory(FLAGS.checkpoint_path):
            checkpoint_path = tf.train.latest_checkpoint(FLAGS.checkpoint_path)
    else:
            checkpoint_path = FLAGS.checkpoint_path

    tf.logging.info('Evaluating %s' % checkpoint_path)
    init_fn = slim.assign_from_checkpoint_fn(
                os.path.join(checkpoint_path),
                slim.get_model_variables())# vriable name???

    #Volshape=(50,61,61)
    imgshape=spmap.shape
    segResult=np.zeros(imgshape)
    groundtruth=np.zeros(imgshape)
    segPromap=np.zeros(imgshape)
    segPromapEdge=np.zeros(imgshape)
    PreMap=[]
    labellist=[]
    seglist=[]
    conv1list=[]
    conv2list=[]
    imgorglist=[]
    fclist=[]
    with tf.Session() as sess:
            # Load weights
            init_fn(sess)
           # sess.run(images.initializer, feed_dict)
            # Start input enqueue threads.
            coord = tf.train.Coordinator()
            threads = tf.train.start_queue_runners(sess=sess, coord=coord)

            num_iter = int(math.ceil(dataset.num_samples/float(FLAGS.batch_size)))
            step = 0

            try:
                while step < num_iter and not coord.should_stop():
                    # Run evaluation steps or whatever
                    segmentation,log,pmap,labelmap,imgpre,conv1,conv2,fc3= sess.run([pred,logits,probabilities,labels,images,end_points['conv1'],end_points['conv3'],end_points['fc3']])
                    step+=1
                    PreMap.extend(pmap)
                    conv1list.extend(conv1)
                    conv2list.extend(conv2)
                    fclist.extend(fc3)
                    imgorglist.extend(imgpre)
                    seglist.append(segmentation)
                    labellist.append(labelmap)
                    print('The No. %d/%d caculation'%(step,num_iter))
                    #Miaimshow.subplots(Pro_imgs, num=step+2, cols=8)
            except tf.errors.OutOfRangeError:
                print('Done evalutaion -- epoch limit reached')
            finally:
                # When done, ask the threads to stop.
                coord.request_stop()
            PreMap = np.array(PreMap)
            np.save(os.path.join(FLAGS.dataset_dir,'liverspProbmap.npy'), PreMap)
            # PreMap=np.squeeze(PreMap,axis=1)

           # PreMap_flat = PreMap.ravel()
           # PreMap_flat=np.divide((PreMap_flat - np.amin(PreMap_flat)) * 255, (np.amax(PreMap_flat) - np.amin(PreMap_flat)))
            m = 0
            for i in range(len(rindex)):
                segResult[spmap==rindex[i]]=np.array(seglist).ravel()[i]
                segPromap[spmap==rindex[i]]=PreMap[i,1]
                segPromapEdge[spmap==rindex[i]]=PreMap[i,2]
                groundtruth[spmap==rindex[i]]=np.array(labellist).ravel()[i]

            coord.join(threads)

            fig,ax= plt.subplots(nrows=2,ncols=3)

            from skimage.segmentation import mark_boundaries
            ax[0,0].set_title('Segmentation with superpixel map')
            ax[0,0].imshow(mark_boundaries(segResult, spmap))
            ax[0,1].set_title('Segmentation with ground truth map')
            ax[0,1].imshow(segResult)
            ax[0,1].imshow(labelOrg,alpha=0.5,cmap='jet')
            ax[0,2].set_title('Reading label')
            ax[0,2].imshow(groundtruth)

            ax[1,0].set_title('liver Probabilities map')
            ax[1,0].imshow(segPromap)
            ax[1,1].set_title('edge Probabilities map')
            ax[1,1].imshow(segPromapEdge)
            ax[1,2].set_title('liver +edge Probabilities map')
            ax[1,2].imshow(segPromapEdge+segPromap)

            segthpro=segPromapEdge+segPromap
            segthpro[segthpro<0.8]=0

    from skimage.segmentation import active_contour
    from skimage.measure import find_contours
    from skimage.filters import gaussian
    from skimage import morphology

    #edg=sobel(segResult.astype(int))
    segmorp=morphology.remove_small_objects(segthpro.astype(bool),5000)
    segopen=morphology.opening(segmorp,morphology.disk(3))
    segclose=morphology.closing(segopen,morphology.disk(15))
    fig,ax=plt.subplots(1,3)
    ax=ax.ravel()
    ax[0].imshow(segmorp)
    ax[0].set_title('Removed the small objects')
    ax[1].imshow(segopen)
    ax[1].set_title('After open operation')
    ax[2].imshow(segclose)
    ax[2].imshow(labelOrg,alpha=0.5,cmap='jet')
    ax[2].set_title('After close operation')
    plt.axis('off')
    from MiaUtils import Miametrics as metric
    mt=metric.MiaMetrics(logger)
    dsc=mt.DSCMetric(segclose,labelOrg.astype(bool))
    print('The dice similarity coefficient score is {}'.format(dsc))

    voe=mt.VOEMetric(segclose,labelOrg.astype(bool))
    print('The Volume overlap Error score is {}'.format(voe))

    rvd=mt.RVDMetric(segclose,labelOrg.astype(bool))
    print('The Relative voume difference score is {}'.format(rvd))

    from medpy.metric.binary import hd
    from medpy.metric.binary import asd
    from medpy.metric.binary import  obj_fpr
    from medpy.metric.binary import  obj_tpr
    Asd=asd(segclose,labelOrg.astype(bool))
    print('The Asd score is {}'.format(Asd))

    HD=hd(segclose,labelOrg.astype(bool))
    print('The Hausdorff Distance score is {}'.format(HD))
###************************************************************************
    ####superpixel-graph cuts mehtod computation
#######********************************************************************
    from skimage import segmentation, color,filters
    from skimage.future import graph
    img=DataNormalize(imgOrg)/255
    img=np.dstack((np.dstack((img, img)), img))
    labels1 = segmentation.slic(img, compactness=5, n_segments=2000,sigma=1)
    #labels1=spmap
    out1 = color.label2rgb(labels1, img, kind='avg')
    edge_map = filters.sobel(color.rgb2gray(img))
    g = graph.rag_boundary(labels1, edge_map)
    #g = graph.rag_mean_color(img, labels1, mode='similarity')
    labels2 = graph.cut_normalized(labels1, g)
    out2 = color.label2rgb(labels2, img, kind='avg')

    fig, ax = plt.subplots(nrows=2, sharex=True, sharey=True)
    ax[0].imshow(out1)
    ax[1].imshow(out2)
    for a in ax:
       a.axis('off')
    plt.tight_layout()
示例#25
0
                                np.save(os.path.join(save_dir, str(epochs) + 'epochs_mask_prediction'), mask_prediction)
                                np.save(os.path.join(save_dir, str(epochs) + 'test_images'), test_images)
                                np.save(os.path.join(save_dir, str(epochs) + 'test_masks'), test_masks)
                                np.save(os.path.join(save_dir, str(epochs) + 'rounded_mask_pred'), rounded_pred)

                                mask_prediction = model.predict(test_images, verbose=0)
                                mask_prediction = np.squeeze(mask_prediction, 3)

                                rounded_dice = []
                                dice = []
                                thresholded_hausdorff = []
                                hausdorff = []
                                for s in range(test_masks.shape[0]):
                                    rounded_dice.append(getdicescore(test_masks[s, :, :, 0], rounded_pred[s, :, :]))
                                    if np.max(rounded_pred[s, :, :]) != 0:
                                        thresholded_hausdorff.append(hd(rounded_pred[s, :, :], test_masks[s, :, :, 0]))

                                median_rounded_dice_score = np.median(rounded_dice)
                                median_thresholded_hausdorff = np.mean(thresholded_hausdorff)

                                median_thresholded_hausdorff = round(median_thresholded_hausdorff, 2)
                                median_rounded_dice_score = round(median_rounded_dice_score, 3)




                                #save_visualisation2(train_images[:, :, :, 0], train_masks[:, :, :, 0], median_rounded_dice_score, median_thresholded_hausdorff, save_dir)
                                save_visualisation(test_images[:,:,:,0], test_masks[:,:,:,0], mask_prediction, rounded_pred,
                                                   median_rounded_dice_score, median_thresholded_hausdorff, prefix, save_dir)

示例#26
0
                                    rounded_pred)

                                rounded_dice = []
                                dice = []
                                thresholded_hausdorff = []
                                hausdorff = []
                                for s in range(test_masks.shape[0]):
                                    rounded_dice.append(
                                        getdicescore(test_masks[s, :, :, 0],
                                                     rounded_pred[s, :, :]))
                                    dice.append(
                                        getdicescore(test_masks[s, :, :, 0],
                                                     mask_prediction[s, :, :]))
                                    if np.max(rounded_pred[s, :, :]) != 0:
                                        thresholded_hausdorff.append(
                                            hd(rounded_pred[s, :, :],
                                               test_masks[s, :, :, 0]))
                                    if np.max(rounded_pred[s, :, :]) != 0:
                                        hausdorff.append(
                                            hd(rounded_pred[s, :, :],
                                               test_masks[s, :, :, 0]))

                                median_rounded_dice_score = np.median(
                                    rounded_dice)
                                median_thresholded_hausdorff = np.mean(
                                    thresholded_hausdorff)

                                median_thresholded_hausdorff = round(
                                    median_thresholded_hausdorff, 2)
                                median_rounded_dice_score = round(
                                    median_rounded_dice_score, 3)
示例#27
0
def get_geometrical_results(model, data, groundtruths, path, inds, use_pp):
    """Compute Dices, Hausdorff distances and ASSDs between the model predictions on the inds indices of data and the groundtruths
       use_pp enables to use post-processing on the predictions. The original image sizes are stored in inds"""

    # Get predictions from the input data
    segmentations = model.predict(data, verbose=1)
    predictions = np.argmax(segmentations, axis=-1)

    voxel_spacing = [0.154, 0.308]

    nb_im = predictions.shape[0]
    nb_struct = groundtruths.shape[-1] - 1
    results = np.zeros((nb_im, nb_struct, 3), dtype=np.float)

    size_file = open(join(path, 'ori_sizes.txt'), 'r')
    sizes = size_file.readlines()

    # get image indices
    indices = []
    for ind in inds:
        indices.append(ind * 2)
        indices.append(ind * 2 + 1)

    for im in tnrange(nb_im, desc="Evaluation on each image"):

        # Reshape the prediction as a binary class matrix
        pred_cat = keras.utils.to_categorical(predictions[im, :, :],
                                              num_classes=4)

        # get original size from the relative indexing
        line = sizes[indices[im] - 600]
        ori_size = [int(line.split()[2][1:-1]), int(line.split()[3][0:-1])]

        for struct in range(1, nb_struct + 1):

            # Extract the structure channel
            pred = pred_cat[:, :, struct]
            gt = groundtruths[im, :, :, struct]

            # Resize to the original size
            pred = np.array(
                Image.fromarray(pred).resize(
                    (ori_size[1], ori_size[0]), PIL.Image.NEAREST)).astype(
                        'uint8')  #Image.resize inverts dimensions
            gt = np.array(
                Image.fromarray(gt).resize((ori_size[1], ori_size[0]),
                                           PIL.Image.NEAREST)).astype('uint8')

            # Transform into boolean array
            pred = (pred == 1)
            gt = (gt == 1)

            # Apply postprocessing
            if use_pp:
                pred = post_process(pred)

            #  Compute geometrical metrics using the medpy library
            dice = dc(pred, gt)
            if np.sum(
                    pred
            ) > 0:  # If the structure is predicted on at least one pixel
                hausdorff = hd(
                    pred,
                    gt,
                    voxelspacing=[voxel_spacing[0], voxel_spacing[1]])
                asd = assd(pred,
                           gt,
                           voxelspacing=[voxel_spacing[0], voxel_spacing[1]])
            else:
                print("on image ", nb_im, "the structure ", struct,
                      " was not associated to any pixel")
                hausdorff = 'nan'
                asd = 'nan'

            results[im, struct - 1, :] = [dice, hausdorff, asd]

    return results, segmentations
示例#28
0
        ground_truth_componentSet = glob.glob(ground_truth_sequenceSet[0] +
                                              '/*')
        ground_truth_componentSet.sort()

        for component in range(0, len(componentSet)):
            time_frameSet = glob.glob(componentSet[component] +
                                      '/final_results/' + '*.nii.gz')
            time_frameSet.sort()

            ground_truth_time_frameSet = glob.glob(
                ground_truth_componentSet[component] + '/' + '*.nii.gz')
            ground_truth_time_frameSet.sort()
            ##### Dice score metric

            #sheet1.write(subject+1,component+1,Bin_dice(ground_truth_time_frameSet[0],time_frameSet[0]))
            #sheet2.write(subject+1,component+1,Bin_dice(ground_truth_time_frameSet[1],time_frameSet[len(time_frameSet)-1]))

            ##### Hausdroff distance metric
            im1 = nifti_to_array(ground_truth_time_frameSet[0])
            im2 = nifti_to_array(time_frameSet[0])
            im3 = nifti_to_array(ground_truth_time_frameSet[1])
            im4 = nifti_to_array(time_frameSet[len(time_frameSet) - 1])

            #sheet1.write(subject+1,component+1,hausdorff(np.argwhere(im1!=0), np.argwhere(im2!=0)))
            #sheet2.write(subject+1,component+1,hausdorff(np.argwhere(im3!=0), np.argwhere(im4!=0)))

            sheet1.write(subject + 1, component + 1, hd(im1, im2))
            sheet2.write(subject + 1, component + 1, hd(im3, im4))

book.save(save_path)
示例#29
0
def val_step(val_loader,
             model,
             criterion,
             weights_criterion,
             multiclass_criterion,
             binary_threshold,
             num_classes=4,
             generate_stats=False,
             generate_overlays=False,
             save_path="",
             swap_values=None):
    """
    Perform a validation step
    :param val_loader: (Dataloader) Validation dataset loader
    :param model: Model used in training
    :param criterion: Choosed criterion
    :param weights_criterion: (list -> float) Choosed criterion weights
    :param multiclass_criterion:
    :param binary_threshold: (float) Threshold to set class as class 1. Typically 0.5
    :param num_classes: Num total classes in predictions
    :param generate_stats: (bool) If true generate predictions stats via pandas
    :param generate_overlays: (bool) If true save mask predictions
    :param save_path: (string) If save_preds then which directory to save mask predictions
    :param swap_values: (list of lists) In predicted mask, swaps first item and second in list. Example: [[1,2]]
    :return: Intersection Over Union and Dice Metrics, Mean validation loss
    """
    # https://stackoverflow.com/questions/8713620/appending-items-to-a-list-of-lists-in-python
    ious, dices = [[] for _ in range(num_classes)
                   ], [[] for _ in range(num_classes)]
    hausdorffs, assds = [[] for _ in range(num_classes)
                         ], [[] for _ in range(num_classes)]
    val_loss, df_info = [], []
    model.eval()

    if save_path != "":
        os.makedirs(save_path, exist_ok=True)

    with torch.no_grad():
        for sample_indx, (image, original_img, original_mask, mask,
                          img_id) in enumerate(val_loader):

            original_mask = original_mask.cuda()
            image = image.type(torch.float).cuda()
            prob_pred = model(image)

            # ToDo: Fix val loss
            # val_loss.append(calculate_loss(mask, prob_pred, criterion, weights_criterion, multiclass_criterion).item())
            val_loss.append(0.0)

            for indx, single_pred in enumerate(prob_pred):

                original_mask = original_mask[indx].data.cpu().numpy().astype(
                    np.uint8).squeeze()

                # Calculate metrics resizing prediction to original mask shape
                pred_mask = convert_multiclass_mask(
                    single_pred.unsqueeze(0)).data.cpu().numpy()
                pred_mask = reshape_masks(pred_mask.squeeze(0),
                                          original_mask.shape)
                if swap_values is not None:
                    for swap_val in swap_values:
                        pred_mask = np.where(
                            pred_mask == swap_val[0], swap_val[1],
                            np.where(pred_mask == swap_val[1], swap_val[0],
                                     pred_mask))

                patient_iou = [-1, -1, -1]  # LV, MYO, RV
                patient_dice = [-1, -1, -1]  # LV, MYO, RV
                patient_hausddorf = [999, 999, 999]  # LV, MYO, RV
                patient_assd = [999, 999, 999]  # LV, MYO, RV

                for current_class in np.unique(
                        np.concatenate((original_mask, pred_mask))):

                    binary_ground_truth = np.where(
                        original_mask == current_class, 1, 0).astype(np.int32)
                    binary_pred_mask = np.where(pred_mask == current_class, 1,
                                                0).astype(np.int32)

                    tmp_iou = jaccard_coef(binary_ground_truth,
                                           binary_pred_mask)
                    tmp_dice = dice_coef(binary_ground_truth, binary_pred_mask)
                    # https://github.com/loli/medpy/blob/master/medpy/metric/binary.py#L1212
                    if not np.count_nonzero(
                            binary_pred_mask) and not np.count_nonzero(
                                binary_ground_truth):
                        # The same, distances 0
                        tmp_assd = 0
                        tmp_hausdorff = 0
                    elif not np.count_nonzero(
                            binary_pred_mask) or not np.count_nonzero(
                                binary_ground_truth):
                        # ToDo: equivalent worst value for Hausdorff and surface distances
                        tmp_assd = 999
                        tmp_hausdorff = 999
                    else:
                        tmp_assd = medmetrics.assd(binary_pred_mask,
                                                   binary_ground_truth)
                        tmp_hausdorff = medmetrics.hd(binary_pred_mask,
                                                      binary_ground_truth)

                    ious[current_class].append(tmp_iou)
                    dices[current_class].append(tmp_dice)
                    hausdorffs[current_class].append(tmp_hausdorff)
                    assds[current_class].append(tmp_assd)

                    # -1 Due index 0 is background
                    if current_class != 0:
                        patient_iou[current_class - 1] = tmp_iou
                        patient_dice[current_class - 1] = tmp_dice
                        patient_hausddorf[current_class - 1] = tmp_hausdorff
                        patient_assd[current_class - 1] = tmp_assd

                if generate_stats:
                    patient_info = img_id[0].split("_")
                    df_info.append({
                        "patient":
                        patient_info[0],
                        "slice":
                        patient_info[1][5:],
                        "phase":
                        patient_info[2][5:],
                        "IOU_LV":
                        patient_iou[0],
                        "IOU_MYO":
                        patient_iou[1],
                        "IOU_RV":
                        patient_iou[2],
                        "IOU_MEAN":
                        np.mean(
                            np.array([
                                value for value in patient_iou if value != -1
                            ])),
                        "DICE_LV":
                        patient_dice[0],
                        "DICE_MYO":
                        patient_dice[1],
                        "DICE_RV":
                        patient_dice[2],
                        "DICE_MEAN":
                        np.mean(
                            np.array([
                                value for value in patient_dice if value != -1
                            ])),
                        "HAUSDORFF_LV":
                        patient_hausddorf[0],
                        "HAUSDORFF_MYO":
                        patient_hausddorf[1],
                        "HAUSDORFF_RV":
                        patient_hausddorf[2],
                        "HAUSDORFF_MEAN":
                        np.mean(
                            np.array([
                                value for value in patient_hausddorf
                                if value != -999
                            ])),
                        "ASSD_LV":
                        patient_assd[0],
                        "ASSD_MYO":
                        patient_assd[1],
                        "ASSD_RV":
                        patient_assd[2],
                        "ASSD_MEAN":
                        np.mean(
                            np.array([
                                value for value in patient_assd
                                if value != -999
                            ])),
                    })

                if generate_overlays:
                    plot_save_pred(original_img.data.cpu().numpy().squeeze(),
                                   original_mask, pred_mask, save_path,
                                   img_id[0])

    stats = None
    if generate_stats:
        stats = pd.DataFrame(df_info)
        stats.to_csv(os.path.join(save_path, "val_patient_stats.csv"),
                     index=False)

    iou = [np.mean(i) for i in ious]  # Class mean, not global
    iou = np.append(
        np.mean(iou[1:]),
        iou)  # Add as first value global class mean (without background)

    dice = [np.mean(i) for i in dices]
    dice = np.append(np.mean(dice[1:]), dice)

    hausdorff = [np.mean(i) for i in hausdorffs]
    hausdorff = np.append(np.mean(hausdorff[1:]), hausdorff)

    assd = [np.mean(i) for i in assds]
    assd = np.append(np.mean(assd[1:]), assd)

    return iou, dice, hausdorff, assd, np.mean(val_loss), stats
示例#30
0
 def __call__(self, prediction, target):
     try:
         return binary.hd(prediction, target)
     except Exception:
         return np.nan
示例#31
0
def compute_metrics_on_directories_raw(dir_gt, dir_pred):
    """
    Calculates a number of measures from the predicted and ground truth segmentations:
    - Dice
    - Hausdorff distance
    - Average surface distance
    - Predicted volume
    - Volume error w.r.t. ground truth

    :param dir_gt: Directory of the ground truth segmentation maps.
    :param dir_pred: Directory of the predicted segmentation maps.
    :return: Pandas dataframe with all measures in a row for each prediction and each structure
    """

    filenames_gt = sorted(glob(os.path.join(dir_gt, '*')), key=natural_order)
    filenames_pred = sorted(glob(os.path.join(dir_pred, '*')), key=natural_order)

    cardiac_phase = []
    file_names = []
    structure_names = []

    # 5 measures per structure:
    dices_list = []
    hausdorff_list = []
    assd_list = []
    vol_list = []
    vol_err_list = []

    structures_dict = {1: 'RV', 2: 'Myo', 3: 'LV'}

    for p_gt, p_pred in zip(filenames_gt, filenames_pred):
        if os.path.basename(p_gt) != os.path.basename(p_pred):
            raise ValueError("The two files don't have the same name"
                             " {}, {}.".format(os.path.basename(p_gt),
                                               os.path.basename(p_pred)))

        # load ground truth and prediction
        gt, _, header = utils.load_nii(p_gt)
        pred, _, _ = utils.load_nii(p_pred)
        zooms = header.get_zooms()

        # calculate measures for each structure
        for struc in [3,1,2]:

            gt_binary = (gt == struc) * 1
            pred_binary = (pred == struc) * 1

            volpred = pred_binary.sum() * np.prod(zooms) / 1000.
            volgt = gt_binary.sum() * np.prod(zooms) / 1000.

            vol_list.append(volpred)
            vol_err_list.append(volpred - volgt)

            if np.sum(gt_binary) == 0 and np.sum(pred_binary) == 0:
                dices_list.append(1)
                assd_list.append(0)
                hausdorff_list.append(0)
            elif np.sum(pred_binary) > 0 and np.sum(gt_binary) == 0 or np.sum(pred_binary) == 0 and np.sum(gt_binary) > 0:
                logging.warning('Structure missing in either GT (x)or prediction. ASSD and HD will not be accurate.')
                dices_list.append(0)
                assd_list.append(1)
                hausdorff_list.append(1)
            else:
                hausdorff_list.append(hd(gt_binary, pred_binary, voxelspacing=zooms, connectivity=1))
                assd_list.append(assd(pred_binary, gt_binary, voxelspacing=zooms, connectivity=1))
                dices_list.append(dc(gt_binary, pred_binary))

            cardiac_phase.append(os.path.basename(p_gt).split('.nii.gz')[0].split('_')[-1])
            file_names.append(os.path.basename(p_pred))
            structure_names.append(structures_dict[struc])


    df = pd.DataFrame({'dice': dices_list, 'hd': hausdorff_list, 'assd': assd_list,
                       'vol': vol_list, 'vol_err': vol_err_list,
                      'phase': cardiac_phase, 'struc': structure_names, 'filename': file_names})

    return df
示例#32
0
print('dice coefficient',maxdice)    ############################# Val needs to be shown on GUI

#itemindex = np.where(dice==maxdata)
#itemindex = np.argmax(best_dice)
if axis in range (0,3):
	itemindex= best_dice[200:255].argmax() + 200
elif axis == 3:
	itemindex= best_dice[90:255].argmax() + 90

print('Intensity value at max dice',itemindex)

preds_perfect=(preds_train255>itemindex-1).astype(np.bool)
preds_perfect = preds_perfect[...,axis].squeeze()


haufdist= hd(preds_perfect,predictionmask,voxelspacing=None, connectivity=1)
print('Hausdorff Distance.',haufdist)   ############################# Val needs to be shown on GUI

####################################################################################################################################################################
# P-value and A-bland altman plot

pearson_stats=stats.pearsonr(preds_perfect.flatten(),predictionmask.flatten())
print('pearson values ','r-value :' ,pearson_stats[0],'p-value :',pearson_stats[1])     ############################# both Vals needs to be shown on GUI



mask_graph=predictionmask*255
#mask_graph=cv2.imread(maskimg,0)
#mask_graph=tf.keras.utils.to_categorical(mask_graph, num_classes=4, dtype='uint8')*255
#mask_graph= mask_graph[...,axis].squeeze()