File size: 7,421 Bytes
67a9b5d
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
import numpy as np


def paired_intersection(boxes1, boxes2):
    """Compute paired intersection areas between boxes.
    Args:
        boxes1: a numpy array with shape [N, 4] holding N boxes
        boxes2: a numpy array with shape [N, 4] holding N boxes
        
    Returns:
        a numpy array with shape [N,] representing itemwise intersection area
        
    References:
        `core.box_list_ops.matched_intersection` in Tensorflow object detection API
        
    Notes:
        can called as itemwise_intersection, matched_intersection, aligned_intersection
    """
    max_x_mins = np.maximum(boxes1[:, 0], boxes2[:, 0])
    max_y_mins = np.maximum(boxes1[:, 1], boxes2[:, 1])
    min_x_maxs = np.minimum(boxes1[:, 2], boxes2[:, 2])
    min_y_maxs = np.minimum(boxes1[:, 3], boxes2[:, 3])
    intersect_widths = np.maximum(0, min_x_maxs - max_x_mins)
    intersect_heights = np.maximum(0, min_y_maxs - max_y_mins)
    return intersect_widths * intersect_heights
    
    
def pairwise_intersection(boxes1, boxes2):
    """Compute pairwise intersection areas between boxes.
    
    Args:
        boxes1: a numpy array with shape [N, 4] holding N boxes.
        boxes2: a numpy array with shape [M, 4] holding M boxes.
        
    Returns:
        a numpy array with shape [N, M] representing pairwise intersection area.
        
    References:
        `core.box_list_ops.intersection` in Tensorflow object detection API
        `utils.box_list_ops.intersection` in Tensorflow object detection API
    """
    if boxes1.shape[0] * boxes2.shape[0] == 0:
        return np.zeros((boxes1.shape[0], boxes2.shape[0]), dtype=boxes1.dtype)

    swap = False
    if boxes1.shape[0] > boxes2.shape[0]:
        boxes1, boxes2 = boxes2, boxes1
        swap = True
    intersect_areas = np.empty((boxes1.shape[0], boxes2.shape[0]), dtype=boxes1.dtype)

    for i in range(boxes1.shape[0]):
        max_x_mins = np.maximum(boxes1[i, 0], boxes2[:, 0])
        max_y_mins = np.maximum(boxes1[i, 1], boxes2[:, 1])
        min_x_maxs = np.minimum(boxes1[i, 2], boxes2[:, 2])
        min_y_maxs = np.minimum(boxes1[i, 3], boxes2[:, 3])
        intersect_widths = np.maximum(0, min_x_maxs - max_x_mins)
        intersect_heights = np.maximum(0, min_y_maxs - max_y_mins)
        intersect_areas[i, :] = intersect_widths * intersect_heights
    if swap:
        intersect_areas = intersect_areas.T
    return intersect_areas
    
    
def paired_overlap_ratio(boxes1, boxes2, ratio_type='iou'):
    """Compute paired overlap ratio between boxes.
    
    Args:
        boxes1: a numpy array with shape [N, 4] holding N boxes
        boxes2: a numpy array with shape [N, 4] holding N boxes
        ratio_type:
            iou: Intersection-over-union (iou).
            ioa: Intersection-over-area (ioa) between two boxes box1 and box2 is defined as
                their intersection area over box2's area. Note that ioa is not symmetric,
                that is, IOA(box1, box2) != IOA(box2, box1).
            min: Compute the ratio as the area of intersection between box1 and box2, 
                divided by the minimum area of the two bounding boxes.
                
    Returns:
        a numpy array with shape [N,] representing itemwise overlap ratio.
        
    References:
        `core.box_list_ops.matched_iou` in Tensorflow object detection API
        `structures.boxes.matched_boxlist_iou` in detectron2
        `mmdet.core.bbox.bbox_overlaps`, see https://mmdetection.readthedocs.io/en/v2.17.0/api.html#mmdet.core.bbox.bbox_overlaps
    """
    intersect_areas = paired_intersection(boxes1, boxes2)
    areas1 = (boxes1[:, 2] - boxes1[:, 0]) * (boxes1[:, 3] - boxes1[:, 1])
    areas2 = (boxes2[:, 2] - boxes2[:, 0]) * (boxes2[:, 3] - boxes2[:, 1])
    
    if ratio_type in ['union', 'iou', 'giou']:
        union_areas = areas1 - intersect_areas
        union_areas += areas2
        intersect_areas /= union_areas
    elif ratio_type == 'min':
        min_areas = np.minimum(areas1, areas2)
        intersect_areas /= min_areas
    elif ratio_type == 'ioa':
        intersect_areas /= areas2
    else:
        raise ValueError('Unsupported ratio_type. Got {}'.format(ratio_type))
        
    if ratio_type == 'giou':
        min_xy_mins = np.minimum(boxes1[:, 0:2], boxes2[:, 0:2])
        max_xy_mins = np.maximum(boxes1[:, 2:4], boxes2[:, 2:4])
        # mebb = minimum enclosing bounding boxes
        mebb_whs = np.maximum(0, max_xy_mins - min_xy_mins)
        mebb_areas = mebb_whs[:, 0] * mebb_whs[:, 1]
        union_areas -= mebb_areas
        union_areas /= mebb_areas
        intersect_areas += union_areas
    return intersect_areas


def pairwise_overlap_ratio(boxes1, boxes2, ratio_type='iou'):
    """Compute pairwise overlap ratio between boxes.
    
    Args:
        boxes1: a numpy array with shape [N, 4] holding N boxes
        boxes2: a numpy array with shape [M, 4] holding M boxes
        ratio_type:
            iou: Intersection-over-union (iou).
            ioa: Intersection-over-area (ioa) between two boxes box1 and box2 is defined as
                their intersection area over box2's area. Note that ioa is not symmetric,
                that is, IOA(box1, box2) != IOA(box2, box1).
            min: Compute the ratio as the area of intersection between box1 and box2, 
                divided by the minimum area of the two bounding boxes.
                
    Returns:
        a numpy array with shape [N, M] representing pairwise overlap ratio.
        
    References:
        `utils.np_box_ops.iou` in Tensorflow object detection API
        `utils.np_box_ops.ioa` in Tensorflow object detection API
        `utils.np_box_ops.giou` in Tensorflow object detection API
        `mmdet.core.bbox.bbox_overlaps`, see https://mmdetection.readthedocs.io/en/v2.17.0/api.html#mmdet.core.bbox.bbox_overlaps
        `torchvision.ops.box_iou`, see https://pytorch.org/vision/stable/ops.html#torchvision.ops.box_iou
        `torchvision.ops.generalized_box_iou`, see https://pytorch.org/vision/stable/ops.html#torchvision.ops.generalized_box_iou
        http://ww2.mathworks.cn/help/vision/ref/bboxoverlapratio.html
    """
    intersect_areas = pairwise_intersection(boxes1, boxes2)
    areas1 = (boxes1[:, 2] - boxes1[:, 0]) * (boxes1[:, 3] - boxes1[:, 1])
    areas2 = (boxes2[:, 2] - boxes2[:, 0]) * (boxes2[:, 3] - boxes2[:, 1])
    
    if ratio_type in ['union', 'iou', 'giou']:
        union_areas = np.expand_dims(areas1, axis=1) - intersect_areas
        union_areas += np.expand_dims(areas2, axis=0)
        intersect_areas /= union_areas
    elif ratio_type == 'min':
        min_areas = np.minimum(np.expand_dims(areas1, axis=1), np.expand_dims(areas2, axis=0))
        intersect_areas /= min_areas
    elif ratio_type == 'ioa':
        intersect_areas /= np.expand_dims(areas2, axis=0)
    else:
        raise ValueError('Unsupported ratio_type. Got {}'.format(ratio_type))
        
    if ratio_type == 'giou':
        min_xy_mins = np.minimum(boxes1[:, None, 0:2], boxes2[:, 0:2])
        max_xy_mins = np.maximum(boxes1[:, None, 2:4], boxes2[:, 2:4])
        # mebb = minimum enclosing bounding boxes
        mebb_whs = np.maximum(0, max_xy_mins - min_xy_mins)
        mebb_areas = mebb_whs[:, :, 0] * mebb_whs[:, :, 1]
        union_areas -= mebb_areas
        union_areas /= mebb_areas
        intersect_areas += union_areas
    return intersect_areas