def nms(boxes, scores, **kwargs):
    """Do Non Maximal Suppression

    As translated from the OpenCV c++ source in
    `nms.inl.hpp <https://github.com/opencv/opencv/blob/ee1e1ce377aa61ddea47a6c2114f99951153bb4f/modules/dnn/src/nms.inl.hpp#L67>`__
    which was in turn inspired by `Piotr Dollar's NMS implementation in EdgeBox. <https://goo.gl/jV3JYS>`_

    This function is not usually called directly.  Instead use :func:`nms.nms.boxes`, :func:`nms.nms.rboxes`,
    or :func:`nms.nms.polygons`

    :param boxes:  the boxes to compare, the structure of the boxes must be compatible with the compare_function.
    :type boxes:  list
    :param scores: the scores associated with boxes
    :type scores: list
    :param kwargs: optional keyword parameters
    :type kwargs: dict (see below)
    :returns: an list of indicies of the best boxes
    :rtype: list
    :kwargs:

    * score_threshold (float): the minimum score necessary to be a viable solution, default 0.3
    * nms_threshold (float): the minimum nms value to be a viable solution, default: 0.4
    * compare_function (function): function that accepts two boxes and returns their overlap ratio, this function must
      accept two boxes and return an overlap ratio
    * eta (float): a coefficient in adaptive threshold formula: \\ |nmsi1|\\ =eta\\*\\ |nmsi0|\\ , default: 1.0
    * top_k (int): if >0, keep at most top_k picked indices. default:0

    .. |nmsi0| replace:: nms_threshold\\ :sub:`i`
    .. |nmsi1| replace:: nms_threshold\\ :sub:`(i+1)`

    """
    if 'eta' in kwargs:
        eta = kwargs['eta']
    else:
        eta = 1.0
    assert 0 < eta <= 1.0
    if 'top_k' in kwargs:
        top_k = kwargs['top_k']
    else:
        top_k = 0
    assert 0 <= top_k
    if 'score_threshold' in kwargs:
        score_threshold = kwargs['score_threshold']
    else:
        score_threshold = 0.3
    assert score_threshold > 0
    if 'nms_threshold' in kwargs:
        nms_threshold = kwargs['nms_threshold']
    else:
        nms_threshold = 0.4
    assert 0 < nms_threshold < 1
    if 'compare_function' in kwargs:
        compare_function = kwargs['compare_function']
    else:
        compare_function = None
    assert compare_function is not None
    if len(boxes) == 0:
        return []
    assert len(scores) == len(boxes)
    assert scores is not None
    scores = help.get_max_score_index(scores, score_threshold, top_k)
    adaptive_threshold = nms_threshold
    indicies = []
    for i in range(0, len(scores)):
        idx = int(scores[i][1])
        keep = True
        for k in range(0, len(indicies)):
            if not keep:
                break
            kept_idx = indicies[k]
            overlap = compare_function(boxes[idx], boxes[kept_idx])
            keep = overlap <= adaptive_threshold
        if keep:
            indicies.append(idx)
        if keep and eta < 1 and adaptive_threshold > 0.5:
            adaptive_threshold = adaptive_threshold * eta
    return indicies
