Skip to content

Commit 2db547b

Browse files
authored
Adjust value_range for random_contrast and random_hue (#20671)
* Adjust value_range for random_contrast and random_hue * Add value_range description * Correct failed test cases
1 parent 84b531c commit 2db547b

File tree

4 files changed

+83
-13
lines changed

4 files changed

+83
-13
lines changed

keras/src/layers/preprocessing/image_preprocessing/random_contrast.py

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -40,14 +40,19 @@ class RandomContrast(BaseImagePreprocessingLayer):
4040
`[1.0 - lower, 1.0 + upper]`. For any pixel x in the channel,
4141
the output will be `(x - mean) * factor + mean`
4242
where `mean` is the mean value of the channel.
43+
value_range: the range of values the incoming images will have.
44+
Represented as a two-number tuple written `[low, high]`. This is
45+
typically either `[0, 1]` or `[0, 255]` depending on how your
46+
preprocessing pipeline is set up.
4347
seed: Integer. Used to create a random seed.
4448
"""
4549

4650
_FACTOR_BOUNDS = (0, 1)
4751

48-
def __init__(self, factor, seed=None, **kwargs):
52+
def __init__(self, factor, value_range=(0, 255), seed=None, **kwargs):
4953
super().__init__(**kwargs)
5054
self._set_factor(factor)
55+
self.value_range = value_range
5156
self.seed = seed
5257
self.generator = SeedGenerator(seed)
5358

@@ -89,7 +94,9 @@ def transform_images(self, images, transformation, training=True):
8994
if training:
9095
constrast_factor = transformation["contrast_factor"]
9196
outputs = self._adjust_constrast(images, constrast_factor)
92-
outputs = self.backend.numpy.clip(outputs, 0, 255)
97+
outputs = self.backend.numpy.clip(
98+
outputs, self.value_range[0], self.value_range[1]
99+
)
93100
self.backend.numpy.reshape(outputs, self.backend.shape(images))
94101
return outputs
95102
return images
@@ -135,6 +142,7 @@ def compute_output_shape(self, input_shape):
135142
def get_config(self):
136143
config = {
137144
"factor": self.factor,
145+
"value_range": self.value_range,
138146
"seed": self.seed,
139147
}
140148
base_config = super().get_config()

keras/src/layers/preprocessing/image_preprocessing/random_contrast_test.py

Lines changed: 56 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ def test_layer(self):
1414
layers.RandomContrast,
1515
init_kwargs={
1616
"factor": 0.75,
17+
"value_range": (0, 255),
1718
"seed": 1,
1819
},
1920
input_shape=(8, 3, 4, 3),
@@ -24,6 +25,7 @@ def test_layer(self):
2425
layers.RandomContrast,
2526
init_kwargs={
2627
"factor": 0.75,
28+
"value_range": (0, 255),
2729
"seed": 1,
2830
"data_format": "channels_first",
2931
},
@@ -32,21 +34,67 @@ def test_layer(self):
3234
expected_output_shape=(8, 3, 4, 4),
3335
)
3436

35-
def test_random_contrast(self):
37+
def test_random_contrast_with_value_range_0_to_255(self):
3638
seed = 9809
3739
np.random.seed(seed)
38-
inputs = np.random.random((12, 8, 16, 3))
39-
layer = layers.RandomContrast(factor=0.5, seed=seed)
40-
outputs = layer(inputs)
40+
41+
data_format = backend.config.image_data_format()
42+
if data_format == "channels_last":
43+
inputs = np.random.random((12, 8, 16, 3))
44+
height_axis = -3
45+
width_axis = -2
46+
else:
47+
inputs = np.random.random((12, 3, 8, 16))
48+
height_axis = -2
49+
width_axis = -1
50+
51+
inputs = backend.convert_to_tensor(inputs, dtype="float32")
52+
layer = layers.RandomContrast(
53+
factor=0.5, value_range=(0, 255), seed=seed
54+
)
55+
transformation = layer.get_random_transformation(inputs, training=True)
56+
outputs = layer.transform_images(inputs, transformation, training=True)
57+
58+
# Actual contrast arithmetic
59+
np.random.seed(seed)
60+
factor = backend.convert_to_numpy(transformation["contrast_factor"])
61+
inputs = backend.convert_to_numpy(inputs)
62+
inp_mean = np.mean(inputs, axis=height_axis, keepdims=True)
63+
inp_mean = np.mean(inp_mean, axis=width_axis, keepdims=True)
64+
actual_outputs = (inputs - inp_mean) * factor + inp_mean
65+
outputs = backend.convert_to_numpy(outputs)
66+
actual_outputs = np.clip(actual_outputs, 0, 255)
67+
68+
self.assertAllClose(outputs, actual_outputs)
69+
70+
def test_random_contrast_with_value_range_0_to_1(self):
71+
seed = 9809
72+
np.random.seed(seed)
73+
74+
data_format = backend.config.image_data_format()
75+
if data_format == "channels_last":
76+
inputs = np.random.random((12, 8, 16, 3))
77+
height_axis = -3
78+
width_axis = -2
79+
else:
80+
inputs = np.random.random((12, 3, 8, 16))
81+
height_axis = -2
82+
width_axis = -1
83+
84+
inputs = backend.convert_to_tensor(inputs, dtype="float32")
85+
layer = layers.RandomContrast(factor=0.5, value_range=(0, 1), seed=seed)
86+
transformation = layer.get_random_transformation(inputs, training=True)
87+
outputs = layer.transform_images(inputs, transformation, training=True)
4188

4289
# Actual contrast arithmetic
4390
np.random.seed(seed)
44-
factor = np.random.uniform(0.5, 1.5)
45-
inp_mean = np.mean(inputs, axis=-3, keepdims=True)
46-
inp_mean = np.mean(inp_mean, axis=-2, keepdims=True)
91+
factor = backend.convert_to_numpy(transformation["contrast_factor"])
92+
inputs = backend.convert_to_numpy(inputs)
93+
inp_mean = np.mean(inputs, axis=height_axis, keepdims=True)
94+
inp_mean = np.mean(inp_mean, axis=width_axis, keepdims=True)
4795
actual_outputs = (inputs - inp_mean) * factor + inp_mean
4896
outputs = backend.convert_to_numpy(outputs)
49-
actual_outputs = np.clip(outputs, 0, 255)
97+
actual_outputs = np.clip(actual_outputs, 0, 1)
5098

5199
self.assertAllClose(outputs, actual_outputs)
52100

keras/src/layers/preprocessing/image_preprocessing/random_hue.py

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -44,7 +44,12 @@ class RandomHue(BaseImagePreprocessingLayer):
4444
_FACTOR_BOUNDS = (0, 1)
4545

4646
def __init__(
47-
self, factor, value_range, data_format=None, seed=None, **kwargs
47+
self,
48+
factor,
49+
value_range=(0, 255),
50+
data_format=None,
51+
seed=None,
52+
**kwargs,
4853
):
4954
super().__init__(data_format=data_format, **kwargs)
5055
self._set_factor(factor)

keras/src/layers/preprocessing/image_preprocessing/random_hue_test.py

Lines changed: 11 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,24 @@ def test_random_hue_inference(self):
3131
output = layer(inputs, training=False)
3232
self.assertAllClose(inputs, output)
3333

34-
def test_random_hue_value_range(self):
34+
def test_random_hue_value_range_0_to_1(self):
3535
image = keras.random.uniform(shape=(3, 3, 3), minval=0, maxval=1)
3636

37-
layer = layers.RandomHue(0.2, (0, 255))
37+
layer = layers.RandomHue(0.2, (0, 1))
3838
adjusted_image = layer(image)
3939

4040
self.assertTrue(keras.ops.numpy.all(adjusted_image >= 0))
4141
self.assertTrue(keras.ops.numpy.all(adjusted_image <= 1))
4242

43+
def test_random_hue_value_range_0_to_255(self):
44+
image = keras.random.uniform(shape=(3, 3, 3), minval=0, maxval=255)
45+
46+
layer = layers.RandomHue(0.2, (0, 255))
47+
adjusted_image = layer(image)
48+
49+
self.assertTrue(keras.ops.numpy.all(adjusted_image >= 0))
50+
self.assertTrue(keras.ops.numpy.all(adjusted_image <= 255))
51+
4352
def test_random_hue_no_change_with_zero_factor(self):
4453
data_format = backend.config.image_data_format()
4554
if data_format == "channels_last":

0 commit comments

Comments
 (0)