//  [python]
def random_shift_bbox(image, bbox, pixel_scaling, replace,
                      new_min_bbox_coords=None):
  """Move the bbox and the image content to a slightly new random location.

  Args:
    image: 3D uint8 Tensor.
    bbox: 1D Tensor that has 4 elements (min_y, min_x, max_y, max_x)
      of type float that represents the normalized coordinates between 0 and 1.
      The potential values for the new min corner of the bbox will be between
      [old_min - pixel_scaling * bbox_height/2,
       old_min - pixel_scaling * bbox_height/2].
    pixel_scaling: A float between 0 and 1 that specifies the pixel range
      that the new bbox location will be sampled from.
    replace: A one or three value 1D tensor to fill empty pixels.
    new_min_bbox_coords: If not None, then this is a tuple that specifies the
      (min_y, min_x) coordinates of the new bbox. Normally this is randomly
      specified, but this allows it to be manually set. The coordinates are
      the absolute coordinates between 0 and image height/width and are int32.

  Returns:
    The new image that will have the shifted bbox location in it along with
    the new bbox that contains the new coordinates.
  """
  # Obtains image height and width and create helper clip functions.
  image_height = tf.cast(tf.shape(image)[0], tf.float32)
  image_width = tf.cast(tf.shape(image)[1], tf.float32)
  def clip_y(val):
    return tf.clip_by_value(val, 0, tf.to_int32(image_height) - 1)
  def clip_x(val):
    return tf.clip_by_value(val, 0, tf.to_int32(image_width) - 1)

  # Convert bbox to pixel coordinates.
  min_y = tf.to_int32(image_height * bbox[0])
  min_x = tf.to_int32(image_width * bbox[1])
  max_y = clip_y(tf.to_int32(image_height * bbox[2]))
  max_x = clip_x(tf.to_int32(image_width * bbox[3]))
  bbox_height, bbox_width = (max_y - min_y + 1, max_x - min_x + 1)
  image_height = tf.to_int32(image_height)
  image_width = tf.to_int32(image_width)

  # Select the new min/max bbox ranges that are used for sampling the
  # new min x/y coordinates of the shifted bbox.
  minval_y = clip_y(
      min_y - tf.to_int32(pixel_scaling * tf.cast(bbox_height, tf.float32) / 2.0))
  maxval_y = clip_y(
      min_y + tf.to_int32(pixel_scaling * tf.cast(bbox_height, tf.float32) / 2.0))
  minval_x = clip_x(
      min_x - tf.to_int32(pixel_scaling * tf.cast(bbox_width, tf.float32) / 2.0))
  maxval_x = clip_x(
      min_x + tf.to_int32(pixel_scaling * tf.cast(bbox_width, tf.float32) / 2.0))

  # Sample and calculate the new unclipped min/max coordinates of the new bbox.
  if new_min_bbox_coords is None:
    unclipped_new_min_y = tf.random_uniform(
        shape=[], minval=minval_y, maxval=maxval_y,
        dtype=tf.int32)
    unclipped_new_min_x = tf.random_uniform(
        shape=[], minval=minval_x, maxval=maxval_x,
        dtype=tf.int32)
  else:
    unclipped_new_min_y, unclipped_new_min_x = (
        clip_y(new_min_bbox_coords[0]), clip_x(new_min_bbox_coords[1]))
  unclipped_new_max_y = unclipped_new_min_y + bbox_height - 1
  unclipped_new_max_x = unclipped_new_min_x + bbox_width - 1

  # Determine if any of the new bbox was shifted outside the current image.
  # This is used for determining if any of the original bbox content should be
  # discarded.
  new_min_y, new_min_x, new_max_y, new_max_x = (
      clip_y(unclipped_new_min_y), clip_x(unclipped_new_min_x),
      clip_y(unclipped_new_max_y), clip_x(unclipped_new_max_x))
  shifted_min_y = (new_min_y - unclipped_new_min_y) + min_y
  shifted_max_y = max_y - (unclipped_new_max_y - new_max_y)
  shifted_min_x = (new_min_x - unclipped_new_min_x) + min_x
  shifted_max_x = max_x - (unclipped_new_max_x - new_max_x)

  # Create the new bbox tensor by converting pixel integer values to floats.
  new_bbox = tf.stack([
      tf.cast(new_min_y, tf.float32) / tf.cast(image_height, tf.float32),
      tf.cast(new_min_x, tf.float32) / tf.cast(image_width, tf.float32),
      tf.cast(new_max_y, tf.float32) / tf.cast(image_height, tf.float32),
      tf.cast(new_max_x, tf.float32) / tf.cast(image_width, tf.float32)])

  # Copy the contents in the bbox and fill the old bbox location
  # with gray (128).
  bbox_content = image[shifted_min_y:shifted_max_y + 1,
                       shifted_min_x:shifted_max_x + 1, :]

  def mask_and_add_image(
      min_y_, min_x_, max_y_, max_x_, mask, content_tensor, image_):
    """Applies mask to bbox region in image then adds content_tensor to it."""
    mask = tf.pad(mask,
                  [[min_y_, (image_height - 1) - max_y_],
                   [min_x_, (image_width - 1) - max_x_],
                   [0, 0]], constant_values=1)
    content_tensor = tf.pad(content_tensor,
                            [[min_y_, (image_height - 1) - max_y_],
                             [min_x_, (image_width - 1) - max_x_],
                             [0, 0]], constant_values=0)
    return image_ * mask + content_tensor

  # Zero out original bbox location.
  mask = tf.zeros_like(image)[min_y:max_y+1, min_x:max_x+1, :]
  grey_tensor = tf.zeros_like(mask) + replace[0]
  image = mask_and_add_image(min_y, min_x, max_y, max_x, mask,
                             grey_tensor, image)

  # Fill in bbox content to new bbox location.
  mask = tf.zeros_like(bbox_content)
  image = mask_and_add_image(new_min_y, new_min_x, new_max_y, new_max_x, mask,
                             bbox_content, image)

  return image, new_bbox