# This code is a copy and paste with small modifications of the code: # https://github.com/rafaelpadilla/review_object_detection_metrics/blob/main/src/evaluators/coco_evaluator.py from typing import List import numpy as np class MaskEvaluator(object): @staticmethod def iou( dt: List[List[float]], gt: List[List[float]], iscrowd: List[bool] ) -> np.ndarray: """ Calculate the intersection over union (IoU) between detection bounding boxes (dt) and \ ground truth bounding boxes (gt). Reference: https://github.com/rafaelpadilla/review_object_detection_metrics Args: dt (List[List[float]]): List of detection bounding boxes in the \ format [x, y, width, height]. gt (List[List[float]]): List of ground-truth bounding boxes in the \ format [x, y, width, height]. iscrowd (List[bool]): List indicating if each ground-truth bounding box \ is a crowd region or not. Returns: np.ndarray: Array of IoU values of shape (len(dt), len(gt)). """ assert len(iscrowd) == len(gt), "iou(iscrowd=) must have the same length as gt" if len(dt) == 0 or len(gt) == 0: return [] ious = np.zeros((len(dt), len(gt)), dtype=np.float64) for g_idx, g in enumerate(gt): for d_idx, d in enumerate(dt): ious[d_idx, g_idx] = _jaccard(d, g, iscrowd[g_idx]) return ious def _jaccard(a: List[float], b: List[float], iscrowd: bool) -> float: """ Calculate the Jaccard index (intersection over union) between two bounding boxes. For "crowd" regions, we use a modified criteria. If a gt object is marked as "iscrowd", we allow a dt to match any subregion of the gt. Choosing gt' in the crowd gt that best matches the dt can be done using gt'=intersect(dt,gt). Since by definition union(gt',dt)=dt, computing iou(gt,dt,iscrowd) = iou(gt',dt) = area(intersect(gt,dt)) / area(dt) For crowd gt regions we use this modified criteria above for the iou. Args: a (List[float]): Bounding box coordinates in the format [x, y, width, height]. b (List[float]): Bounding box coordinates in the format [x, y, width, height]. iscrowd (bool): Flag indicating if the second bounding box is a crowd region or not. Returns: float: Jaccard index between the two bounding boxes. """ eps = 4e-12 xa, ya, x2a, y2a = a[0], a[1], a[0] + a[2], a[1] + a[3] xb, yb, x2b, y2b = b[0], b[1], b[0] + b[2], b[1] + b[3] # innermost left x xi = max(xa, xb) # innermost right x x2i = min(x2a, x2b) # same for y yi = max(ya, yb) y2i = min(y2a, y2b) # calculate areas Aa = max(x2a - xa, 0.) * max(y2a - ya, 0.) Ab = max(x2b - xb, 0.) * max(y2b - yb, 0.) Ai = max(x2i - xi, 0.) * max(y2i - yi, 0.) if iscrowd: return Ai / (Aa + eps) return Ai / (Aa + Ab - Ai + eps)