136 lines
5.3 KiB
Python
136 lines
5.3 KiB
Python
# Copyright 2023 The TensorFlow Authors. All Rights Reserved.
|
|
#
|
|
# Licensed under the Apache License, Version 2.0 (the "License");
|
|
# you may not use this file except in compliance with the License.
|
|
# You may obtain a copy of the License at
|
|
#
|
|
# http://www.apache.org/licenses/LICENSE-2.0
|
|
#
|
|
# Unless required by applicable law or agreed to in writing, software
|
|
# distributed under the License is distributed on an "AS IS" BASIS,
|
|
# WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
|
# See the License for the specific language governing permissions and
|
|
# limitations under the License.
|
|
# ==============================================================================
|
|
"""Operations for random tensor cropping."""
|
|
|
|
from tensorflow.python.framework import dtypes
|
|
from tensorflow.python.framework import ops
|
|
from tensorflow.python.ops import array_ops
|
|
from tensorflow.python.ops import control_flow_assert
|
|
from tensorflow.python.ops import control_flow_ops
|
|
from tensorflow.python.ops import math_ops
|
|
from tensorflow.python.ops import random_ops
|
|
from tensorflow.python.ops import stateless_random_ops
|
|
from tensorflow.python.util import deprecation
|
|
from tensorflow.python.util import dispatch
|
|
from tensorflow.python.util.tf_export import tf_export
|
|
|
|
|
|
@tf_export("image.random_crop", v1=["image.random_crop", "random_crop"])
|
|
@dispatch.add_dispatch_support
|
|
@deprecation.deprecated_endpoints("random_crop")
|
|
def random_crop(value, size, seed=None, name=None):
|
|
"""Randomly crops a tensor to a given size.
|
|
|
|
Slices a shape `size` portion out of `value` at a uniformly chosen offset.
|
|
Requires `value.shape >= size`.
|
|
|
|
If a dimension should not be cropped, pass the full size of that dimension.
|
|
For example, RGB images can be cropped with
|
|
`size = [crop_height, crop_width, 3]`.
|
|
|
|
Example usage:
|
|
|
|
>>> image = [[1, 2, 3], [4, 5, 6]]
|
|
>>> result = tf.image.random_crop(value=image, size=(1, 3))
|
|
>>> result.shape.as_list()
|
|
[1, 3]
|
|
|
|
For producing deterministic results given a `seed` value, use
|
|
`tf.image.stateless_random_crop`. Unlike using the `seed` param with
|
|
`tf.image.random_*` ops, `tf.image.stateless_random_*` ops guarantee the same
|
|
results given the same seed independent of how many times the function is
|
|
called, and independent of global seed settings (e.g. tf.random.set_seed).
|
|
|
|
Args:
|
|
value: Input tensor to crop.
|
|
size: 1-D tensor with size the rank of `value`.
|
|
seed: Python integer. Used to create a random seed. See
|
|
`tf.random.set_seed`
|
|
for behavior.
|
|
name: A name for this operation (optional).
|
|
|
|
Returns:
|
|
A cropped tensor of the same rank as `value` and shape `size`.
|
|
"""
|
|
with ops.name_scope(name, "random_crop", [value, size]) as name:
|
|
value = ops.convert_to_tensor(value, name="value")
|
|
size = ops.convert_to_tensor(size, dtype=dtypes.int32, name="size")
|
|
shape = array_ops.shape(value)
|
|
check = control_flow_assert.Assert(
|
|
math_ops.reduce_all(shape >= size),
|
|
["Need value.shape >= size, got ", shape, size],
|
|
summarize=1000)
|
|
shape = control_flow_ops.with_dependencies([check], shape)
|
|
limit = shape - size + 1
|
|
offset = random_ops.random_uniform(
|
|
array_ops.shape(shape),
|
|
dtype=size.dtype,
|
|
maxval=size.dtype.max,
|
|
seed=seed) % limit
|
|
return array_ops.slice(value, offset, size, name=name)
|
|
|
|
|
|
@tf_export("image.stateless_random_crop", v1=[])
|
|
@dispatch.add_dispatch_support
|
|
def stateless_random_crop(value, size, seed, name=None):
|
|
"""Randomly crops a tensor to a given size in a deterministic manner.
|
|
|
|
Slices a shape `size` portion out of `value` at a uniformly chosen offset.
|
|
Requires `value.shape >= size`.
|
|
|
|
If a dimension should not be cropped, pass the full size of that dimension.
|
|
For example, RGB images can be cropped with
|
|
`size = [crop_height, crop_width, 3]`.
|
|
|
|
Guarantees the same results given the same `seed` independent of how many
|
|
times the function is called, and independent of global seed settings (e.g.
|
|
`tf.random.set_seed`).
|
|
|
|
Usage Example:
|
|
|
|
>>> image = [[[1, 2, 3], [4, 5, 6]], [[7, 8, 9], [10, 11, 12]]]
|
|
>>> seed = (1, 2)
|
|
>>> tf.image.stateless_random_crop(value=image, size=(1, 2, 3), seed=seed)
|
|
<tf.Tensor: shape=(1, 2, 3), dtype=int32, numpy=
|
|
array([[[1, 2, 3],
|
|
[4, 5, 6]]], dtype=int32)>
|
|
|
|
Args:
|
|
value: Input tensor to crop.
|
|
size: 1-D tensor with size the rank of `value`.
|
|
seed: A shape [2] Tensor, the seed to the random number generator. Must have
|
|
dtype `int32` or `int64`. (When using XLA, only `int32` is allowed.)
|
|
name: A name for this operation (optional).
|
|
|
|
Returns:
|
|
A cropped tensor of the same rank as `value` and shape `size`.
|
|
"""
|
|
with ops.name_scope(name, "random_crop", [value, size]) as name:
|
|
value = ops.convert_to_tensor(value, name="value")
|
|
size = ops.convert_to_tensor(size, dtype=dtypes.int32, name="size")
|
|
shape = array_ops.shape(value)
|
|
check = control_flow_assert.Assert(
|
|
math_ops.reduce_all(shape >= size),
|
|
["Need value.shape >= size, got ", shape, size],
|
|
summarize=1000)
|
|
shape = control_flow_ops.with_dependencies([check], shape)
|
|
limit = shape - size + 1
|
|
offset = stateless_random_ops.stateless_random_uniform(
|
|
array_ops.shape(shape),
|
|
dtype=size.dtype,
|
|
maxval=size.dtype.max,
|
|
seed=seed) % limit
|
|
return array_ops.slice(value, offset, size, name=name)
|
|
|