Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Random Resized Crop #499

Merged
merged 44 commits into from
Jun 29, 2022
Merged
Show file tree
Hide file tree
Changes from 9 commits
Commits
Show all changes
44 commits
Select commit Hold shift + click to select a range
8237608
Created random resized crop files
AdityaKane2001 Jun 16, 2022
ebb52bd
Added test from #457
AdityaKane2001 Jun 16, 2022
43ae6b6
Used `tf.image.crop_and_resize` instead of `ImageProjectionTransformV3`
AdityaKane2001 Jun 18, 2022
ddcc662
Minor bug
AdityaKane2001 Jun 18, 2022
7916bc5
Merge branch 'master' into rrc
AdityaKane2001 Jun 18, 2022
19ff395
Formatted
AdityaKane2001 Jun 18, 2022
0a2042d
Reformatted
AdityaKane2001 Jun 19, 2022
8967911
Update keras_cv/layers/preprocessing/random_resized_crop.py
AdityaKane2001 Jun 21, 2022
0f25f7e
Apply suggestions from code review
AdityaKane2001 Jun 21, 2022
258b979
Doc changes
AdityaKane2001 Jun 23, 2022
2ed932f
Doc changes
AdityaKane2001 Jun 23, 2022
bcb876c
Doc changes
AdityaKane2001 Jun 23, 2022
be4e8f0
Made requested changes
AdityaKane2001 Jun 23, 2022
2e259cd
Merge branch 'master' into rrc
AdityaKane2001 Jun 23, 2022
2044339
Reformatted and tested
AdityaKane2001 Jun 23, 2022
1911775
Update keras_cv/layers/preprocessing/random_resized_crop.py
AdityaKane2001 Jun 24, 2022
f87732a
Made requested changes
AdityaKane2001 Jun 24, 2022
9036bd8
Created random resized crop files
AdityaKane2001 Jun 16, 2022
309d266
Added test from #457
AdityaKane2001 Jun 16, 2022
5c89b18
Used `tf.image.crop_and_resize` instead of `ImageProjectionTransformV3`
AdityaKane2001 Jun 18, 2022
ca405cf
Minor bug
AdityaKane2001 Jun 18, 2022
83e090a
Formatted
AdityaKane2001 Jun 18, 2022
0787611
Reformatted
AdityaKane2001 Jun 19, 2022
6cb4965
Doc changes
AdityaKane2001 Jun 23, 2022
6e2bdcb
Update keras_cv/layers/preprocessing/random_resized_crop.py
AdityaKane2001 Jun 21, 2022
a4973be
Apply suggestions from code review
AdityaKane2001 Jun 21, 2022
55c19db
Doc changes
AdityaKane2001 Jun 23, 2022
9edae6b
Made requested changes
AdityaKane2001 Jun 23, 2022
75ce892
Reformatted and tested
AdityaKane2001 Jun 23, 2022
fbb1f83
Luke edits
LukeWood Jun 24, 2022
844ec79
remove merge conflict
LukeWood Jun 24, 2022
4a2aa3c
Fix broken test cases
LukeWood Jun 24, 2022
8006afc
Fix merge conflicts
AdityaKane2001 Jun 25, 2022
b1448a4
Made changes to rrc
AdityaKane2001 Jun 25, 2022
fa8b715
Minor changes
AdityaKane2001 Jun 28, 2022
82d6de0
Added checks
AdityaKane2001 Jun 29, 2022
a2f7e24
Added checks
AdityaKane2001 Jun 29, 2022
4e85e59
Added checks for inputs
AdityaKane2001 Jun 29, 2022
4c80dc0
Docstring updates
LukeWood Jun 29, 2022
95e4d6e
Made requested changes
AdityaKane2001 Jun 29, 2022
f0f897d
Minor changes
AdityaKane2001 Jun 29, 2022
b283cb4
Added demo
AdityaKane2001 Jun 29, 2022
6ab77e3
Formatted
AdityaKane2001 Jun 29, 2022
0b6c478
Update random_resized_crop_demo
LukeWood Jun 29, 2022
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions keras_cv/layers/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,7 @@
from keras_cv.layers.preprocessing.random_cutout import RandomCutout
from keras_cv.layers.preprocessing.random_gaussian_blur import RandomGaussianBlur
from keras_cv.layers.preprocessing.random_hue import RandomHue
from keras_cv.layers.preprocessing.random_resized_crop import RandomResizedCrop
from keras_cv.layers.preprocessing.random_saturation import RandomSaturation
from keras_cv.layers.preprocessing.random_sharpness import RandomSharpness
from keras_cv.layers.preprocessing.random_shear import RandomShear
Expand Down
1 change: 1 addition & 0 deletions keras_cv/layers/preprocessing/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,7 @@
from keras_cv.layers.preprocessing.random_cutout import RandomCutout
from keras_cv.layers.preprocessing.random_gaussian_blur import RandomGaussianBlur
from keras_cv.layers.preprocessing.random_hue import RandomHue
from keras_cv.layers.preprocessing.random_resized_crop import RandomResizedCrop
from keras_cv.layers.preprocessing.random_saturation import RandomSaturation
from keras_cv.layers.preprocessing.random_sharpness import RandomSharpness
from keras_cv.layers.preprocessing.random_shear import RandomShear
Expand Down
140 changes: 140 additions & 0 deletions keras_cv/layers/preprocessing/random_resized_crop.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Copyright 2022 The KerasCV Authors
#
# 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
#
# https://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.
import warnings

import tensorflow as tf

from keras_cv.layers import BaseImageAugmentationLayer
from keras_cv.utils import preprocessing


@tf.keras.utils.register_keras_serializable(package="keras_cv")
class RandomResizedCrop(BaseImageAugmentationLayer):
"""
Randomly crops a part of an image and resizes it to provided size.
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved

Args:
target_size: A tuple of two integers used as the target size to crop
images to.
aspect_ratio_factor: (Optional) A tuple of two floats. Represents the
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
lower and upper bounds for the aspect ratio of the cropped image
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
before resizing it to `target_size`. Defaults to (3./4., 4./3.).
area_factor: (Optional) A tuple of two floats, a single float or
`keras_cv.FactorSampler`. Represents the lower and upper bounds for
the area relative to the original image of the cropped image before
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
resizing it to `target_size`. Defaults to (0.08, 1.0).
interpolation: interpolation method used in the `ImageProjectiveTransformV3` op.
Supported values are `"nearest"` and `"bilinear"`.
Defaults to `"bilinear"`.
fill_mode: fill_mode in the `ImageProjectiveTransformV3` op.
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
Supported values are `"reflect"`, `"wrap"`, `"constant"`, and `"nearest"`.
Defaults to `"reflect"`.
fill_value: fill_value in the `ImageProjectiveTransformV3` op.
A `Tensor` of type `float32`. The value to be filled when fill_mode is
constant". Defaults to `0.0`.
seed: Integer. Used to create a random seed.
"""
def __init__(self,
target_size,
aspect_ratio_factor=(3. / 4., 4. / 3.),
area_factor=(0.08, 1.0),
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
interpolation="bilinear",
fill_mode="reflect",
fill_value=0.0,
seed=None,
**kwargs):
super(RandomResizedCrop, self).__init__(seed=seed, **kwargs)
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved

self.target_size = target_size
self.aspect_ratio_factor = aspect_ratio_factor
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
self.area_factor = preprocessing.parse_factor(area_factor,
param_name="area_factor",
seed=seed)

self.interpolation = interpolation
self.fill_mode = fill_mode
self.fill_value = fill_value
self.seed = seed

if area_factor == 0.0 and aspect_ratio_factor == 0.0:
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
warnings.warn(
"RandomResizedCrop received both `area_factor=0.0` and "
"`aspect_ratio_factor=0.0`. As a result, the layer will perform no "
"augmentation.")

def get_random_transformation(self,
image=None,
label=None,
bounding_box=None):
area_factor = self.area_factor()
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
aspect_ratio = tf.random.uniform((),
minval=self.aspect_ratio_factor[0],
maxval=self.aspect_ratio_factor[1],
dtype=tf.float32)

new_height = tf.clip_by_value(
tf.sqrt(area_factor / aspect_ratio), 0.0,
1.0) # to avoid unwanted/unintuitive effects
new_width = tf.clip_by_value(tf.sqrt(area_factor * aspect_ratio), 0.0,
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
1.0)

height_offset = tf.random.uniform(
(),
minval=tf.minimum(0.0, 1.0 - new_height),
maxval=tf.maximum(0.0, 1.0 - new_height),
dtype=tf.float32,
)

width_offset = tf.random.uniform(
(),
minval=tf.minimum(0.0, 1.0 - new_width),
maxval=tf.maximum(0.0, 1.0 - new_width),
dtype=tf.float32,
)

y1 = height_offset
y2 = height_offset + new_height
x1 = width_offset
x2 = width_offset + new_width

return [[y1, x1, y2, x2]]

def augment_image(self, image, transformation):
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
image = tf.expand_dims(image, axis=0)
LukeWood marked this conversation as resolved.
Show resolved Hide resolved
boxes = transformation
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved

# See bit.ly/tf_crop_resize for more details
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
augmented_image = tf.image.crop_and_resize(
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
image, # image shape: [B, H, W, C]
boxes, # boxes: (1, 4) in this case; represents area
# to be cropped from the original image
[0], # box_indices: maps boxes to images along batch axis
# [0] since there is only one image
self.target_size, # output size
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
)

return tf.squeeze(augmented_image, axis=0)

def get_config(self):
config = super().get_config()
config.update({
"target_size": self.target_size,
"area_factor": self.area_factor,
"aspect_ratio_factor": self.aspect_ratio_factor,
"interpolation": self.interpolation,
"fill_mode": self.fill_mode,
"fill_value": self.fill_value,
"seed": self.seed,
})
return config
42 changes: 42 additions & 0 deletions keras_cv/layers/preprocessing/random_resized_crop_test.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# Copyright 2022 The KerasCV Authors
#
# 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
#
# https://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.
import tensorflow as tf

from keras_cv.layers import preprocessing


class RandomResizedCropTest(tf.test.TestCase):
def train_augments_image(self):
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
# Checks if original and augmented images are different

input_image_shape = (4, 300, 300, 3)
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
image = tf.random.uniform(shape=input_image_shape)

layer = preprocessing.RandomResizedCrop((224, 224))
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
output = layer(image, training=True)

output_image_resized = tf.image.resize(output, input_image_shape)

self.assertNotEqual(image, output_image_resized)

def test_preserves_image(self):
LukeWood marked this conversation as resolved.
Show resolved Hide resolved
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
# Checks if resultant image stays the same at inference time

image_shape = (4, 300, 300, 3)
image = tf.random.uniform(shape=image_shape)

layer = preprocessing.RandomResizedCrop((300, 300))
output = layer(image, training=False)

self.assertEqual(image.shape, output.shape)
103 changes: 85 additions & 18 deletions keras_cv/layers/serialization_test.py
Original file line number Diff line number Diff line change
Expand Up @@ -36,54 +36,96 @@ def config_equals(config1, config2):

class SerializationTest(tf.test.TestCase, parameterized.TestCase):
@parameterized.named_parameters(
("AutoContrast", preprocessing.AutoContrast, {"value_range": (0, 255)}),
("ChannelShuffle", preprocessing.ChannelShuffle, {"seed": 1}),
("CutMix", preprocessing.CutMix, {"seed": 1}),
("Equalization", preprocessing.Equalization, {"value_range": (0, 255)}),
("AutoContrast", preprocessing.AutoContrast, {
"value_range": (0, 255)
}),
("ChannelShuffle", preprocessing.ChannelShuffle, {
"seed": 1
}),
("CutMix", preprocessing.CutMix, {
"seed": 1
}),
("Equalization", preprocessing.Equalization, {
"value_range": (0, 255)
}),
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
("Grayscale", preprocessing.Grayscale, {}),
("GridMask", preprocessing.GridMask, {"seed": 1}),
("MixUp", preprocessing.MixUp, {"seed": 1}),
("GridMask", preprocessing.GridMask, {
"seed": 1
}),
("MixUp", preprocessing.MixUp, {
"seed": 1
}),
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
(
"RandomChannelShift",
preprocessing.RandomChannelShift,
{"value_range": (0, 255), "factor": 0.5},
{
"value_range": (0, 255),
"factor": 0.5
},
),
(
"Posterization",
preprocessing.Posterization,
{"bits": 3, "value_range": (0, 255)},
{
"bits": 3,
"value_range": (0, 255)
},
AdityaKane2001 marked this conversation as resolved.
Show resolved Hide resolved
),
(
"RandomColorDegeneration",
preprocessing.RandomColorDegeneration,
{"factor": 0.5, "seed": 1},
{
"factor": 0.5,
"seed": 1
},
),
(
"RandomCutout",
preprocessing.RandomCutout,
{"height_factor": 0.2, "width_factor": 0.2, "seed": 1},
{
"height_factor": 0.2,
"width_factor": 0.2,
"seed": 1
},
),
(
"RandomHue",
preprocessing.RandomHue,
{"factor": 0.5, "value_range": (0, 255), "seed": 1},
{
"factor": 0.5,
"value_range": (0, 255),
"seed": 1
},
),
(
"RandomSaturation",
preprocessing.RandomSaturation,
{"factor": 0.5, "seed": 1},
{
"factor": 0.5,
"seed": 1
},
),
(
"RandomSharpness",
preprocessing.RandomSharpness,
{"factor": 0.5, "value_range": (0, 255), "seed": 1},
{
"factor": 0.5,
"value_range": (0, 255),
"seed": 1
},
),
(
"RandomShear",
preprocessing.RandomShear,
{"x_factor": 0.3, "x_factor": 0.3, "seed": 1},
{
"x_factor": 0.3,
"x_factor": 0.3,
"seed": 1
},
),
("Solarization", preprocessing.Solarization, {"value_range": (0, 255)}),
("Solarization", preprocessing.Solarization, {
"value_range": (0, 255)
}),
(
"RandAugment",
preprocessing.RandAugment,
Expand All @@ -98,12 +140,20 @@ class SerializationTest(tf.test.TestCase, parameterized.TestCase):
(
"RandomAugmentationPipeline",
preprocessing.RandomAugmentationPipeline,
{"layers": [], "augmentations_per_image": 1, "rate": 1.0},
{
"layers": [],
"augmentations_per_image": 1,
"rate": 1.0
},
),
(
"RandomChoice",
preprocessing.RandomChoice,
{"layers": [], "seed": 3, "auto_vectorize": False},
{
"layers": [],
"seed": 3,
"auto_vectorize": False
},
),
(
"RandomColorJitter",
Expand All @@ -117,10 +167,27 @@ class SerializationTest(tf.test.TestCase, parameterized.TestCase):
"seed": 1,
},
),
(
"RandomResizedCrop",
preprocessing.RandomResizedCrop,
{
"target_size": (224, 224),
"area_factor": (0.08, 1.0),
"aspect_ratio_factor": (3. / 4., 4. / 3.),
"interpolation": "bilinear",
"fill_mode": "reflect",
"fill_value": 0.,
"seed": 1,
},
),
(
"DropBlock2D",
regularization.DropBlock2D,
{"rate": 0.1, "block_size": (7, 7), "seed": 1234},
{
"rate": 0.1,
"block_size": (7, 7),
"seed": 1234
},
),
(
"StochasticDepth",
Expand Down