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

feat: adjust brightness and contrast of image #368

Merged
merged 24 commits into from
Jun 16, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
a1c044d
in progress
patrikguempel Jun 16, 2023
cad81bc
added file
patrikguempel Jun 16, 2023
862e264
added brighten feature
patrikguempel Jun 16, 2023
dab8650
added adjust_contrast function
daniaHu Jun 16, 2023
4f943a7
added brighten/contrast feature
patrikguempel Jun 16, 2023
db14b5c
Merge branch 'main' of https://github.com/Safe-DS/Stdlib into 289-adj…
patrikguempel Jun 16, 2023
4f9c38b
Merge branch 'main' of https://github.com/Safe-DS/Stdlib into 289-adj…
patrikguempel Jun 16, 2023
9fb280e
Merge branch 'main' of https://github.com/Safe-DS/Stdlib into 289-adj…
patrikguempel Jun 16, 2023
096e72a
Merge remote-tracking branch 'origin/289-adjust-brightness-and-contra…
patrikguempel Jun 16, 2023
f341fb2
style: apply automated linter fixes
megalinter-bot Jun 16, 2023
acb251e
provided further error handling
patrikguempel Jun 16, 2023
c9fbe48
Merge remote-tracking branch 'origin/289-adjust-brightness-and-contra…
patrikguempel Jun 16, 2023
290f432
Merge branch 'main' of https://github.com/Safe-DS/Stdlib into 289-adj…
patrikguempel Jun 16, 2023
e3b1894
Merge branch 'main' of https://github.com/Safe-DS/Stdlib into 289-adj…
patrikguempel Jun 16, 2023
63f64b9
Merge branch 'main' of https://github.com/Safe-DS/Stdlib into 289-adj…
patrikguempel Jun 16, 2023
2eb20c0
Merge remote-tracking branch 'origin/289-adjust-brightness-and-contra…
patrikguempel Jun 16, 2023
1f2aa64
style: apply automated linter fixes
megalinter-bot Jun 16, 2023
94dc2e5
Merge branch 'main' of https://github.com/Safe-DS/Stdlib into 289-adj…
patrikguempel Jun 16, 2023
7697be4
Merge remote-tracking branch 'origin/289-adjust-brightness-and-contra…
patrikguempel Jun 16, 2023
801379d
style: apply automated linter fixes
megalinter-bot Jun 16, 2023
56dcc34
Merge remote-tracking branch 'origin/289-adjust-brightness-and-contra…
patrikguempel Jun 16, 2023
8fc0c24
Merge remote-tracking branch 'origin/289-adjust-brightness-and-contra…
patrikguempel Jun 16, 2023
67766e7
style: apply automated linter fixes
megalinter-bot Jun 16, 2023
4e0fdf2
Merge branch 'main' into 289-adjust-brightness-and-contrast-of-image
PhilipGutberlet Jun 16, 2023
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
73 changes: 67 additions & 6 deletions src/safeds/data/image/containers/_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

import copy
import io
import warnings
from pathlib import Path
from typing import Any, BinaryIO

Expand Down Expand Up @@ -273,9 +274,9 @@ def flip_vertically(self) -> Image:
result : Image
The flipped image.
"""
imagecopy = copy.deepcopy(self)
imagecopy._image = self._image.transpose(PIL.Image.FLIP_TOP_BOTTOM)
return imagecopy
image_copy = copy.deepcopy(self)
image_copy._image = self._image.transpose(PIL.Image.FLIP_TOP_BOTTOM)
return image_copy

def flip_horizontally(self) -> Image:
"""
Expand All @@ -286,9 +287,69 @@ def flip_horizontally(self) -> Image:
result : Image
The flipped image.
"""
imagecopy = copy.deepcopy(self)
imagecopy._image = self._image.transpose(PIL.Image.FLIP_LEFT_RIGHT)
return imagecopy
image_copy = copy.deepcopy(self)
image_copy._image = self._image.transpose(PIL.Image.FLIP_LEFT_RIGHT)
return image_copy

def adjust_brightness(self, factor: float) -> Image:
"""
Adjust the brightness of an image.

Parameters
----------
factor: float
The brightness factor.
1.0 will not change the brightness.
Below 1.0 will result in a darker image.
Above 1.0 will resolut in a brighter image.
Has to be bigger than or equal to 0 (black).

Returns
-------
result: Image
The Image with adjusted brightness.
"""
if factor < 0:
raise ValueError("Brightness factor has to be 0 or bigger")
elif factor == 1:
warnings.warn(
"Brightness adjustment factor is 1.0, this will not make changes to the image.",
UserWarning,
stacklevel=2,
)

image_copy = copy.deepcopy(self)
image_copy._image = ImageEnhance.Brightness(image_copy._image).enhance(factor)
return image_copy

def adjust_contrast(self, factor: float) -> Image:
"""
Adjust Contrast of image.

Parameters
----------
factor: float
If factor > 1, increase contrast of image.
If factor = 1, no changes will be made.
If factor < 1, make image greyer.
Has to be bigger than or equal to 0 (gray).

Returns
-------
New image with adjusted contrast.
"""
if factor < 0:
raise ValueError("Contrast factor has to be 0 or bigger")
elif factor == 1:
warnings.warn(
"Contrast adjustment factor is 1.0, this will not make changes to the image.",
UserWarning,
stacklevel=2,
)

image_copy = copy.deepcopy(self)
image_copy._image = ImageEnhance.Contrast(image_copy._image).enhance(factor)
return image_copy

def blur(self, radius: int = 1) -> Image:
"""
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
64 changes: 58 additions & 6 deletions tests/safeds/data/image/containers/test_image.py
Original file line number Diff line number Diff line change
Expand Up @@ -242,9 +242,10 @@ def test_should_raise(self) -> None:
class TestFlipVertically:
def test_should_flip_vertically(self) -> None:
image = Image.from_png_file(resolve_resource_path("image/original.png"))
image = image.flip_vertically()
image2 = Image.from_png_file(resolve_resource_path("image/flip_vertically.png"))
assert image == image2
image2 = image.flip_vertically()
image3 = Image.from_png_file(resolve_resource_path("image/flip_vertically.png"))
assert image != image2
assert image2 == image3

def test_should_be_original(self) -> None:
image = Image.from_png_file(resolve_resource_path("image/original.png"))
Expand All @@ -255,16 +256,67 @@ def test_should_be_original(self) -> None:
class TestFlipHorizontally:
def test_should_flip_horizontally(self) -> None:
image = Image.from_png_file(resolve_resource_path("image/original.png"))
image = image.flip_horizontally()
image2 = Image.from_png_file(resolve_resource_path("image/flip_horizontally.png"))
assert image == image2
image2 = image.flip_horizontally()
image3 = Image.from_png_file(resolve_resource_path("image/flip_horizontally.png"))
assert image != image2
assert image2 == image3

def test_should_be_original(self) -> None:
image = Image.from_png_file(resolve_resource_path("image/original.png"))
image2 = image.flip_horizontally().flip_horizontally()
assert image == image2


class TestAdjustContrast:
@pytest.mark.parametrize("factor", [0.75, 5])
def test_should_adjust_contrast(self, factor: float) -> None:
image = Image.from_png_file(resolve_resource_path("image/contrast/to_adjust_contrast.png"))
image2 = image.adjust_contrast(factor)
image3 = Image.from_png_file(
resolve_resource_path("image/contrast/contrast_adjusted_by_" + str(factor) + ".png"),
)
assert image != image2
assert image2 == image3

def test_should_not_adjust_contrast(self) -> None:
with pytest.warns(
UserWarning,
match="Contrast adjustment factor is 1.0, this will not make changes to the image.",
):
image = Image.from_png_file(resolve_resource_path("image/contrast/to_adjust_contrast.png"))
image2 = image.adjust_contrast(1)
assert image == image2

def test_should_raise(self) -> None:
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
with pytest.raises(ValueError, match="Contrast factor has to be 0 or bigger"):
image.adjust_contrast(-1)


class TestBrightness:
@pytest.mark.parametrize("factor", [0.5, 10])
def test_should_adjust_brightness(self, factor: float) -> None:
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
image2 = image.adjust_brightness(factor)
image3 = Image.from_png_file(resolve_resource_path("image/brightness/brightened_by_" + str(factor) + ".png"))
assert image != image2
assert image2 == image3

def test_should_not_brighten(self) -> None:
with pytest.warns(
UserWarning,
match="Brightness adjustment factor is 1.0, this will not make changes to the image.",
):
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
image2 = image.adjust_brightness(1)
assert image == image2

def test_should_raise(self) -> None:
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
with pytest.raises(ValueError, match="Brightness factor has to be 0 or bigger"):
image.adjust_brightness(-1)


class TestInvertColors:
def test_should_invert_colors_png(self) -> None:
image = Image.from_png_file(resolve_resource_path("image/original.png"))
Expand Down