class_docstr: Compute the bounding boxes and object classes from segmentation masks.
docstr: Compute the bounding boxes and object classes.
  
  based on:
  https://github.com/facebookresearch/detr/blob/6a608d3c3a9e10403379f7e7f65f48e26d03f645/util/box_ops.py#L64
  
  Args:
    features: dict; Contains a single unbatched input example with keys
      `inputs` and `label`. `label` contains the field `masks` with a tensor
      of shape [num_objects, H, W, 1].
  
  Returns:
    An updated feature dict with box coordinates and labels.
code: def __call__(self, features):
      """Compute the bounding boxes and object classes.
  
      based on:
      https://github.com/facebookresearch/detr/blob/6a608d3c3a9e10403379f7e7f65f48e26d03f645/util/box_ops.py#L64
  
      Args:
        features: dict; Contains a single unbatched input example with keys
          `inputs` and `label`. `label` contains the field `masks` with a tensor
          of shape [num_objects, H, W, 1].
  
      Returns:
        An updated feature dict with box coordinates and labels.
      """
      instance_masks = features["label"]["masks"][
          ..., 0
      ]  # Remove channel dim.
      object_labels = features["label"]["labels"]
      h = tf.shape(instance_masks)[-2]
      w = tf.shape(instance_masks)[-1]
      x, y = tf.meshgrid(tf.range(w), tf.range(h))
  
      def get_axis_min_max(axis_grid):
          """Calculates the min and max pixel along the given axis for each object.
  
          Args:
            axis_grid: tensor; grid of axis over which min and max is calculated.
  
          Returns:
            tuple(int): axis_min and axis_max
          """
          axis_mask = instance_masks * tf.expand_dims(axis_grid, axis=0)
          axis_max = tf.math.reduce_max(axis_mask, axis=(1, 2))
          axis_min = tf.math.reduce_min(
              tf.where(instance_masks == 0, int(1e8), axis_mask),
              axis=(1, 2),
          )
          return axis_min, axis_max
  
      x_min, x_max = get_axis_min_max(x)
      y_min, y_max = get_axis_min_max(y)
  
      # Stack objects to form the shape [num_objects, 4].
      bbox = tf.stack([x_min, y_min, x_max, y_max], 1)
  
      # Filter out objects that do not fall into the resized/cropped image
      # non-existing objects are those with:
      #  [x_min, y_min, x_max, y_max] = [int(1e8), int(1e8), 0, 0]
      existing_objects_bool = tf.reduce_all(
          tf.not_equal(bbox, [int(1e8), int(1e8), 0, 0]), axis=-1
      )
      existing_objects = tf.where(existing_objects_bool)
      existing_objects = tf.squeeze(existing_objects, -1)
  
      # Gather rows that correspond to the existing objects.
      instance_masks = tf.gather(instance_masks, existing_objects)
      bbox = tf.gather(bbox, existing_objects)
      object_labels = tf.gather(object_labels, existing_objects)
      object_labels = object_labels + 1  # for the padded objects
  
      # Maps boxes to cxcywh format (the loss function expects to receive cxcywh).
      bbox = tf.cast(bbox, tf.float32)
      x0, y0, x1, y1 = tf.split(bbox, 4, axis=-1)
      bbox = tf.concat(
          [(x0 + x1) / 2, (y0 + y1) / 2, (x1 - x0), (y1 - y0)], axis=-1
      )
  
      # Normalizes boxes to [0, 1].
      size = tf.reshape(tf.stack([w, h, w, h]), shape=[1, 4])
      size = tf.cast(size, tf.float32)
      bbox = bbox / size
  
      # Add channel dim back:
      instance_masks = instance_masks[..., tf.newaxis]
  
      tf.debugging.assert_shapes(
          (
              (bbox, ["num_objects", 4]),
              (object_labels, ["num_objects"]),
              (instance_masks, ["num_objects", "h", "w", 1]),
          )
      )
  
      if self.keep_masks:
          features["label"]["masks"] = tf.identity(
              instance_masks, "masks"
          )
      else:
          del features["label"]["masks"]
      features["label"]["boxes"] = tf.identity(bbox, "boxes")
      features["label"]["labels"] = tf.identity(object_labels, "labels")
  
      return features
  
imports: from typing import Any, Dict
  import tensorflow
label_desc: Use image node_id 2 for calling the GetCocoBboxFromMasks obj's underlying member method code with example usage: obj.__call__(features) and returns: features, axis_min,  axis_max