|
| 1 | +import numpy as np |
| 2 | +import paddle |
| 3 | + |
| 4 | + |
| 5 | +def box_xyxy_to_cxcywh_numpy(box): |
| 6 | + """convert box from top-left/bottom-right format: |
| 7 | + [x0, y0, x1, y1] |
| 8 | + to center-size format: |
| 9 | + [center_x, center_y, width, height] |
| 10 | +
|
| 11 | + Args: |
| 12 | + box: numpy array, last_dim=4, stop-left/bottom-right format boxes |
| 13 | + Return: |
| 14 | + numpy array, last_dim=4, center-size format boxes |
| 15 | + """ |
| 16 | + |
| 17 | + #x0, y0, x1, y1 = box.unbind(-1) |
| 18 | + x0 = box[:, 0] |
| 19 | + y0 = box[:, 1] |
| 20 | + x1 = box[:, 2] |
| 21 | + y1 = box[:, 3] |
| 22 | + xc = x0 + (x1-x0)/2 |
| 23 | + yc = y0 + (y1-y0)/2 |
| 24 | + w = x1 - x0 |
| 25 | + h = y1 - y0 |
| 26 | + return np.stack([xc, yc, w, h], axis=-1) |
| 27 | + |
| 28 | + |
| 29 | + |
| 30 | +def box_cxcywh_to_xyxy(box): |
| 31 | + """convert box from center-size format: |
| 32 | + [center_x, center_y, width, height] |
| 33 | + to top-left/bottom-right format: |
| 34 | + [x0, y0, x1, y1] |
| 35 | +
|
| 36 | + Args: |
| 37 | + box: paddle.Tensor, last_dim=4, stores center-size format boxes |
| 38 | + Return: |
| 39 | + paddle.Tensor, last_dim=4, top-left/bottom-right format boxes |
| 40 | + """ |
| 41 | + |
| 42 | + x_c, y_c, w, h = box.unbind(-1) |
| 43 | + x0 = x_c - 0.5 * w |
| 44 | + y0 = y_c - 0.5 * h |
| 45 | + x1 = x_c + 0.5 * w |
| 46 | + y1 = y_c + 0.5 * h |
| 47 | + return paddle.stack([x0, y0, x1, y1], axis=-1) |
| 48 | + |
| 49 | + |
| 50 | +def box_xyxy_to_cxcywh(box): |
| 51 | + """convert box from top-left/bottom-right format: |
| 52 | + [x0, y0, x1, y1] |
| 53 | + to center-size format: |
| 54 | + [center_x, center_y, width, height] |
| 55 | +
|
| 56 | + Args: |
| 57 | + box: paddle.Tensor, last_dim=4, stop-left/bottom-right format boxes |
| 58 | + Return: |
| 59 | + paddle.Tensor, last_dim=4, center-size format boxes |
| 60 | + """ |
| 61 | + |
| 62 | + x0, y0, x1, y1 = box.unbind(-1) |
| 63 | + xc = x0 + (x1-x0)/2 |
| 64 | + yc = y0 + (y1-y0)/2 |
| 65 | + w = x1 - x0 |
| 66 | + h = y1 - y0 |
| 67 | + return paddle.stack([xc, yc, w, h], axis=-1) |
| 68 | + |
| 69 | + |
| 70 | +def box_area(boxes): |
| 71 | + """ compute area of a set of boxes in (x1, y1, x2, y2) format |
| 72 | + Args: |
| 73 | + boxes: paddle.Tensor, shape = Nx4, must in (x1, y1, x2, y2) format |
| 74 | + Return: |
| 75 | + areas: paddle.Tensor, N, areas of each box |
| 76 | + """ |
| 77 | + |
| 78 | + return (boxes[:, 2] - boxes[:, 0]) * (boxes[:, 3] - boxes[:, 1]) |
| 79 | + |
| 80 | + |
| 81 | +def box_iou(boxes1, boxes2): |
| 82 | + """compute iou of 2 sets of boxes in (x1, y1, x2, y2) format |
| 83 | +
|
| 84 | + This method returns the iou between every pair of boxes |
| 85 | + in two sets of boxes. |
| 86 | +
|
| 87 | + Args: |
| 88 | + boxes1: paddle.Tensor, shape=N x 4, boxes are stored in (x1, y1, x2, y2) format |
| 89 | + boxes2: paddle.Tensor, shape=N x 4, boxes are stored in (x1, y1, x2, y2) format |
| 90 | + Return: |
| 91 | + iou: iou ratios between each pair of boxes in boxes1 and boxes2 |
| 92 | + union: union areas between each pair of boxes in boxes1 and boxes2 |
| 93 | + """ |
| 94 | + |
| 95 | + area1 = box_area(boxes1) |
| 96 | + area2 = box_area(boxes2) |
| 97 | + |
| 98 | + boxes1 = boxes1.unsqueeze(1) # N x 1 x 4 |
| 99 | + lt = paddle.maximum(boxes1[:, :, :2], boxes2[:, :2]) |
| 100 | + rb = paddle.minimum(boxes1[:, :, 2:], boxes2[:, 2:]) |
| 101 | + |
| 102 | + wh = (rb - lt).clip(min=0) |
| 103 | + inter = wh[:, :, 0] * wh[:, :, 1] |
| 104 | + |
| 105 | + union = area1.unsqueeze(1) + area2 - inter # broadcast |
| 106 | + |
| 107 | + iou = inter / union |
| 108 | + return iou, union |
| 109 | + |
| 110 | + |
| 111 | +def generalized_box_iou(boxes1, boxes2): |
| 112 | + """Compute GIoU of each pais in boxes1 and boxes2 |
| 113 | +
|
| 114 | + GIoU = IoU - |A_c - U| / |A_c| |
| 115 | + where A_c is the smallest convex hull that encloses both boxes, U is the union of boxes |
| 116 | + Details illustrations can be found in https://giou.stanford.edu/ |
| 117 | +
|
| 118 | + Args: |
| 119 | + boxes1: paddle.Tensor, shape=N x 4, boxes are stored in (x1, y1, x2, y2) format |
| 120 | + boxes2: paddle.Tensor, shape=N x 4, boxes are stored in (x1, y1, x2, y2) format |
| 121 | + Return: |
| 122 | + giou: giou ratios between each pair of boxes in boxes1 and boxes2 |
| 123 | + """ |
| 124 | + |
| 125 | + iou, union = box_iou(boxes1, boxes2) |
| 126 | + |
| 127 | + boxes1 = boxes1.unsqueeze(1) # N x 1 x 4 |
| 128 | + lt = paddle.minimum(boxes1[:, :, :2], boxes2[:, :2]) |
| 129 | + rb = paddle.maximum(boxes1[:, :, 2:], boxes2[:, 2:]) |
| 130 | + |
| 131 | + wh = (rb - lt).clip(min=0) |
| 132 | + area = wh[:, :, 0] * wh[:, :, 1] |
| 133 | + |
| 134 | + return iou - (area-union) / area |
| 135 | + |
| 136 | + |
| 137 | +def masks_to_boxes(masks): |
| 138 | + """convert masks to bboxes |
| 139 | +
|
| 140 | + Args: |
| 141 | + masks: paddle.Tensor, NxHxW |
| 142 | + Return: |
| 143 | + boxes: paddle.Tensor, Nx4 |
| 144 | + """ |
| 145 | + |
| 146 | + if masks.numel() == 0: |
| 147 | + return paddle.zeros((0, 4)) |
| 148 | + h, w = masks.shape[-2:] |
| 149 | + y = paddle.arange(0, h, dtype='float32') |
| 150 | + x = paddle.arange(0, w, dtype='float32') |
| 151 | + y, x = paddle.meshgrid(y, x) |
| 152 | + |
| 153 | + x_mask = (masks * x.unsqueeze(0)) |
| 154 | + x_max = x_mask.flatten(1).max(-1)[0] |
| 155 | + |
| 156 | + #x_min = x_mask.masked_fill(~(masks.bool()), 1e8).flatten(1).min(-1) |
| 157 | + x_min = paddle.where(masks == 0, paddle.ones_like(x_mask)*float(1e8), x_mask) |
| 158 | + x_min = x_min.flatten(1).min(-1)[0] |
| 159 | + |
| 160 | + y_mask = (masks * y.unsqueeze(0)) |
| 161 | + y_max = y_mask.flatten(1).max(-1)[0] |
| 162 | + #y_min = y_mask.masked_fill(~(masks.bool()), 1e8).flatten(1).min(-1)[0] |
| 163 | + y_min = paddle.where(masks == 0, paddle.ones_like(y_mask) * float(1e8), y_mask) |
| 164 | + y_min = y_min.flatten(1).min(-1)[0] |
| 165 | + |
| 166 | + return paddle.stack([x_min, y_min, x_max, y_max], 1) |
| 167 | + |
| 168 | + |
0 commit comments