def analysis_by_sizes(target, estimated, sizes):
    a = as_logical(target)
    b = as_logical(estimated)
    a_sub = masks_by_size(a, sizes)
    fp_sub = masks_by_size(np.logical_and(np.logical_not(a), b), sizes)
    tpd_list = [true_positive_det(a_i, b) for a_i in a_sub]
    tps_list = [true_positive_seg(a_i, b) for a_i in a_sub]
    fpd_list = [
        len(list(filter(bool, np.unique(bwlabeln(fp_i))))) for fp_i in fp_sub
    ]
    fps_list = [np.count_nonzero(fp_i) for fp_i in fp_sub]
    gtd_list = [
        len(list(filter(bool, np.unique(bwlabeln(a_i))))) for a_i in a_sub
    ]
    gts_list = [np.count_nonzero(a_i) for a_i in a_sub]
    tpf_list = [
        100.0 * tp_i / gt_i if gt_i > 0 else np.nan
        for tp_i, gt_i in zip(tpd_list, gtd_list)
    ]
    fpf_list = [
        100.0 * fp_i / (fp_i + tp_i) if fp_i + tp_i > 0 else 0
        for tp_i, fp_i in zip(tpd_list, fpd_list)
    ]
    dscd_list = [
        2.0 * tp_i / (tp_i + fp_i + gt_i) if gt_i > 0 else np.nan
        for tp_i, fp_i, gt_i in zip(tpd_list, fpd_list, gtd_list)
    ]
    dscs_list = [
        2.0 * tp_i / (tp_i + fp_i + gt_i) if gt_i > 0 else np.nan
        for tp_i, fp_i, gt_i in zip(tps_list, fps_list, gts_list)
    ]
    return tpf_list, fpf_list, dscd_list, dscs_list
def remove_boundary_regions(img_vol, mask_vol, boundary=2):
    """
    Function to remove regions that are inside the boundary of mask. The
    boundary's thickness can also be defined (default is 2 voxels).
    :param img_vol: Mask volume to process. It should be a numpy array of type
     bool.
    :param mask_vol: Mask from where the boundary area is defined.
    :param boundary: Boundary thickness (default = 2).
    :return: New mask without boundary regions.
    """
    # White matter lesions, should not be on the boundaries of a brain. That
    # region is where the cortex is located which can sometimes present
    # hyperintense artifacts. A way of removing some is to remove all lesions
    # that are on the boundaries (given a certain thickness).

    # First, we'll create a boundary mask by eroding the brain mask and taking
    # only the region of the mask that is not part of the erosion.
    new_mask = np.copy(img_vol)
    im_lab = bwlabeln(img_vol)
    mask_bin = mask_vol.astype(np.bool)
    inner = imerode(mask_bin, iterations=boundary)
    boundary = np.logical_and(mask_bin, np.logical_not(inner))

    # Then it's just a matter of removing any lesion that overlaps with that
    # boundary mask.
    boundary_labs = np.unique(im_lab[boundary])
    boundary_labs = boundary_labs[boundary_labs > 0]
    if len(boundary_labs) > 0:
        new_mask[np.isin(im_lab, boundary_labs)] = 0

    return new_mask
def analysis_by_sizes(target, estimated, sizes):
    a = as_logical(target)
    b = as_logical(estimated)
    a_sub = masks_by_size(a, sizes)
    fp_sub = masks_by_size(np.logical_and(np.logical_not(a), b), sizes)
    tpd_list = [true_positive_det(a_i, b) for a_i in a_sub]
    tps_list = [true_positive_seg(a_i, b) for a_i in a_sub]
    fpd_list = [len(filter(bool, np.unique(bwlabeln(fp_i)))) for fp_i in fp_sub]
    fps_list = [np.count_nonzero(fp_i) for fp_i in fp_sub]
    gtd_list = [len(filter(bool, np.unique(bwlabeln(a_i)))) for a_i in a_sub]
    gts_list = [np.count_nonzero(a_i) for a_i in a_sub]
    tpf_list = [100.0 * tp_i/gt_i if gt_i > 0 else np.nan
                for tp_i, gt_i in zip(tpd_list, gtd_list)]
    fpf_list = [100.0 * fp_i / (fp_i+tp_i) if fp_i+tp_i > 0 else 0
                for tp_i, fp_i in zip(tpd_list, fpd_list)]
    dscd_list = [2.0 * tp_i / (tp_i + fp_i + gt_i) if gt_i > 0 else np.nan
                 for tp_i, fp_i, gt_i in zip(tpd_list, fpd_list, gtd_list)]
    dscs_list = [2.0 * tp_i / (tp_i + fp_i + gt_i) if gt_i > 0 else np.nan
                 for tp_i, fp_i, gt_i in zip(tps_list, fps_list, gts_list)]
    return tpf_list, fpf_list, dscd_list, dscs_list
def num_regions(mask):
    return np.max(bwlabeln(as_logical(mask)))
def dsc_det(target, estimated):
    t_det = np.max(bwlabeln(as_logical(target)))
    e_det = np.max(bwlabeln(as_logical(estimated)))
    all_det = t_det + e_det
    tp_det = true_positive_det(target, estimated)
    return 2.0 * tp_det / all_det if all_det > 0 else 0.0
def fp_fraction_det(target, estimated):
    det = np.max(bwlabeln(as_logical(estimated)))
    fp_det = false_positive_det(target, estimated)
    return 100.0 * fp_det / det if det > 0 else np.nan
def tp_fraction_det(target, estimated):
    tp_det = true_positive_det(target, estimated)
    det = np.max(bwlabeln(as_logical(target)))
    return 100.0 * tp_det / det if det > 0 else 0
def regionprops(mask):
    blobs = bwlabeln(as_logical(mask))
    labels = filter(bool, np.unique(blobs))
    areas = [np.count_nonzero(blobs == l) for l in labels]
    return blobs, labels, areas
def regionprops(mask):
    blobs = bwlabeln(as_logical(mask))
    labels = filter(bool, np.unique(blobs))
    areas = [np.count_nonzero(blobs == l) for l in labels]
    return blobs, labels, areas
def true_positive_det(target, estimated):
    a = bwlabeln(as_logical(target))
    b = as_logical(estimated)
    return np.min([np.sum([np.logical_and(b, a == (i+1)).any() for i in range(np.max(a))]), np.max(bwlabeln(b))])
def num_regions(mask):
    return np.max(bwlabeln(as_logical(mask)))
def dsc_det(target, estimated):
    a_plus_b = (np.max(bwlabeln(as_logical(target))) + np.max(bwlabeln(as_logical(estimated))))
    return 2.0 * true_positive_det(target, estimated) / a_plus_b if a_plus_b > 0 else 0.0
def fp_fraction_det(target, estimated):
    b = np.max(bwlabeln(as_logical(estimated)))
    return 100.0 * false_positive_det(target, estimated) / b if b > 0 else np.nan
def tp_fraction_det(target, estimated):
    return 100.0 * true_positive_det(target, estimated) / np.max(bwlabeln(as_logical(target)))
def true_positive_det(target, estimated):
    t_mask = as_logical(target)
    e_det = bwlabeln(as_logical(estimated))
    tp_det = np.count_nonzero(np.unique(e_det[t_mask]) > 0)
    return tp_det
def false_positive_det(target, estimated):
    e_det = bwlabeln(as_logical(estimated))
    tp_det = true_positive_det(target, estimated)
    return len(e_det) - tp_det
def false_positive_det(target, estimated):
    a = as_logical(target)
    b = bwlabeln(as_logical(estimated))
    tp_labels = np.unique(a * b)
    fp_labels = np.unique(np.logical_not(a) * b)
    return len([label for label in fp_labels if label not in tp_labels])