def random_self_concat_image(
    image, boxes, labels, label_weights, label_confidences=None,
    multiclass_scores=None, concat_vertical_probability=0.1,
    concat_horizontal_probability=0.1, seed=None,
    preprocess_vars_cache=None):
  """Randomly concatenates the image with itself.

  This function randomly concatenates the image with itself; the random
  variables for vertical and horizontal concatenation are independent.
  Afterwards, we adjust the old bounding boxes, and add new bounding boxes
  for the new objects.

  Args:
    image: rank 3 float32 tensor containing 1 image -> [height, width, channels]
           with pixel values varying between [0, 1].
    boxes: rank 2 float32 tensor containing the bounding boxes -> [N, 4].
           Boxes are in normalized form meaning their coordinates vary
           between [0, 1].
           Each row is in the form of [ymin, xmin, ymax, xmax].
    labels: rank 1 int32 tensor containing the object classes.
    label_weights: rank 1 float32 containing the label weights.
    label_confidences: (optional) rank 1 float32 containing the label
                       confidences.
    multiclass_scores: (optional) float32 tensor of shape
                       [num_instances, num_classes] representing the score for
                       each box for each class.
    concat_vertical_probability: (optional) a tf.float32 scalar denoting the
                                 probability of a vertical concatenation.
    concat_horizontal_probability: (optional) a tf.float32 scalar denoting the
                                   probability of a horizontal concatenation.
    seed: random seed.
    preprocess_vars_cache: PreprocessorCache object that records previously
                           performed augmentations. Updated in-place. If this
                           function is called multiple times with the same
                           non-null cache, it will perform deterministically.

  Returns:
    image: Image shape will be [new_height, new_width, channels].
    boxes: boxes which is the same rank as input boxes. Boxes are in normalized
           form.
    if label_confidences is not None also returns:
    maybe_concat_label_confidences: cropped label weights.
    if multiclass_scores is not None also returns:
    maybe_concat_multiclass_scores: cropped_multiclass_scores.
  """

  concat_vertical = (tf.random_uniform([], seed=seed) <
                     concat_vertical_probability)
  # Note the seed + 1 so we get some semblance of independence even with
  # fixed seeds.
  concat_horizontal = (tf.random_uniform([], seed=seed + 1 if seed else None)
                       < concat_horizontal_probability)

  gen_func = lambda: (concat_vertical, concat_horizontal)
  params = _get_or_create_preprocess_rand_vars(
      gen_func, preprocessor_cache.PreprocessorCache.SELF_CONCAT_IMAGE,
      preprocess_vars_cache)
  concat_vertical, concat_horizontal = params

  def _concat_image(image, boxes, labels, label_weights, axis):
    """Concats the image to itself on `axis`."""
    output_images = tf.concat([image, image], axis=axis)

    if axis == 0:
      # Concat vertically, so need to reduce the y coordinates.
      old_scaling = tf.constant([0.5, 1.0, 0.5, 1.0])
      new_translation = tf.constant([0.5, 0.0, 0.5, 0.0])
    elif axis == 1:
      old_scaling = tf.constant([1.0, 0.5, 1.0, 0.5])
      new_translation = tf.constant([0.0, 0.5, 0.0, 0.5])

    old_boxes = old_scaling * boxes
    new_boxes = old_boxes + new_translation
    all_boxes = tf.concat([old_boxes, new_boxes], axis=0)

    return [output_images, all_boxes, tf.tile(labels, [2]), tf.tile(
        label_weights, [2])]

  image, boxes, labels, label_weights = tf.cond(
      concat_vertical,
      lambda: _concat_image(image, boxes, labels, label_weights, axis=0),
      lambda: [image, boxes, labels, label_weights],
      strict=True)

  outputs = tf.cond(
      concat_horizontal,
      lambda: _concat_image(image, boxes, labels, label_weights, axis=1),
      lambda: [image, boxes, labels, label_weights],
      strict=True)

  if label_confidences is not None:
    label_confidences = tf.cond(concat_vertical,
                                lambda: tf.tile(label_confidences, [2]),
                                lambda: label_confidences)
    outputs.append(tf.cond(concat_horizontal,
                           lambda: tf.tile(label_confidences, [2]),
                           lambda: label_confidences))

  if multiclass_scores is not None:
    multiclass_scores = tf.cond(concat_vertical,
                                lambda: tf.tile(multiclass_scores, [2, 1]),
                                lambda: multiclass_scores)
    outputs.append(tf.cond(concat_horizontal,
                           lambda: tf.tile(multiclass_scores, [2, 1]),
                           lambda: multiclass_scores))

  return outputs
Randomly concatenates the image with itself.

  This function randomly concatenates the image with itself; the random
  variables for vertical and horizontal concatenation are independent.
  Afterwards, we adjust the old bounding boxes, and add new bounding boxes
  for the new objects.

  Args:
    image: rank 3 float32 tensor containing 1 image -> [height, width, channels]
           with pixel values varying between [0, 1].
    boxes: rank 2 float32 tensor containing the bounding boxes -> [N, 4].
           Boxes are in normalized form meaning their coordinates vary
           between [0, 1].
           Each row is in the form of [ymin, xmin, ymax, xmax].
    labels: rank 1 int32 tensor containing the object classes.
    label_weights: rank 1 float32 containing the label weights.
    label_confidences: (optional) rank 1 float32 containing the label
                       confidences.
    multiclass_scores: (optional) float32 tensor of shape
                       [num_instances, num_classes] representing the score for
                       each box for each class.
    concat_vertical_probability: (optional) a tf.float32 scalar denoting the
                                 probability of a vertical concatenation.
    concat_horizontal_probability: (optional) a tf.float32 scalar denoting the
                                   probability of a horizontal concatenation.
    seed: random seed.
    preprocess_vars_cache: PreprocessorCache object that records previously
                           performed augmentations. Updated in-place. If this
                           function is called multiple times with the same
                           non-null cache, it will perform deterministically.

  Returns:
    image: Image shape will be [new_height, new_width, channels].
    boxes: boxes which is the same rank as input boxes. Boxes are in normalized
           form.
    if label_confidences is not None also returns:
    maybe_concat_label_confidences: cropped label weights.
    if multiclass_scores is not None also returns:
    maybe_concat_multiclass_scores: cropped_multiclass_scores.
  
inference_api/src/main/object_detection/core/preprocessor.py