//  [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.cast(image_height, tf.int32) - 1)

    def clip_x(val):
        return tf.clip_by_value(val, 0, tf.cast(image_width, tf.int32) - 1)

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

    # 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.cast(pixel_scaling * tf.cast(bbox_height, tf.float32) / 2.0, tf.int32))
    maxval_y = clip_y(
        min_y + tf.cast(pixel_scaling * tf.cast(bbox_height, tf.float32) / 2.0, tf.int32))
    minval_x = clip_x(
        min_x - tf.cast(pixel_scaling * tf.cast(bbox_width, tf.float32) / 2.0, tf.int32))
    maxval_x = clip_x(
        min_x + tf.cast(pixel_scaling * tf.cast(bbox_width, tf.float32) / 2.0, tf.int32))

    # 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