From 897c280064f0986b7e43762dab9c7aa280da62cc Mon Sep 17 00:00:00 2001 From: Roy Smart Date: Wed, 15 Nov 2023 23:30:41 -0700 Subject: [PATCH] Added `colorsynth.xyY_from_XYZ_cie()` and `colorsynth.XYZ_from_xyY_cie()` functions. --- colorsynth/_colorsynth.py | 46 ++++++++++++++++++++++++++++ colorsynth/_tests/test_colorsynth.py | 36 +++++++++++++++++----- 2 files changed, 75 insertions(+), 7 deletions(-) diff --git a/colorsynth/_colorsynth.py b/colorsynth/_colorsynth.py index 88da2d6..358f4c9 100644 --- a/colorsynth/_colorsynth.py +++ b/colorsynth/_colorsynth.py @@ -9,6 +9,8 @@ "color_matching_z", "color_matching_xyz", "cie_1931_tristimulus", + "xyY_from_XYZ_cie", + "XYZ_from_xyY_cie", "srgb", ] @@ -322,6 +324,50 @@ def cie_1931_tristimulus( return result +def xyY_from_XYZ_cie( + XYZ: np.ndarray, + axis: int = -1, +) -> np.ndarray: + """ + Convert from a CIE :math:`XYZ` color space to a :math:`xyY` color space + + Parameters + ---------- + XYZ + color values in a CIE :math:`XYZ` color space to be converted + axis + logical axis along which the :math:`XYZ` values are distributed + """ + XYZ_sum = XYZ.sum(axis) + X, Y, Z = np.moveaxis(XYZ, source=axis, destination=0) + x = X / XYZ_sum + y = Y / XYZ_sum + result = np.stack([x, y, Y], axis=axis) + return result + + +def XYZ_from_xyY_cie( + xyY: np.ndarray, + axis: int = -1, +) -> np.ndarray: + """ + Convert from a CIE :math:`xyY` color space to a :math:`XYZ` color space + + Parameters + ---------- + xyY + color values in a CIE :math:`xyY` color space to be converted + axis + logical axis along which the :math:`xyY` values are distributed + """ + x, y, Y = np.moveaxis(xyY, source=axis, destination=0) + r = Y / y + X = r * x + Z = r * (1 - x - y) + result = np.stack([X, Y, Z], axis=axis) + return result + + def srgb( tristimulus: np.ndarray, axis: int = -1, diff --git a/colorsynth/_tests/test_colorsynth.py b/colorsynth/_tests/test_colorsynth.py index e252b2a..ac6669f 100644 --- a/colorsynth/_tests/test_colorsynth.py +++ b/colorsynth/_tests/test_colorsynth.py @@ -12,6 +12,12 @@ ] +XYZ = [ + np.random.uniform(size=(3,)), + np.random.uniform(size=(64, 64, 3)), +] + + @pytest.mark.parametrize(argnames="wavelength", argvalues=wavelengths) def test_d65_standard_illuminant( wavelength: u.Quantity, @@ -84,13 +90,29 @@ def test_cie_1931_tristimulus( assert result.shape[axis] == 3 -@pytest.mark.parametrize( - argnames="tristimulus", - argvalues=[ - np.random.uniform(size=(3,)), - np.random.uniform(size=(64, 64, 3)), - ], -) +@pytest.mark.parametrize("XYZ", XYZ) +@pytest.mark.parametrize("axis", [-1]) +def test_xyY_from_XYZ_cie( + XYZ: np.ndarray, + axis: int, +): + result = colorsynth.xyY_from_XYZ_cie(XYZ, axis=axis) + assert isinstance(result, np.ndarray) + assert result.shape[axis] == 3 + + +@pytest.mark.parametrize("xyY", XYZ) +@pytest.mark.parametrize("axis", [-1]) +def test_XYZ_from_xyY_cie( + xyY: np.ndarray, + axis: int, +): + result = colorsynth.XYZ_from_xyY_cie(xyY, axis=axis) + assert isinstance(result, np.ndarray) + assert result.shape[axis] == 3 + + +@pytest.mark.parametrize("tristimulus", XYZ,) @pytest.mark.parametrize(argnames="axis", argvalues=[-1]) def test_srgb( tristimulus: np.ndarray,