From 78121dbe04a0ce81ec7c2ed8aced156ffea7f4e2 Mon Sep 17 00:00:00 2001 From: fsx950223 Date: Fri, 20 Mar 2020 10:18:06 +0000 Subject: [PATCH 1/5] add autocontrast --- tensorflow_addons/image/contrast_op.py | 44 ++++++++++++++++++++++++++ 1 file changed, 44 insertions(+) create mode 100644 tensorflow_addons/image/contrast_op.py diff --git a/tensorflow_addons/image/contrast_op.py b/tensorflow_addons/image/contrast_op.py new file mode 100644 index 0000000000..36dda0a793 --- /dev/null +++ b/tensorflow_addons/image/contrast_op.py @@ -0,0 +1,44 @@ +import tensorflow as tf + +def autocontrast(image): + """Implements Autocontrast function from PIL using TF ops. + + Args: + image: A 3D uint8 tensor. + + Returns: + The image after it has had autocontrast applied to it and will be of type + uint8. + """ + dtype=image.dtype + interval=dtype.max - dtype.min + def scale_channel(image_channel): + """Scale the 2D image using the autocontrast rule.""" + # A possibly cheaper version can be done using cumsum/unique_with_counts + # over the histogram values, rather than iterating over the entire image. + # to compute mins and maxes. + lo = tf.reduce_min(image_channel) + hi = tf.reduce_max(image_channel) + + if hi > lo: + image_channel=tf.cast(image_channel,tf.float32) + image_channel=image_channel*(interval/(hi - lo)) + image_channel=tf.cast(image_channel, dtype) + return image_channel + + # Assumes RGB for now. Scales each channel independently + # and then stacks the result. + + ss=tf.unstack(image,axis=-1) + for i in range(len(ss)): + ss[i]=scale_channel(ss[i]) + image = tf.stack(ss, 2) + + return image + +file=tf.io.read_file("/media/fangsixie/data/keras-yolo3/Yellow_Smiley_Face_Warp-cutout-20.png") +image=tf.io.decode_image(file) +result=autocontrast(image) +encoded=tf.image.encode_png(result) +tf.io.write_file('./test.png',encoded) + From 0ff2a0dd89bfc2ffc41f18df207d9546b5ff28ed Mon Sep 17 00:00:00 2001 From: fsx950223 Date: Fri, 20 Mar 2020 22:38:51 +0800 Subject: [PATCH 2/5] add constrast ops tests --- .../image/{contrast_op.py => contrast_ops.py} | 21 ++++-- tensorflow_addons/image/contrast_ops_test.py | 68 +++++++++++++++++++ 2 files changed, 83 insertions(+), 6 deletions(-) rename tensorflow_addons/image/{contrast_op.py => contrast_ops.py} (61%) create mode 100644 tensorflow_addons/image/contrast_ops_test.py diff --git a/tensorflow_addons/image/contrast_op.py b/tensorflow_addons/image/contrast_ops.py similarity index 61% rename from tensorflow_addons/image/contrast_op.py rename to tensorflow_addons/image/contrast_ops.py index 36dda0a793..b7af97c3a3 100644 --- a/tensorflow_addons/image/contrast_op.py +++ b/tensorflow_addons/image/contrast_ops.py @@ -1,3 +1,17 @@ +# Copyright 2020 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. +# ============================================================================== import tensorflow as tf def autocontrast(image): @@ -32,13 +46,8 @@ def scale_channel(image_channel): ss=tf.unstack(image,axis=-1) for i in range(len(ss)): ss[i]=scale_channel(ss[i]) - image = tf.stack(ss, 2) + image = tf.stack(ss, -1) return image -file=tf.io.read_file("/media/fangsixie/data/keras-yolo3/Yellow_Smiley_Face_Warp-cutout-20.png") -image=tf.io.decode_image(file) -result=autocontrast(image) -encoded=tf.image.encode_png(result) -tf.io.write_file('./test.png',encoded) diff --git a/tensorflow_addons/image/contrast_ops_test.py b/tensorflow_addons/image/contrast_ops_test.py new file mode 100644 index 0000000000..152f1fea0a --- /dev/null +++ b/tensorflow_addons/image/contrast_ops_test.py @@ -0,0 +1,68 @@ +# Copyright 2020 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. +# ============================================================================== +"""Tests for contrast ops.""" + +import sys + +import pytest +import tensorflow as tf +import numpy as np +from absl.testing import parameterized +from tensorflow_addons.image.contrast_ops import autocontrast +from tensorflow_addons.image.utils import from_4D_image, to_4D_image + + +@parameterized.named_parameters( + ("float16", np.float16), ("float32", np.float32), ("uint8", np.uint8) +) +def test_different_dtypes(dtype): + test_image = tf.ones([1, 40, 40, 3], dtype=dtype) + result_image = autocontrast(test_image) + np.testing.assert_allclose(result_image, test_image) + + +def test_different_channels(): + for channel in [0, 1, 3, 4]: + test_image = tf.ones([1, 40, 40, channel], dtype=np.uint8) + result_image = autocontrast(test_image) + np.testing.assert_allclose(result_image, test_image) + + +# def test_different_ranks(): +# test_image_4d = tf.ones([1, 40, 40, 1], dtype=np.uint8) +# cutout_area = tf.zeros([4, 4], dtype=np.uint8) +# cutout_area = tf.pad(cutout_area, ((0, 36), (0, 36)), constant_values=1) +# expect_image_4d = to_4D_image(cutout_area) + +# test_image_2d = from_4D_image(test_image_4d, 2) +# expect_image_2d = from_4D_image(expect_image_4d, 2) +# result_image_2d = random_cutout(test_image_2d, 20, seed=1234) +# np.testing.assert_allclose(tf.shape(result_image_2d), tf.shape(expect_image_2d)) + +# result_image_4d = random_cutout(test_image_4d, 20, seed=1234) +# np.testing.assert_allclose(tf.shape(result_image_4d), tf.shape(expect_image_4d)) + + +# def test_with_tf_function(): +# test_image = tf.ones([1, 40, 40, 1], dtype=tf.uint8) +# result_image = tf.function(cutout)(test_image, 2, [2, 2]) +# cutout_area = tf.zeros([4, 4], dtype=tf.uint8) +# cutout_area = tf.pad(cutout_area, ((0, 36), (0, 36)), constant_values=1) +# expect_image = to_4D_image(cutout_area) +# np.testing.assert_allclose(result_image, expect_image) + + +if __name__ == "__main__": + sys.exit(pytest.main([__file__])) \ No newline at end of file From 87cd60e1c4958b96d4ad6ba9c4514a4f8021f622 Mon Sep 17 00:00:00 2001 From: fsx950223 Date: Fri, 20 Mar 2020 22:43:12 +0800 Subject: [PATCH 3/5] format code --- tensorflow_addons/image/contrast_ops.py | 18 +++++++++--------- tensorflow_addons/image/contrast_ops_test.py | 2 +- 2 files changed, 10 insertions(+), 10 deletions(-) diff --git a/tensorflow_addons/image/contrast_ops.py b/tensorflow_addons/image/contrast_ops.py index b7af97c3a3..8dac69abfd 100644 --- a/tensorflow_addons/image/contrast_ops.py +++ b/tensorflow_addons/image/contrast_ops.py @@ -14,6 +14,7 @@ # ============================================================================== import tensorflow as tf + def autocontrast(image): """Implements Autocontrast function from PIL using TF ops. @@ -24,8 +25,9 @@ def autocontrast(image): The image after it has had autocontrast applied to it and will be of type uint8. """ - dtype=image.dtype - interval=dtype.max - dtype.min + dtype = image.dtype + interval = dtype.max - dtype.min + def scale_channel(image_channel): """Scale the 2D image using the autocontrast rule.""" # A possibly cheaper version can be done using cumsum/unique_with_counts @@ -35,19 +37,17 @@ def scale_channel(image_channel): hi = tf.reduce_max(image_channel) if hi > lo: - image_channel=tf.cast(image_channel,tf.float32) - image_channel=image_channel*(interval/(hi - lo)) - image_channel=tf.cast(image_channel, dtype) + image_channel = tf.cast(image_channel, tf.float32) + image_channel = image_channel * (interval / (hi - lo)) + image_channel = tf.cast(image_channel, dtype) return image_channel # Assumes RGB for now. Scales each channel independently # and then stacks the result. - ss=tf.unstack(image,axis=-1) + ss = tf.unstack(image, axis=-1) for i in range(len(ss)): - ss[i]=scale_channel(ss[i]) + ss[i] = scale_channel(ss[i]) image = tf.stack(ss, -1) return image - - diff --git a/tensorflow_addons/image/contrast_ops_test.py b/tensorflow_addons/image/contrast_ops_test.py index 152f1fea0a..e4570510b0 100644 --- a/tensorflow_addons/image/contrast_ops_test.py +++ b/tensorflow_addons/image/contrast_ops_test.py @@ -65,4 +65,4 @@ def test_different_channels(): if __name__ == "__main__": - sys.exit(pytest.main([__file__])) \ No newline at end of file + sys.exit(pytest.main([__file__])) From 9aa02c9e79387af6f25b017de42f9b021bde699d Mon Sep 17 00:00:00 2001 From: fsx950223 Date: Fri, 20 Mar 2020 23:12:24 +0800 Subject: [PATCH 4/5] add bazel build --- tensorflow_addons/image/BUILD | 13 ++++++++++ tensorflow_addons/image/__init__.py | 1 + tensorflow_addons/image/contrast_ops_test.py | 27 +------------------- 3 files changed, 15 insertions(+), 26 deletions(-) diff --git a/tensorflow_addons/image/BUILD b/tensorflow_addons/image/BUILD index a1a09d66bf..07b493b32f 100644 --- a/tensorflow_addons/image/BUILD +++ b/tensorflow_addons/image/BUILD @@ -18,6 +18,7 @@ py_library( "connected_components.py", "resampler_ops.py", "compose_ops.py", + "contrast_ops.py", ]), data = [ ":sparse_image_warp_test_data", @@ -177,3 +178,15 @@ py_test( ":image", ], ) + +py_test( + name = "contrast_ops_test", + size = "small", + srcs = [ + "contrast_ops_test.py", + ], + main = "contrast_ops_test.py", + deps = [ + ":image", + ], +) \ No newline at end of file diff --git a/tensorflow_addons/image/__init__.py b/tensorflow_addons/image/__init__.py index fbd5cda029..e8f81f5939 100644 --- a/tensorflow_addons/image/__init__.py +++ b/tensorflow_addons/image/__init__.py @@ -29,3 +29,4 @@ from tensorflow_addons.image.transform_ops import transform from tensorflow_addons.image.translate_ops import translate from tensorflow_addons.image.compose_ops import blend +from tensorflow_addons.image.contrast_ops import autocontrast diff --git a/tensorflow_addons/image/contrast_ops_test.py b/tensorflow_addons/image/contrast_ops_test.py index e4570510b0..914b86b811 100644 --- a/tensorflow_addons/image/contrast_ops_test.py +++ b/tensorflow_addons/image/contrast_ops_test.py @@ -21,7 +21,6 @@ import numpy as np from absl.testing import parameterized from tensorflow_addons.image.contrast_ops import autocontrast -from tensorflow_addons.image.utils import from_4D_image, to_4D_image @parameterized.named_parameters( @@ -34,35 +33,11 @@ def test_different_dtypes(dtype): def test_different_channels(): - for channel in [0, 1, 3, 4]: + for channel in [1, 3, 4]: test_image = tf.ones([1, 40, 40, channel], dtype=np.uint8) result_image = autocontrast(test_image) np.testing.assert_allclose(result_image, test_image) -# def test_different_ranks(): -# test_image_4d = tf.ones([1, 40, 40, 1], dtype=np.uint8) -# cutout_area = tf.zeros([4, 4], dtype=np.uint8) -# cutout_area = tf.pad(cutout_area, ((0, 36), (0, 36)), constant_values=1) -# expect_image_4d = to_4D_image(cutout_area) - -# test_image_2d = from_4D_image(test_image_4d, 2) -# expect_image_2d = from_4D_image(expect_image_4d, 2) -# result_image_2d = random_cutout(test_image_2d, 20, seed=1234) -# np.testing.assert_allclose(tf.shape(result_image_2d), tf.shape(expect_image_2d)) - -# result_image_4d = random_cutout(test_image_4d, 20, seed=1234) -# np.testing.assert_allclose(tf.shape(result_image_4d), tf.shape(expect_image_4d)) - - -# def test_with_tf_function(): -# test_image = tf.ones([1, 40, 40, 1], dtype=tf.uint8) -# result_image = tf.function(cutout)(test_image, 2, [2, 2]) -# cutout_area = tf.zeros([4, 4], dtype=tf.uint8) -# cutout_area = tf.pad(cutout_area, ((0, 36), (0, 36)), constant_values=1) -# expect_image = to_4D_image(cutout_area) -# np.testing.assert_allclose(result_image, expect_image) - - if __name__ == "__main__": sys.exit(pytest.main([__file__])) From f9e78d778fd1581c9138a823873360bd80d2e9f8 Mon Sep 17 00:00:00 2001 From: fsx950223 Date: Fri, 20 Mar 2020 23:26:06 +0800 Subject: [PATCH 5/5] add types --- tensorflow_addons/image/contrast_ops.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/tensorflow_addons/image/contrast_ops.py b/tensorflow_addons/image/contrast_ops.py index 8dac69abfd..4f075fe08b 100644 --- a/tensorflow_addons/image/contrast_ops.py +++ b/tensorflow_addons/image/contrast_ops.py @@ -13,9 +13,10 @@ # limitations under the License. # ============================================================================== import tensorflow as tf +from tensorflow_addons.utils.types import TensorLike -def autocontrast(image): +def autocontrast(image: TensorLike) -> tf.Tensor: """Implements Autocontrast function from PIL using TF ops. Args: