"""
Utility code.
NMS adapted from Tomasz Malisiewicz's & Ross Girshick's code.
- [https://gist.github.com/quantombone/1144423]
- [https://github.com/rbgirshick/py-faster-rcnn/blob/master/lib/nms/py_cpu_nms.py]
"""
# pylint: disable=invalid-name,missing-docstring,assignment-from-no-return,logging-format-interpolation
import numpy as np
from bbox import BBox2DList
from bbox.box_modes import XYXY
[docs]def nms(bbl, scores, thresh):
    """
    Perform fast non-maximum suppression on a set of bounding boxes \
        given their associated confidences.
    Args:
        bbl (:py:class:`BBox2DList`): List of 2D bounding boxes.
        scores (:py:class:`list` or :py:class:`ndarray`): Scores for each bounding box.
    Raises:
        ValueError: If arguments are of incorrect type or size.
    """
    if bbl.shape[0] == 0:
        return np.array([]).astype(np.int)
    if not isinstance(scores, (list, np.ndarray)):
        raise ValueError("`scores` should be a list of numpy array")
    # convert to numpy array if it is a list
    scores = np.asarray(scores)
    if not scores.shape[0] == bbl.shape[0]:
        raise ValueError("box list and scores should have the same number of elements.")
    areas = bbl.w * bbl.h
    order = scores.argsort()[::-1]
    keep = []
    while order.size > 0:
        i = order[0]
        keep.append(int(i))
        xx1 = np.maximum(bbl.x1[i], bbl.x1[order[1:]])
        yy1 = np.maximum(bbl.y1[i], bbl.y1[order[1:]])
        xx2 = np.minimum(bbl.x2[i], bbl.x2[order[1:]])
        yy2 = np.minimum(bbl.y2[i], bbl.y2[order[1:]])
        w = np.maximum(0.0, xx2 - xx1 + 1)
        h = np.maximum(0.0, yy2 - yy1 + 1)
        inter = w * h
        overlap = inter / (areas[i] + areas[order[1:]] - inter)
        idx = np.where(overlap <= thresh)[0]
        order = order[idx + 1]
    return np.array(keep).astype(np.int) 
[docs]def aspect_ratio(bbox, ratios):
    """
    Enumerate box for each aspect ratio.
    Args:
        bbox (:py:class:`BBox2D`): 2D bounding box.
        ratios (:py:class:`list`): list of int/float values.
    """
    cx, cy = bbox.center()
    w, h = bbox.w, bbox.h
    size = w * h
    ratios = np.asarray(ratios, dtype=np.float)
    size_ratios = size / ratios
    ws = np.round(np.sqrt(size_ratios))
    hs = np.round(ws * ratios)
    stack = np.vstack((cx - 0.5*(ws-1), cy - 0.5*(hs-1),
                       cx + 0.5*(ws-1), cy + 0.5*(hs-1)))
    boxes = BBox2DList(stack.T, mode=XYXY)
    return boxes