From 133a7eace158415d388a0d6b65c68ec5839e71a8 Mon Sep 17 00:00:00 2001 From: jxnior01 Date: Fri, 16 Jun 2023 11:40:50 +0200 Subject: [PATCH 1/8] added method + test to convert image to grayscale --- src/safeds/data/image/containers/_image.py | 17 +++++++++++++++++ .../safeds/data/image/containers/test_image.py | 13 +++++++++++++ 2 files changed, 30 insertions(+) diff --git a/src/safeds/data/image/containers/_image.py b/src/safeds/data/image/containers/_image.py index d122d06c8..27d33936e 100644 --- a/src/safeds/data/image/containers/_image.py +++ b/src/safeds/data/image/containers/_image.py @@ -176,3 +176,20 @@ def resize(self, new_width: int, new_height: int) -> Image: new_image = Image(data, self._format) new_image._image = new_image._image.resize((new_width, new_height)) return new_image + + def convert_to_grayscale(self) -> Image: + """ + Convert the image to grayscale. + + Returns + ------- + grayscale_image : Image + The grayscale image. + """ + data = io.BytesIO() + grayscale_image = self._image.convert("L") + grayscale_image.save(data, format=self._format.value) + return Image(data, self._format) + + + diff --git a/tests/safeds/data/image/containers/test_image.py b/tests/safeds/data/image/containers/test_image.py index e4b0a87c9..1a6d41da4 100644 --- a/tests/safeds/data/image/containers/test_image.py +++ b/tests/safeds/data/image/containers/test_image.py @@ -181,3 +181,16 @@ def test_should_return_resized_image( new_size: tuple[int, int], ) -> None: assert image.resize(new_width, new_height)._image.size == new_size + + +class TestConvertToGrayscale: + @pytest.mark.parametrize( + "image", + [ + (Image.from_png_file(resolve_resource_path("image/snapshot_heatmap.png"))) + ], + ids=["grayscale"], + ) + def test_convert_to_grayscale(self, image: Image) -> None: + grayscale_image = image.convert_to_grayscale() + assert grayscale_image._image.mode == "L" From b916bf40fb3061f21fd077bb4eecf5f3fe54cff4 Mon Sep 17 00:00:00 2001 From: jxnior01 Date: Fri, 16 Jun 2023 14:13:49 +0200 Subject: [PATCH 2/8] modified grayscale_test and added resulting image --- .../image/snapshot_heatmap_grayscale.png | Bin 0 -> 11217 bytes .../safeds/data/image/containers/test_image.py | 11 +++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) create mode 100644 tests/resources/image/snapshot_heatmap_grayscale.png diff --git a/tests/resources/image/snapshot_heatmap_grayscale.png b/tests/resources/image/snapshot_heatmap_grayscale.png new file mode 100644 index 0000000000000000000000000000000000000000..ca7f451c0019b372982c63e43d1d0a00e9de62ba GIT binary patch literal 11217 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 tSq;b0?1zEyl^QC|r4jYk@=0E|5+Q=~ None: + def test_convert_to_grayscale(self, image: Image, expected: Image) -> None: grayscale_image = image.convert_to_grayscale() - assert grayscale_image._image.mode == "L" + assert grayscale_image._image.tobytes() == expected._image.tobytes() + + From 1efa7e52be31c38322de49f8cf19976a67473434 Mon Sep 17 00:00:00 2001 From: jxnior01 Date: Fri, 16 Jun 2023 14:44:52 +0200 Subject: [PATCH 3/8] resolving conflicts --- src/safeds/data/image/containers/_image.py | 15 +++++++++++++++ tests/safeds/data/image/containers/test_image.py | 14 ++++++++++++++ 2 files changed, 29 insertions(+) diff --git a/src/safeds/data/image/containers/_image.py b/src/safeds/data/image/containers/_image.py index 2c3659859..05848d963 100644 --- a/src/safeds/data/image/containers/_image.py +++ b/src/safeds/data/image/containers/_image.py @@ -221,6 +221,20 @@ def resize(self, new_width: int, new_height: int) -> Image: new_image._image = new_image._image.resize((new_width, new_height)) return new_image + def convert_to_grayscale(self) -> Image: + """ + Convert the image to grayscale. + + Returns + ------- + grayscale_image : Image + The grayscale image. + """ + data = io.BytesIO() + grayscale_image = self._image.convert("L") + grayscale_image.save(data, format=self._format.value) + return Image(data, self._format) + def flip_vertically(self) -> Image: """ Flip the image vertically (horizontal axis, flips up-down and vice versa). @@ -246,3 +260,4 @@ def flip_horizontally(self) -> Image: imagecopy = copy.deepcopy(self) imagecopy._image = self._image.transpose(PIL.Image.FLIP_LEFT_RIGHT) return imagecopy + diff --git a/tests/safeds/data/image/containers/test_image.py b/tests/safeds/data/image/containers/test_image.py index 0b8e09bd6..a95d2db5a 100644 --- a/tests/safeds/data/image/containers/test_image.py +++ b/tests/safeds/data/image/containers/test_image.py @@ -206,6 +206,20 @@ def test_should_return_resized_image( assert image.resize(new_width, new_height)._image.size == new_size +class TestConvertToGrayscale: + @pytest.mark.parametrize( + ("image", "expected"), + [ + (Image.from_png_file(resolve_resource_path("image/snapshot_heatmap.png")), + Image.from_png_file(resolve_resource_path("image/snapshot_heatmap_grayscale.png"))), + ], + ids=["grayscale"], + ) + def test_convert_to_grayscale(self, image: Image, expected: Image) -> None: + grayscale_image = image.convert_to_grayscale() + assert grayscale_image._image.tobytes() == expected._image.tobytes() + + class TestEQ: def test_should_be_equal(self) -> None: image = Image.from_png_file(resolve_resource_path("image/original.png")) From 59f206b2ff0ff50a1f1ae9fa35f595b5f8e91518 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Fri, 16 Jun 2023 12:47:46 +0000 Subject: [PATCH 4/8] style: apply automated linter fixes --- src/safeds/data/image/containers/_image.py | 1 - tests/safeds/data/image/containers/test_image.py | 6 ++++-- 2 files changed, 4 insertions(+), 3 deletions(-) diff --git a/src/safeds/data/image/containers/_image.py b/src/safeds/data/image/containers/_image.py index 05848d963..714269359 100644 --- a/src/safeds/data/image/containers/_image.py +++ b/src/safeds/data/image/containers/_image.py @@ -260,4 +260,3 @@ def flip_horizontally(self) -> Image: imagecopy = copy.deepcopy(self) imagecopy._image = self._image.transpose(PIL.Image.FLIP_LEFT_RIGHT) return imagecopy - diff --git a/tests/safeds/data/image/containers/test_image.py b/tests/safeds/data/image/containers/test_image.py index a95d2db5a..dba8cee54 100644 --- a/tests/safeds/data/image/containers/test_image.py +++ b/tests/safeds/data/image/containers/test_image.py @@ -210,8 +210,10 @@ class TestConvertToGrayscale: @pytest.mark.parametrize( ("image", "expected"), [ - (Image.from_png_file(resolve_resource_path("image/snapshot_heatmap.png")), - Image.from_png_file(resolve_resource_path("image/snapshot_heatmap_grayscale.png"))), + ( + Image.from_png_file(resolve_resource_path("image/snapshot_heatmap.png")), + Image.from_png_file(resolve_resource_path("image/snapshot_heatmap_grayscale.png")), + ), ], ids=["grayscale"], ) From 8aa7e12ed1efdad414fb554bc20290b9f730c470 Mon Sep 17 00:00:00 2001 From: jxnior01 Date: Fri, 16 Jun 2023 15:13:18 +0200 Subject: [PATCH 5/8] code-cov down, maybe new commit needed --- tests/safeds/data/image/containers/test_image.py | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/safeds/data/image/containers/test_image.py b/tests/safeds/data/image/containers/test_image.py index dba8cee54..d0e3862f7 100644 --- a/tests/safeds/data/image/containers/test_image.py +++ b/tests/safeds/data/image/containers/test_image.py @@ -216,6 +216,7 @@ class TestConvertToGrayscale: ), ], ids=["grayscale"], + ) def test_convert_to_grayscale(self, image: Image, expected: Image) -> None: grayscale_image = image.convert_to_grayscale() From bf29b00c98211aa593c55d9a9402410679dedd91 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:15:07 +0000 Subject: [PATCH 6/8] style: apply automated linter fixes --- tests/safeds/data/image/containers/test_image.py | 1 - 1 file changed, 1 deletion(-) diff --git a/tests/safeds/data/image/containers/test_image.py b/tests/safeds/data/image/containers/test_image.py index d0e3862f7..dba8cee54 100644 --- a/tests/safeds/data/image/containers/test_image.py +++ b/tests/safeds/data/image/containers/test_image.py @@ -216,7 +216,6 @@ class TestConvertToGrayscale: ), ], ids=["grayscale"], - ) def test_convert_to_grayscale(self, image: Image, expected: Image) -> None: grayscale_image = image.convert_to_grayscale() From a493f517107a060d7dca93dbbacaa7f0e9b56e6e Mon Sep 17 00:00:00 2001 From: jxnior01 Date: Fri, 16 Jun 2023 15:31:54 +0200 Subject: [PATCH 7/8] code-cov 100% --- src/safeds/data/image/containers/_image.py | 1 - 1 file changed, 1 deletion(-) diff --git a/src/safeds/data/image/containers/_image.py b/src/safeds/data/image/containers/_image.py index 714269359..2237e926e 100644 --- a/src/safeds/data/image/containers/_image.py +++ b/src/safeds/data/image/containers/_image.py @@ -195,7 +195,6 @@ def _repr_png_(self) -> bytes | None: self._image.save(buffer, format="png") buffer.seek(0) return buffer.read() - # ------------------------------------------------------------------------------------------------------------------ # Transformations # ------------------------------------------------------------------------------------------------------------------ From 515a4a0fb9f020685c7a96c16b2b4b8bc3ca8968 Mon Sep 17 00:00:00 2001 From: megalinter-bot <129584137+megalinter-bot@users.noreply.github.com> Date: Fri, 16 Jun 2023 13:35:44 +0000 Subject: [PATCH 8/8] style: apply automated linter fixes --- src/safeds/data/image/containers/_image.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/safeds/data/image/containers/_image.py b/src/safeds/data/image/containers/_image.py index 9312139dc..41309159e 100644 --- a/src/safeds/data/image/containers/_image.py +++ b/src/safeds/data/image/containers/_image.py @@ -196,6 +196,7 @@ def _repr_png_(self) -> bytes | None: self._image.save(buffer, format="png") buffer.seek(0) return buffer.read() + # ------------------------------------------------------------------------------------------------------------------ # Transformations # ------------------------------------------------------------------------------------------------------------------ @@ -234,7 +235,7 @@ def convert_to_grayscale(self) -> Image: grayscale_image = self._image.convert("L") grayscale_image.save(data, format=self._format.value) return Image(data, self._format) - + def crop(self, x: int, y: int, width: int, height: int) -> Image: """ Return an image that has been cropped to a given bounding rectangle.