bounding_box_from_annotation(source, padding, **kwargs) -> bounding_box

  Creates a bounding box from the given parameters, which are, in general, annotations read using :py:func:`bob.ip.facedetect.read_annotation_file`.
  Different kinds of annotations are supported, given by the ``source`` keyword:

  * ``direct`` : bounding boxes are directly specified by keyword arguments ``topleft`` and ``bottomright``
  * ``eyes`` : the left and right eyes are specified by keyword arguments ``leye`` and ``reye``
  * ``left-profile`` : the left eye and the mouth are specified by keyword arguments ``eye`` and ``mouth``
  * ``right-profile`` : the right eye and the mouth are specified by keyword arguments ``eye`` and ``mouth``
  * ``ellipse`` : the face ellipse as well as face angle and axis radius is provided by keyword arguments ``center``, ``angle`` and ``axis_radius``

  If a ``source`` is specified, the according keywords must be given as well.
  Otherwise, the source is estimated from the given keyword parameters if possible.

  If 'topleft' and 'bottomright' are given (i.e., the 'direct' source), they are taken as is.
  Note that the 'bottomright' is NOT included in the bounding box.
  Please assure that the aspect ratio of the bounding box is 6:5 (height : width).

  For source 'ellipse', the bounding box is computed to capture the whole ellipse, even if it is rotated.

  For other sources (i.e., 'eyes'), the center of the two given positions is computed, and the ``padding`` is applied, which is relative to the distance between the two given points.
  If ``padding`` is ``None`` (the default) the default_paddings of this source are used instead.
  These padding is required to keep an aspect ratio of 6:5.

  **Parameters:**

  ``source`` : str or ``None``
    The type of annotations present in the list of keyword arguments, see above.

  ``padding`` : {'top':float, 'bottom':float, 'left':float, 'right':float}
    This padding is added to the center between the given points, to define the top left and bottom right positions in the bounding box; values are relative to the distance between the two given points; ignored for some of the ``source``\s

  ``kwargs`` : key=value
    Further keyword arguments specifying the annotations.

  **Returns:**

  bounding_box : :py:class:`BoundingBox`
    The bounding box that was estimated from the given annotations.

def bounding_box_from_annotation(source=None, padding=None, **kwargs):
  """bounding_box_from_annotation(source, padding, **kwargs) -> bounding_box

  Creates a bounding box from the given parameters, which are, in general, annotations read using :py:func:`bob.ip.facedetect.read_annotation_file`.
  Different kinds of annotations are supported, given by the ``source`` keyword:

  * ``direct`` : bounding boxes are directly specified by keyword arguments ``topleft`` and ``bottomright``
  * ``eyes`` : the left and right eyes are specified by keyword arguments ``leye`` and ``reye``
  * ``left-profile`` : the left eye and the mouth are specified by keyword arguments ``eye`` and ``mouth``
  * ``right-profile`` : the right eye and the mouth are specified by keyword arguments ``eye`` and ``mouth``
  * ``ellipse`` : the face ellipse as well as face angle and axis radius is provided by keyword arguments ``center``, ``angle`` and ``axis_radius``

  If a ``source`` is specified, the according keywords must be given as well.
  Otherwise, the source is estimated from the given keyword parameters if possible.

  If 'topleft' and 'bottomright' are given (i.e., the 'direct' source), they are taken as is.
  Note that the 'bottomright' is NOT included in the bounding box.
  Please assure that the aspect ratio of the bounding box is 6:5 (height : width).

  For source 'ellipse', the bounding box is computed to capture the whole ellipse, even if it is rotated.

  For other sources (i.e., 'eyes'), the center of the two given positions is computed, and the ``padding`` is applied, which is relative to the distance between the two given points.
  If ``padding`` is ``None`` (the default) the default_paddings of this source are used instead.
  These padding is required to keep an aspect ratio of 6:5.

  **Parameters:**

  ``source`` : str or ``None``
    The type of annotations present in the list of keyword arguments, see above.

  ``padding`` : {'top':float, 'bottom':float, 'left':float, 'right':float}
    This padding is added to the center between the given points, to define the top left and bottom right positions in the bounding box; values are relative to the distance between the two given points; ignored for some of the ``source``\s

  ``kwargs`` : key=value
    Further keyword arguments specifying the annotations.

  **Returns:**

  bounding_box : :py:class:`BoundingBox`
    The bounding box that was estimated from the given annotations.
  """

  if source is None:
    # try to estimate the source
    for s,k in available_sources.items():
      # check if the according keyword arguments are given
      if k[0] in kwargs and k[1] in kwargs:
        # check if we already assigned a source before
        if source is not None:
          raise ValueError("The given list of keywords (%s) is ambiguous. Please specify a source" % kwargs)
        # assign source
        source = s

    # check if a source could be estimated from the keywords
    if source is None:
      raise ValueError("The given list of keywords (%s) could not be interpreted" % kwargs)

  assert source in available_sources

  # use default padding if not specified
  if padding is None:
    padding = default_paddings[source]

  keys = available_sources[source]
  if source == 'ellipse':
    # compute the tight bounding box for the ellipse
    angle = kwargs['angle']
    axis = kwargs['axis_radius']
    center = kwargs['center']
    dx = abs(math.cos(angle) * axis[0]) + abs(math.sin(angle) * axis[1])
    dy = abs(math.sin(angle) * axis[0]) + abs(math.cos(angle) * axis[1])
    top = center[0] - dy
    bottom = center[0] + dy
    left = center[1] - dx
    right = center[1] + dx
  elif padding is None:
    # There is no padding to be applied -> take nodes as they are
    top    = kwargs[keys[0]][0]
    bottom = kwargs[keys[1]][0]
    left   = kwargs[keys[0]][1]
    right  = kwargs[keys[1]][1]
  else:
    # apply padding
    pos_0 = kwargs[keys[0]]
    pos_1 = kwargs[keys[1]]
    tb_center = float(pos_0[0] + pos_1[0]) / 2.
    lr_center = float(pos_0[1] + pos_1[1]) / 2.
    distance = math.sqrt((pos_0[0] - pos_1[0])**2 + (pos_0[1] - pos_1[1])**2)

    top    = tb_center + padding['top'] * distance
    bottom = tb_center + padding['bottom'] * distance
    left   = lr_center + padding['left'] * distance
    right  = lr_center + padding['right'] * distance

  return BoundingBox((top, left), (bottom - top, right - left))