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 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 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])