Skip to content

Commit 1752feb

Browse files
patrikguempeldaniaHumegalinter-botPhilipGutberlet
authored
feat: adjust brightness and contrast of image (#368)
Closes #289, #291. ### Summary of Changes Added features for adjusting both brightness and contrast Co-authored-by: daniaHu <[email protected]> --------- Co-authored-by: daniaHu <[email protected]> Co-authored-by: megalinter-bot <[email protected]> Co-authored-by: Philip Gutberlet <[email protected]>
1 parent 3444700 commit 1752feb

File tree

8 files changed

+125
-12
lines changed

8 files changed

+125
-12
lines changed

src/safeds/data/image/containers/_image.py

+67-6
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
import copy
44
import io
5+
import warnings
56
from pathlib import Path
67
from typing import Any, BinaryIO
78

@@ -273,9 +274,9 @@ def flip_vertically(self) -> Image:
273274
result : Image
274275
The flipped image.
275276
"""
276-
imagecopy = copy.deepcopy(self)
277-
imagecopy._image = self._image.transpose(PIL.Image.FLIP_TOP_BOTTOM)
278-
return imagecopy
277+
image_copy = copy.deepcopy(self)
278+
image_copy._image = self._image.transpose(PIL.Image.FLIP_TOP_BOTTOM)
279+
return image_copy
279280

280281
def flip_horizontally(self) -> Image:
281282
"""
@@ -286,9 +287,69 @@ def flip_horizontally(self) -> Image:
286287
result : Image
287288
The flipped image.
288289
"""
289-
imagecopy = copy.deepcopy(self)
290-
imagecopy._image = self._image.transpose(PIL.Image.FLIP_LEFT_RIGHT)
291-
return imagecopy
290+
image_copy = copy.deepcopy(self)
291+
image_copy._image = self._image.transpose(PIL.Image.FLIP_LEFT_RIGHT)
292+
return image_copy
293+
294+
def adjust_brightness(self, factor: float) -> Image:
295+
"""
296+
Adjust the brightness of an image.
297+
298+
Parameters
299+
----------
300+
factor: float
301+
The brightness factor.
302+
1.0 will not change the brightness.
303+
Below 1.0 will result in a darker image.
304+
Above 1.0 will resolut in a brighter image.
305+
Has to be bigger than or equal to 0 (black).
306+
307+
Returns
308+
-------
309+
result: Image
310+
The Image with adjusted brightness.
311+
"""
312+
if factor < 0:
313+
raise ValueError("Brightness factor has to be 0 or bigger")
314+
elif factor == 1:
315+
warnings.warn(
316+
"Brightness adjustment factor is 1.0, this will not make changes to the image.",
317+
UserWarning,
318+
stacklevel=2,
319+
)
320+
321+
image_copy = copy.deepcopy(self)
322+
image_copy._image = ImageEnhance.Brightness(image_copy._image).enhance(factor)
323+
return image_copy
324+
325+
def adjust_contrast(self, factor: float) -> Image:
326+
"""
327+
Adjust Contrast of image.
328+
329+
Parameters
330+
----------
331+
factor: float
332+
If factor > 1, increase contrast of image.
333+
If factor = 1, no changes will be made.
334+
If factor < 1, make image greyer.
335+
Has to be bigger than or equal to 0 (gray).
336+
337+
Returns
338+
-------
339+
New image with adjusted contrast.
340+
"""
341+
if factor < 0:
342+
raise ValueError("Contrast factor has to be 0 or bigger")
343+
elif factor == 1:
344+
warnings.warn(
345+
"Contrast adjustment factor is 1.0, this will not make changes to the image.",
346+
UserWarning,
347+
stacklevel=2,
348+
)
349+
350+
image_copy = copy.deepcopy(self)
351+
image_copy._image = ImageEnhance.Contrast(image_copy._image).enhance(factor)
352+
return image_copy
292353

293354
def blur(self, radius: int = 1) -> Image:
294355
"""
Loading
Loading
Loading
Loading
Loading
Loading

tests/safeds/data/image/containers/test_image.py

+58-6
Original file line numberDiff line numberDiff line change
@@ -242,9 +242,10 @@ def test_should_raise(self) -> None:
242242
class TestFlipVertically:
243243
def test_should_flip_vertically(self) -> None:
244244
image = Image.from_png_file(resolve_resource_path("image/original.png"))
245-
image = image.flip_vertically()
246-
image2 = Image.from_png_file(resolve_resource_path("image/flip_vertically.png"))
247-
assert image == image2
245+
image2 = image.flip_vertically()
246+
image3 = Image.from_png_file(resolve_resource_path("image/flip_vertically.png"))
247+
assert image != image2
248+
assert image2 == image3
248249

249250
def test_should_be_original(self) -> None:
250251
image = Image.from_png_file(resolve_resource_path("image/original.png"))
@@ -255,16 +256,67 @@ def test_should_be_original(self) -> None:
255256
class TestFlipHorizontally:
256257
def test_should_flip_horizontally(self) -> None:
257258
image = Image.from_png_file(resolve_resource_path("image/original.png"))
258-
image = image.flip_horizontally()
259-
image2 = Image.from_png_file(resolve_resource_path("image/flip_horizontally.png"))
260-
assert image == image2
259+
image2 = image.flip_horizontally()
260+
image3 = Image.from_png_file(resolve_resource_path("image/flip_horizontally.png"))
261+
assert image != image2
262+
assert image2 == image3
261263

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

267269

270+
class TestAdjustContrast:
271+
@pytest.mark.parametrize("factor", [0.75, 5])
272+
def test_should_adjust_contrast(self, factor: float) -> None:
273+
image = Image.from_png_file(resolve_resource_path("image/contrast/to_adjust_contrast.png"))
274+
image2 = image.adjust_contrast(factor)
275+
image3 = Image.from_png_file(
276+
resolve_resource_path("image/contrast/contrast_adjusted_by_" + str(factor) + ".png"),
277+
)
278+
assert image != image2
279+
assert image2 == image3
280+
281+
def test_should_not_adjust_contrast(self) -> None:
282+
with pytest.warns(
283+
UserWarning,
284+
match="Contrast adjustment factor is 1.0, this will not make changes to the image.",
285+
):
286+
image = Image.from_png_file(resolve_resource_path("image/contrast/to_adjust_contrast.png"))
287+
image2 = image.adjust_contrast(1)
288+
assert image == image2
289+
290+
def test_should_raise(self) -> None:
291+
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
292+
with pytest.raises(ValueError, match="Contrast factor has to be 0 or bigger"):
293+
image.adjust_contrast(-1)
294+
295+
296+
class TestBrightness:
297+
@pytest.mark.parametrize("factor", [0.5, 10])
298+
def test_should_adjust_brightness(self, factor: float) -> None:
299+
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
300+
image2 = image.adjust_brightness(factor)
301+
image3 = Image.from_png_file(resolve_resource_path("image/brightness/brightened_by_" + str(factor) + ".png"))
302+
assert image != image2
303+
assert image2 == image3
304+
305+
def test_should_not_brighten(self) -> None:
306+
with pytest.warns(
307+
UserWarning,
308+
match="Brightness adjustment factor is 1.0, this will not make changes to the image.",
309+
):
310+
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
311+
image2 = image.adjust_brightness(1)
312+
assert image == image2
313+
314+
def test_should_raise(self) -> None:
315+
image = Image.from_png_file(resolve_resource_path("image/brightness/to_brighten.png"))
316+
with pytest.raises(ValueError, match="Brightness factor has to be 0 or bigger"):
317+
image.adjust_brightness(-1)
318+
319+
268320
class TestInvertColors:
269321
def test_should_invert_colors_png(self) -> None:
270322
image = Image.from_png_file(resolve_resource_path("image/original.png"))

0 commit comments

Comments
 (0)