diff --git a/src/safeds/data/image/containers/_image.py b/src/safeds/data/image/containers/_image.py index 0a15b1dd9..763fbcb82 100644 --- a/src/safeds/data/image/containers/_image.py +++ b/src/safeds/data/image/containers/_image.py @@ -15,10 +15,6 @@ if TYPE_CHECKING: from torch.types import Device import torchvision - -# Disables torchvision V2 beta warnings -# Disabled because of RUFF Linter E402 (Module level import not at top of file) -# torchvision.disable_beta_transforms_warning() from torchvision.transforms.v2 import PILToTensor from torchvision.transforms.v2 import functional as func2 from torchvision.utils import save_image @@ -434,6 +430,38 @@ def adjust_contrast(self, factor: float) -> Image: else: return Image(func2.adjust_contrast(self._image_tensor, factor * 1.0), device=self.device) + def adjust_color_balance(self, factor: float) -> Image: + """ + Return a new `Image` with adjusted color balance. + + The original image is not modified. + + Parameters + ---------- + factor: float + Has to be bigger than or equal to 0. + If 0 <= factor < 1, make image greyer. + If factor = 1, no changes will be made. + If factor > 1, increase color balance of image. + + Returns + ------- + image: Image + The new, adjusted image. + """ + if factor < 0: + raise OutOfBoundsError(factor, name="factor", lower_bound=ClosedBound(0)) + elif factor == 1: + warnings.warn( + "Color adjustment factor is 1.0, this will not make changes to the image.", + UserWarning, + stacklevel=2, + ) + return Image( + self.convert_to_grayscale()._image_tensor * (1.0 - factor * 1.0) + self._image_tensor * (factor * 1.0), + device=self.device, + ) + def blur(self, radius: int) -> Image: """ Return a blurred version of the image. @@ -498,7 +526,7 @@ def sharpen(self, factor: float) -> Image: def invert_colors(self) -> Image: """ - Return a new image with colors inverted. + Return a new `Image` with colors inverted. The original image is not modified. diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-add color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-add color-cpu].png new file mode 100644 index 000000000..ebf7c5444 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-add color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-add color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-add color-cuda].png new file mode 100644 index 000000000..ebf7c5444 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-add color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-gray-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-gray-cpu].png new file mode 100644 index 000000000..60357e934 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-gray-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-gray-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-gray-cuda].png new file mode 100644 index 000000000..60357e934 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-gray-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-remove color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-remove color-cpu].png new file mode 100644 index 000000000..fd0f65f87 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-remove color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-remove color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-remove color-cuda].png new file mode 100644 index 000000000..fd0f65f87 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-plane-remove color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-add color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-add color-cpu].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-add color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-add color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-add color-cuda].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-add color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-gray-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-gray-cpu].png new file mode 100644 index 000000000..b9028365b Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-gray-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-gray-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-gray-cuda].png new file mode 100644 index 000000000..b9028365b Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-gray-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-remove color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-remove color-cpu].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-remove color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-remove color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-remove color-cuda].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-jpg-white_square-remove color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-add color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-add color-cpu].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-add color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-add color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-add color-cuda].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-add color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-gray-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-gray-cpu].png new file mode 100644 index 000000000..b9028365b Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-gray-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-gray-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-gray-cuda].png new file mode 100644 index 000000000..b9028365b Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-gray-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-remove color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-remove color-cpu].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-remove color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-remove color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-remove color-cuda].png new file mode 100644 index 000000000..94381b429 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-3-channel-png-white_square-remove color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-add color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-add color-cpu].png new file mode 100644 index 000000000..e5d91c818 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-add color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-add color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-add color-cuda].png new file mode 100644 index 000000000..e5d91c818 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-add color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-gray-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-gray-cpu].png new file mode 100644 index 000000000..e1135e9bd Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-gray-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-gray-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-gray-cuda].png new file mode 100644 index 000000000..e1135e9bd Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-gray-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-remove color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-remove color-cpu].png new file mode 100644 index 000000000..99168d9f7 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-remove color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-remove color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-remove color-cuda].png new file mode 100644 index 000000000..99168d9f7 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[opaque-4-channel-png-plane-remove color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-add color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-add color-cpu].png new file mode 100644 index 000000000..6da78e96e Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-add color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-add color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-add color-cuda].png new file mode 100644 index 000000000..6da78e96e Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-add color-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-gray-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-gray-cpu].png new file mode 100644 index 000000000..e8c3bef99 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-gray-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-gray-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-gray-cuda].png new file mode 100644 index 000000000..e8c3bef99 Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-gray-cuda].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-remove color-cpu].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-remove color-cpu].png new file mode 100644 index 000000000..5d847799e Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-remove color-cpu].png differ diff --git a/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-remove color-cuda].png b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-remove color-cuda].png new file mode 100644 index 000000000..5d847799e Binary files /dev/null and b/tests/safeds/data/image/containers/__snapshots__/test_image/TestAdjustColor.test_should_adjust_colors[transparent-4-channel-png-rgba-remove color-cuda].png differ diff --git a/tests/safeds/data/image/containers/test_image.py b/tests/safeds/data/image/containers/test_image.py index 3becd8228..1c4231fb3 100644 --- a/tests/safeds/data/image/containers/test_image.py +++ b/tests/safeds/data/image/containers/test_image.py @@ -614,6 +614,53 @@ def test_should_raise_negative_contrast(self, resource_path: str, device: Device Image.from_file(resolve_resource_path(resource_path), device).adjust_contrast(-1.0) +@pytest.mark.parametrize("device", _test_devices(), ids=_test_devices_ids()) +class TestAdjustColor: + @pytest.mark.parametrize("factor", [2, 0.5, 0], ids=["add color", "remove color", "gray"]) + @pytest.mark.parametrize( + "resource_path", + _test_images_all(), + ids=_test_images_all_ids(), + ) + def test_should_adjust_colors( + self, + factor: float, + resource_path: str, + snapshot_png: SnapshotAssertion, + device: Device, + ) -> None: + _skip_if_device_not_available(device) + image = Image.from_file(resolve_resource_path(resource_path), device) + image_adjusted_color_balance = image.adjust_color_balance(factor) + assert image != image_adjusted_color_balance + assert image_adjusted_color_balance == snapshot_png + + @pytest.mark.parametrize( + "resource_path", + _test_images_all(), + ids=_test_images_all_ids(), + ) + def test_should_not_adjust_colors(self, resource_path: str, device: Device) -> None: + _skip_if_device_not_available(device) + with pytest.warns( + UserWarning, + match="Color adjustment factor is 1.0, this will not make changes to the image.", + ): + image = Image.from_file(resolve_resource_path(resource_path), device) + image_adjusted_color_balance = image.adjust_color_balance(1) + assert image == image_adjusted_color_balance + + @pytest.mark.parametrize( + "resource_path", + _test_images_all(), + ids=_test_images_all_ids(), + ) + def test_should_raise_negative_color_adjust(self, resource_path: str, device: Device) -> None: + _skip_if_device_not_available(device) + with pytest.raises(OutOfBoundsError, match=r"factor \(=-1.0\) is not inside \[0, \u221e\)."): + Image.from_file(resolve_resource_path(resource_path), device).adjust_color_balance(-1.0) + + @pytest.mark.parametrize("device", _test_devices(), ids=_test_devices_ids()) class TestBlur: @pytest.mark.parametrize(