bbox_util.py 4.8 KB
Newer Older
Q
qingqing01 已提交
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24
# Copyright (c) 2020 PaddlePaddle Authors. All Rights Reserved.
#
# Licensed under the Apache License, Version 2.0 (the "License");
# you may not use this file except in compliance with the License.
# You may obtain a copy of the License at
#
#     http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS,
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
# See the License for the specific language governing permissions and
# limitations under the License.

from __future__ import absolute_import
from __future__ import division
from __future__ import print_function

import paddle
import paddle.nn.functional as F
import math


def xywh2xyxy(box):
W
wangxinxin08 已提交
25 26 27 28 29 30
    x, y, w, h = box
    x1 = x - w * 0.5
    y1 = y - h * 0.5
    x2 = x + w * 0.5
    y2 = y + h * 0.5
    return [x1, y1, x2, y2]
Q
qingqing01 已提交
31 32 33 34 35 36 37 38 39 40 41


def make_grid(h, w, dtype):
    yv, xv = paddle.meshgrid([paddle.arange(h), paddle.arange(w)])
    return paddle.stack((xv, yv), 2).cast(dtype=dtype)


def decode_yolo(box, anchor, downsample_ratio):
    """decode yolo box

    Args:
W
wangxinxin08 已提交
42
        box (list): [x, y, w, h], all have the shape [b, na, h, w, 1]
Q
qingqing01 已提交
43 44 45
        anchor (list): anchor with the shape [na, 2]
        downsample_ratio (int): downsample ratio, default 32
        scale (float): scale, default 1.
W
wangxinxin08 已提交
46

Q
qingqing01 已提交
47
    Return:
W
wangxinxin08 已提交
48
        box (list): decoded box, [x, y, w, h], all have the shape [b, na, h, w, 1]
Q
qingqing01 已提交
49
    """
W
wangxinxin08 已提交
50 51 52 53 54
    x, y, w, h = box
    na, grid_h, grid_w = x.shape[1:4]
    grid = make_grid(grid_h, grid_w, x.dtype).reshape((1, 1, grid_h, grid_w, 2))
    x1 = (x + grid[:, :, :, :, 0:1]) / grid_w
    y1 = (y + grid[:, :, :, :, 1:2]) / grid_h
Q
qingqing01 已提交
55 56

    anchor = paddle.to_tensor(anchor)
W
wangxinxin08 已提交
57 58 59 60 61 62
    anchor = paddle.cast(anchor, x.dtype)
    anchor = anchor.reshape((1, na, 1, 1, 2))
    w1 = paddle.exp(w) * anchor[:, :, :, :, 0:1] / (downsample_ratio * grid_w)
    h1 = paddle.exp(h) * anchor[:, :, :, :, 1:2] / (downsample_ratio * grid_h)

    return [x1, y1, w1, h1]
Q
qingqing01 已提交
63 64 65 66 67 68 69 70


def iou_similarity(box1, box2, eps=1e-9):
    """Calculate iou of box1 and box2

    Args:
        box1 (Tensor): box with the shape [N, M1, 4]
        box2 (Tensor): box with the shape [N, M2, 4]
W
wangxinxin08 已提交
71

Q
qingqing01 已提交
72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91
    Return:
        iou (Tensor): iou between box1 and box2 with the shape [N, M1, M2]
    """
    box1 = box1.unsqueeze(2)  # [N, M1, 4] -> [N, M1, 1, 4]
    box2 = box2.unsqueeze(1)  # [N, M2, 4] -> [N, 1, M2, 4]
    px1y1, px2y2 = box1[:, :, :, 0:2], box1[:, :, :, 2:4]
    gx1y1, gx2y2 = box2[:, :, :, 0:2], box2[:, :, :, 2:4]
    x1y1 = paddle.maximum(px1y1, gx1y1)
    x2y2 = paddle.minimum(px2y2, gx2y2)
    overlap = (x2y2 - x1y1).clip(0).prod(-1)
    area1 = (px2y2 - px1y1).clip(0).prod(-1)
    area2 = (gx2y2 - gx1y1).clip(0).prod(-1)
    union = area1 + area2 - overlap + eps
    return overlap / union


def bbox_iou(box1, box2, giou=False, diou=False, ciou=False, eps=1e-9):
    """calculate the iou of box1 and box2

    Args:
W
wangxinxin08 已提交
92 93
        box1 (list): [x, y, w, h], all have the shape [b, na, h, w, 1]
        box2 (list): [x, y, w, h], all have the shape [b, na, h, w, 1]
Q
qingqing01 已提交
94 95 96 97 98 99
        giou (bool): whether use giou or not, default False
        diou (bool): whether use diou or not, default False
        ciou (bool): whether use ciou or not, default False
        eps (float): epsilon to avoid divide by zero

    Return:
W
wangxinxin08 已提交
100
        iou (Tensor): iou of box1 and box1, with the shape [b, na, h, w, 1]
Q
qingqing01 已提交
101
    """
W
wangxinxin08 已提交
102 103 104 105 106 107 108 109 110 111 112 113 114 115 116
    px1, py1, px2, py2 = box1
    gx1, gy1, gx2, gy2 = box2
    x1 = paddle.maximum(px1, gx1)
    y1 = paddle.maximum(py1, gy1)
    x2 = paddle.minimum(px2, gx2)
    y2 = paddle.minimum(py2, gy2)

    overlap = (x2 - x1) * (y2 - y1)
    overlap = overlap.clip(0)

    area1 = (px2 - px1) * (py2 - py1)
    area1 = area1.clip(0)

    area2 = (gx2 - gx1) * (gy2 - gy1)
    area2 = area2.clip(0)
Q
qingqing01 已提交
117 118 119

    union = area1 + area2 - overlap + eps
    iou = overlap / union
W
wangxinxin08 已提交
120

Q
qingqing01 已提交
121 122
    if giou or ciou or diou:
        # convex w, h
W
wangxinxin08 已提交
123 124 125 126 127 128
        cw = paddle.maximum(px2, gx2) - paddle.minimum(px1, gx1)
        ch = paddle.maximum(py2, gy2) - paddle.minimum(py1, gy1)
        if giou:
            c_area = cw * ch + eps
            return iou - (c_area - union) / c_area
        else:
Q
qingqing01 已提交
129
            # convex diagonal squared
W
wangxinxin08 已提交
130
            c2 = cw**2 + ch**2 + eps
Q
qingqing01 已提交
131
            # center distance
W
wangxinxin08 已提交
132
            rho2 = ((px1 + px2 - gx1 - gx2)**2 + (py1 + py2 - gy1 - gy2)**2) / 4
Q
qingqing01 已提交
133 134
            if diou:
                return iou - rho2 / c2
W
wangxinxin08 已提交
135 136 137 138 139
            else:
                w1, h1 = px2 - px1, py2 - py1 + eps
                w2, h2 = gx2 - gx1, gy2 - gy1 + eps
                delta = paddle.atan(w1 / h1) - paddle.atan(w2 / h2)
                v = (4 / math.pi**2) * paddle.pow(delta, 2)
Q
qingqing01 已提交
140 141 142 143 144
                alpha = v / (1 + eps - iou + v)
                alpha.stop_gradient = True
                return iou - (rho2 / c2 + v * alpha)
    else:
        return iou