File size: 3,013 Bytes
f9cf0c4
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# 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)