<reponame>L-Net-1992/Paddle<filename>python/paddle/fluid/tests/unittests/test_nms_op.py<gh_stars>10-100
# Copyright (c) 2022 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.

import unittest
import numpy as np
from op_test import OpTest


def iou(box_a, box_b):
    """Apply intersection-over-union overlap between box_a and box_b
    """
    xmin_a = min(box_a[0], box_a[2])
    ymin_a = min(box_a[1], box_a[3])
    xmax_a = max(box_a[0], box_a[2])
    ymax_a = max(box_a[1], box_a[3])

    xmin_b = min(box_b[0], box_b[2])
    ymin_b = min(box_b[1], box_b[3])
    xmax_b = max(box_b[0], box_b[2])
    ymax_b = max(box_b[1], box_b[3])

    area_a = (ymax_a - ymin_a) * (xmax_a - xmin_a)
    area_b = (ymax_b - ymin_b) * (xmax_b - xmin_b)
    if area_a <= 0 and area_b <= 0:
        return 0.0

    xa = max(xmin_a, xmin_b)
    ya = max(ymin_a, ymin_b)
    xb = min(xmax_a, xmax_b)
    yb = min(ymax_a, ymax_b)

    inter_area = max(xb - xa, 0.0) * max(yb - ya, 0.0)

    iou_ratio = inter_area / (area_a + area_b - inter_area)
    return iou_ratio


def nms(boxes, nms_threshold):
    selected_indices = np.zeros(boxes.shape[0], dtype=np.int64)
    keep = np.ones(boxes.shape[0], dtype=int)
    io_ratio = np.ones((boxes.shape[0], boxes.shape[0]), dtype=np.float64)
    cnt = 0
    for i in range(boxes.shape[0]):
        if keep[i] == 0:
            continue
        selected_indices[cnt] = i
        cnt += 1
        for j in range(i + 1, boxes.shape[0]):
            io_ratio[i][j] = iou(boxes[i], boxes[j])
            if keep[j]:
                overlap = iou(boxes[i], boxes[j])
                keep[j] = 1 if overlap <= nms_threshold else 0
            else:
                continue

    return selected_indices


class TestNMSOp(OpTest):

    def setUp(self):
        self.op_type = 'nms'
        self.dtype = np.float64
        self.init_dtype_type()
        boxes = np.random.rand(32, 4).astype(self.dtype)
        boxes[:, 2] = boxes[:, 0] + boxes[:, 2]
        boxes[:, 3] = boxes[:, 1] + boxes[:, 3]

        self.inputs = {'Boxes': boxes}
        self.attrs = {'iou_threshold': 0.5}
        out_py = nms(boxes, self.attrs['iou_threshold'])
        self.outputs = {'KeepBoxesIdxs': out_py}

    def init_dtype_type(self):
        pass

    def test_check_output(self):
        self.check_output()


if __name__ == "__main__":
    unittest.main()
