File size: 5,588 Bytes
95db528
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
168
169
170
171
172
173
174
175
176
177
178
179
import numpy as np


def convert_locations_to_boxes(locations, priors, center_variance, size_variance):
    """
    Convert regression location results of SSD into boxes in the form of (center_x, center_y, h, w).
    Parameters
    ----------
    locations: numpy.ndarray
        Regression location results, sized [num_priors,4].
    priors: numpy.ndarray
        Prior boxes in center-offset form, sized [num_priors,4].
    center_variance: float
        The center variance for decoding.
    size_variance: float
        The size variance for decoding.

    Returns
    -------
    boxes: numpy.ndarray
        Boxes in corner form, sized [num_priors,4].
    """
    # priors can have one dimension less.
    if len(priors.shape) + 1 == len(locations.shape):
        priors = np.expand_dims(priors, 0)
    return np.concatenate(
        [
            locations[..., :2] * center_variance * priors[..., 2:] + priors[..., :2],
            np.exp(locations[..., 2:] * size_variance) * priors[..., 2:],
        ],
        axis=len(locations.shape) - 1,
    )


def convert_boxes_to_locations(center_form_boxes, center_form_priors, center_variance, size_variance):
    """
    Convert boxes to locations with respect to priors, which are encoded as (cx, cy, w, h).
    Parameters
    ----------
    center_form_boxes: numpy.ndarray
        Boxes to be converted to locations, sized [num_priors,4].
    center_form_priors: numpy.ndarray
        Prior boxes in center-form, sized [num_priors,4].
    center_variance: float
        The center variance for encoding.
    size_variance: float
        The size variance for encoding.

    Returns
    -------
    locations: numpy.ndarray
        Encoded locations, sized [num_priors,4].
    """
    if len(center_form_priors.shape) + 1 == len(center_form_boxes.shape):
        center_form_priors = np.expand_dims(center_form_priors, 0)
    return np.concatenate(
        [
            (center_form_boxes[..., :2] - center_form_priors[..., :2]) / center_form_priors[..., 2:] / center_variance,
            np.log(center_form_boxes[..., 2:] / center_form_priors[..., 2:]) / size_variance,
        ],
        axis=len(center_form_boxes.shape) - 1,
    )


def area_of(left_top, right_bottom):
    """
    Compute the areas of rectangles given two corners.
    Parameters
    ----------
    left_top: numpy.ndarray
        Left top corner of the rectangles, sized [N,2].
    right_bottom: numpy.ndarray
        Right bottom corner of the rectangles, sized [N,2].

    Returns
    -------
    area: numpy.ndarray
        Computed areas, sized [N,].
    """
    hw = np.clip(right_bottom - left_top, 0.0, None)
    return hw[..., 0] * hw[..., 1]


def iou_of(boxes0, boxes1, eps=1e-5):
    """Return intersection-over-union (Jaccard index) of boxes.
    Args:
        boxes0 (N, 4): ground truth boxes.
        boxes1 (N or 1, 4): predicted boxes.
        eps: a small number to avoid 0 as denominator.
    Returns:
        iou (N): IoU values.
    """
    overlap_left_top = np.maximum(boxes0[..., :2], boxes1[..., :2])
    overlap_right_bottom = np.minimum(boxes0[..., 2:], boxes1[..., 2:])

    overlap_area = area_of(overlap_left_top, overlap_right_bottom)
    area0 = area_of(boxes0[..., :2], boxes0[..., 2:])
    area1 = area_of(boxes1[..., :2], boxes1[..., 2:])
    return overlap_area / (area0 + area1 - overlap_area + eps)


def center_form_to_corner_form(locations):
    """
    Convert center-form boxes to corner-form.
    Parameters
    ----------
    locations: numpy.ndarray
        Center-form boxes to be converted to corner-form, sized [num_priors,4].

    Returns
    -------
    boxes: numpy.ndarray
        Corner-form boxes, sized [num_priors,4].
    """
    return np.concatenate(
        [locations[..., :2] - locations[..., 2:] / 2, locations[..., :2] + locations[..., 2:] / 2],
        len(locations.shape) - 1,
    )


def corner_form_to_center_form(boxes):
    """
    Convert corner-form boxes to center-form.
    Parameters
    ----------
    boxes: numpy.ndarray
        Corner-form boxes to be converted to center-form, sized [num_priors,4].

    Returns
    -------
    locations: numpy.ndarray
        Center-form boxes, sized [num_priors,4].
    """
    return np.concatenate(
        [(boxes[..., :2] + boxes[..., 2:]) / 2, boxes[..., 2:] - boxes[..., :2]], len(boxes.shape) - 1
    )


def hard_nms(box_scores, iou_threshold, top_k=-1, candidate_size=200):
    """
    Perform hard non-maximum-supression to filter out boxes with iou greater
    than threshold
    Parameters
    ----------
    box_scores: numpy.ndarray
        boxes in corner-form and probabilities.
    iou_threshold: float
        intersection over union threshold.
    top_k: int
        keep top_k results. If k <= 0, keep all the results.
    candidate_size: int
        only consider the candidates with the highest scores.

    Returns
    -------
    picked: numpy.ndarray
        a list of indexes of the kept boxes
    """
    scores = box_scores[:, -1]
    boxes = box_scores[:, :-1]
    picked = []
    indexes = np.argsort(scores)
    indexes = indexes[-candidate_size:]
    while len(indexes) > 0:
        current = indexes[-1]
        picked.append(current)
        if 0 < top_k == len(picked) or len(indexes) == 1:
            break
        current_box = boxes[current, :]
        indexes = indexes[:-1]
        rest_boxes = boxes[indexes, :]
        iou = iou_of(
            rest_boxes,
            np.expand_dims(current_box, axis=0),
        )
        indexes = indexes[iou <= iou_threshold]

    return box_scores[picked, :]