//  [python]
def randomly_crop_and_resize(image, masks, boxes, keypoints, image_size, probability=0.5):
    """
    Arguments:
        image: a float tensor with shape [height, width, 3].
        masks: a float tensor with shape [height / DOWNSAMPLE, width / DOWNSAMPLE, 2].
        boxes: a float tensor with shape [num_persons, 4].
        keypoints: an int tensor with shape [num_persons, 17, 3].
        image_size: a tuple of integers (h, w).
        probability: a float number.
    Returns:
        image: a float tensor with shape [h, w, 3].
        masks: a float tensor with shape [h / DOWNSAMPLE, w / DOWNSAMPLE, 2].
        boxes: a float tensor with shape [num_remaining, 4].
        keypoints: an int tensor with shape [num_remaining, 17, 3].
    """

    shape = tf.cast(tf.shape(image), tf.float32)
    height, width = shape[0], shape[1]
    scaler = tf.stack([height, width, height, width])
    boxes /= scaler  # to the [0, 1] range

    def crop(image, boxes, keypoints):
        """
        Arguments:
            image: a float tensor with shape [height, width, 3].
            boxes: a float tensor with shape [num_persons, 4].
            keypoints: an int tensor with shape [num_persons, 17, 3].
        Returns:
            image: a float tensor with shape [None, None, 3].
            boxes: a float tensor with shape [num_remaining, 4].
            keypoints: an int tensor with shape [num_remaining, 17, 3].
            window: a float tensor with shape [4].
        """

        image, boxes, window, keep_indices = random_image_crop(
            image, boxes, min_object_covered=0.9,
            aspect_ratio_range=(0.95, 1.05),
            area_range=(0.5, 1.0),
            overlap_threshold=OVERLAP_THRESHOLD
        )

        keypoints = tf.gather(keypoints, keep_indices)
        # it has shape [num_remaining, 17, 3]

        ymin, xmin, ymax, xmax = tf.unstack(window * scaler)
        points, v = tf.split(keypoints, [2, 1], axis=2)
        points = tf.cast(points, tf.float32)  # shape [num_remaining, 17, 2]

        translation = tf.stack([ymin, xmin])
        points = tf.to_int32(tf.round(points - translation))
        keypoints = tf.concat([points, v], axis=2)

        # note that after this some keypoints will be invisible,
        # so we need to modify the `v` vector later

        return image, boxes, keypoints, window

    whole_image_window = tf.constant([0.0, 0.0, 1.0, 1.0], dtype=tf.float32)
    do_it = tf.less(tf.random_uniform([]), probability)

    image, boxes, keypoints, window = tf.cond(
        do_it, lambda: crop(image, boxes, keypoints),
        lambda: (image, boxes, keypoints, whole_image_window)
    )

    def correct_keypoints(image_shape, keypoints):
        """
        Arguments:
            image_shape: an int tensor with shape [3].
            keypoints: an int tensor with shape [num_persons, 17, 3].
        Returns:
            an int tensor with shape [num_persons, 17, 3].
        """
        y, x, v = tf.split(keypoints, 3, axis=2)

        height = image_shape[0]
        width = image_shape[1]

        coordinate_violations = tf.concat([
            tf.less(y, 0), tf.less(x, 0),
            tf.greater_equal(y, height),
            tf.greater_equal(x, width)
        ], axis=2)  # shape [num_persons, 17, 4]

        valid_indicator = tf.logical_not(tf.reduce_any(coordinate_violations, axis=2))
        valid_indicator = tf.expand_dims(valid_indicator, 2)
        # it has shape [num_persons, 17, 1]

        v *= tf.to_int32(valid_indicator)
        keypoints = tf.concat([y, x, v], axis=2)
        return keypoints

    def rescale(boxes, keypoints, old_shape, new_shape):
        """
        Arguments:
            boxes: a float tensor with shape [num_persons, 4].
            keypoints: an int tensor with shape [num_persons, 17, 3].
            old_shape, new_shape: int tensors with shape [3].
        Returns:
            a float tensor with shape [num_persons, 4].
            an int tensor with shape [num_persons, 17, 3].
        """
        points, v = tf.split(keypoints, [2, 1], axis=2)
        points = tf.cast(points, tf.float32)

        old_shape = tf.cast(old_shape, tf.float32)
        new_shape = tf.cast(new_shape, tf.float32)
        old_height, old_width = old_shape[0], old_shape[1]
        new_height, new_width = new_shape[0], new_shape[1]

        scaler = tf.stack([new_height/old_height, new_width/old_width])
        points *= scaler

        scaler = tf.stack([new_height, new_width])
        scaler = tf.concat(2 * [scaler], axis=0)
        boxes *= scaler

        new_height = tf.to_int32(new_height)
        new_width = tf.to_int32(new_width)

        points = tf.to_int32(tf.round(points))
        y, x = tf.split(points, 2, axis=2)
        y = tf.clip_by_value(y, 0, new_height - 1)
        x = tf.clip_by_value(x, 0, new_width - 1)
        keypoints = tf.concat([y, x, v], axis=2)
        return boxes, keypoints

    old_shape = tf.shape(image)
    keypoints = correct_keypoints(old_shape, keypoints)

    h, w = image_size  # image size that will be used for training
    image = tf.image.resize_images(image, [h, w], method=RESIZE_METHOD)

    masks_height = tf.to_int32(tf.ceil(h / DOWNSAMPLE))
    masks_width = tf.to_int32(tf.ceil(w / DOWNSAMPLE))

    masks = tf.image.crop_and_resize(
        image=tf.expand_dims(masks, 0),
        boxes=tf.expand_dims(window, 0),
        box_indices=tf.constant([0], dtype=tf.int32),
        crop_size=[masks_height, masks_width],
        method='nearest'
    )
    masks = masks[0]

    boxes, keypoints = rescale(boxes, keypoints, old_shape, tf.shape(image))
    return image, masks, boxes, keypoints