Source code for pyEdgeEval.common.binary_label.evaluate_boundaries

#!/usr/bin/env python3

import numpy as np

from pyEdgeEval._lib import correspond_pixels
from pyEdgeEval.preprocess import binary_thin, fast_nms


[docs]def evaluate_boundaries_threshold( thresholds: np.ndarray, pred: np.ndarray, gt: np.ndarray, max_dist: float = 0.0075, apply_thinning: bool = True, apply_nms: bool = False, nms_kwargs=dict( r=1, s=5, m=1.01, half_prec=False, ), ): """ Evaluate the accuracy of a predicted boundary and a range of thresholds - Single GT Args: thresholds: a 1D array specifying the thresholds pred: the predicted boundaries as a (H,W) floating point array where each pixel represents the strength of the predicted boundary gts: list of ground truth boundary, as returned by the `load_boundary` or `boundary` methods max_dist: (default=0.02) maximum distance parameter used for determining pixel matches. This value is multiplied by the length of the diagonal of the image to get the threshold used for matching pixels. apply_thinning: (default=True) if True, apply morphologial thinning to the predicted boundaries before evaluation apply_nms: (default=False) apply a fast nms preprocess nms_kwargs: arguments for nms process Returns: tuple `(count_r, sum_r, count_p, sum_p, thresholds)` where each of the first four entries are arrays that can be used to compute recall and precision at each threshold with: ``` recall = count_r / (sum_r + (sum_r == 0)) precision = count_p / (sum_p + (sum_p == 0)) ``` """ sum_p = np.zeros(thresholds.shape) count_p = np.zeros(thresholds.shape) sum_r = np.zeros(thresholds.shape) count_r = np.zeros(thresholds.shape) if apply_nms: pred = fast_nms( img=pred, **nms_kwargs, ) for i_t, thresh in enumerate(list(thresholds)): _pred = pred >= thresh if apply_thinning: _pred = binary_thin(_pred) if gt.any(): match1, match2, cost, oc = correspond_pixels( _pred, gt, max_dist=max_dist ) match1 = match1 > 0 match2 = match2 > 0 # Recall sum_r[i_t] = gt.sum() count_r[i_t] = match2.sum() # Precision sum_p[i_t] = _pred.sum() count_p[i_t] = match1.sum() else: sum_r[i_t] = 0 count_r[i_t] = 0 sum_p[i_t] = _pred.sum() # keep track of false positives count_p[i_t] = 0 return count_r, sum_r, count_p, sum_p
[docs]def evaluate_boundaries_threshold_multiple_gts( thresholds: np.ndarray, pred: np.ndarray, gts: np.ndarray, max_dist: float = 0.0075, apply_thinning: bool = True, apply_nms: bool = False, nms_kwargs=dict( r=1, s=5, m=1.01, half_prec=False, ), ): """ Evaluate the accuracy of a predicted boundary and a range of thresholds - Assumes that there are multiple GTs Args: thresholds: a 1D array specifying the thresholds pred: the predicted boundaries as a (H,W) floating point array where each pixel represents the strength of the predicted boundary gts: list of ground truth boundary, as returned by the `load_boundary` or `boundary` methods max_dist: (default=0.02) maximum distance parameter used for determining pixel matches. This value is multiplied by the length of the diagonal of the image to get the threshold used for matching pixels. apply_thinning: (default=True) if True, apply morphologial thinning to the predicted boundaries before evaluation apply_nms: (default=False) apply a fast nms preprocess nms_kwargs: arguments for nms process Returns: tuple `(count_r, sum_r, count_p, sum_p, thresholds)` where each of the first four entries are arrays that can be used to compute recall and precision at each threshold with: ``` recall = count_r / (sum_r + (sum_r == 0)) precision = count_p / (sum_p + (sum_p == 0)) ``` """ sum_p = np.zeros(thresholds.shape) count_p = np.zeros(thresholds.shape) sum_r = np.zeros(thresholds.shape) count_r = np.zeros(thresholds.shape) if apply_nms: pred = fast_nms( img=pred, **nms_kwargs, ) for i_t, thresh in enumerate(list(thresholds)): _pred = pred >= thresh acc_prec = np.zeros(_pred.shape, dtype=bool) if apply_thinning: _pred = binary_thin(_pred) for gt in gts: match1, match2, cost, oc = correspond_pixels( _pred, gt, max_dist=max_dist ) match1 = match1 > 0 match2 = match2 > 0 # Precision accumulator acc_prec = acc_prec | match1 # Recall sum_r[i_t] += gt.sum() count_r[i_t] += match2.sum() # Precision sum_p[i_t] = _pred.sum() count_p[i_t] = acc_prec.sum() return count_r, sum_r, count_p, sum_p