Skip to content

Commit f7204c7

Browse files
committed
Add rgb_colorspace equivalence and tests
1 parent 4fe8f4c commit f7204c7

File tree

4 files changed

+162
-0
lines changed

4 files changed

+162
-0
lines changed

colour/models/rgb/rgb_colourspace.py

Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626
from __future__ import annotations
2727

2828
from copy import deepcopy
29+
from functools import partial
2930

3031
import numpy as np
3132

@@ -277,6 +278,63 @@ def __init__(
277278
self._use_derived_matrix_XYZ_to_RGB: bool = False
278279
self.use_derived_matrix_XYZ_to_RGB = use_derived_matrix_XYZ_to_RGB
279280

281+
def __eq__(self, other: object) -> bool:
282+
"""Return weather or not two RGB spaces are equivalent and would produce
283+
the same results with XYZ_to_RGB and visa-versa. Can detect and compare
284+
instances of `partial` for the cctf properties.
285+
286+
Parameters
287+
----------
288+
other : object
289+
290+
Returns
291+
-------
292+
bool
293+
"""
294+
if not isinstance(other, RGB_Colourspace):
295+
return False
296+
297+
cctf_decoding_eq: bool
298+
if isinstance(self.cctf_decoding, partial) and isinstance(
299+
other.cctf_decoding, partial
300+
):
301+
cctf_decoding_eq = np.all(
302+
(
303+
self.cctf_decoding.func == other.cctf_decoding.func,
304+
np.all(self.cctf_decoding.args == other.cctf_decoding.args),
305+
np.all(self.cctf_decoding.keywords == other.cctf_decoding.keywords),
306+
)
307+
)
308+
else:
309+
cctf_decoding_eq = self.cctf_decoding == other.cctf_decoding
310+
311+
cctf_encoding_eq: bool
312+
if isinstance(self.cctf_encoding, partial) and isinstance(
313+
other.cctf_encoding, partial
314+
):
315+
cctf_encoding_eq = np.all(
316+
(
317+
self.cctf_encoding.func == other.cctf_encoding.func,
318+
np.all(self.cctf_encoding.args == other.cctf_encoding.args),
319+
np.all(self.cctf_encoding.keywords == other.cctf_encoding.keywords),
320+
)
321+
)
322+
else:
323+
cctf_encoding_eq = self.cctf_encoding == other.cctf_encoding
324+
325+
return np.all(
326+
(
327+
self.name == other.name,
328+
np.all(self.primaries == other.primaries),
329+
np.all(self.whitepoint == self.whitepoint),
330+
self.whitepoint_name == self.whitepoint_name,
331+
np.all(self.matrix_RGB_to_XYZ == other.matrix_RGB_to_XYZ),
332+
np.all(self.matrix_XYZ_to_RGB == other.matrix_XYZ_to_RGB),
333+
cctf_decoding_eq,
334+
cctf_encoding_eq,
335+
)
336+
)
337+
280338
@property
281339
def name(self) -> str:
282340
"""

colour/models/rgb/tests/test_rgb_colourspace.py

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,7 @@
44

55
import re
66
import textwrap
7+
from functools import partial
78
from itertools import product
89

910
import numpy as np
@@ -24,6 +25,7 @@
2425
matrix_RGB_to_RGB,
2526
normalised_primary_matrix,
2627
)
28+
from colour.models.rgb.transfer_functions.gamma import gamma_function
2729
from colour.utilities import domain_range_scale, ignore_numpy_errors
2830

2931
__author__ = "Colour Developers"
@@ -66,6 +68,77 @@ def setup_method(self):
6668
linear_function,
6769
)
6870

71+
class TestRGBSpace__eq__:
72+
def setup_method(self):
73+
pass
74+
# Some pytest possible issue requires this since the encapsulating
75+
# class has a setup_method.
76+
77+
@staticmethod
78+
def get_two_rgb_spaces():
79+
p = np.array([0.73470, 0.26530, 0.00000, 1.00000, 0.00010, -0.07700])
80+
whitepoint = np.array([0.32168, 0.33767])
81+
matrix_RGB_to_XYZ = np.identity(3)
82+
matrix_XYZ_to_RGB = np.identity(3)
83+
84+
s1 = RGB_Colourspace(
85+
"RGB Colourspace",
86+
p,
87+
whitepoint,
88+
"ACES",
89+
matrix_RGB_to_XYZ,
90+
matrix_XYZ_to_RGB,
91+
linear_function,
92+
linear_function,
93+
)
94+
95+
s2 = RGB_Colourspace(
96+
"RGB Colourspace",
97+
p,
98+
whitepoint,
99+
"ACES",
100+
matrix_RGB_to_XYZ,
101+
matrix_XYZ_to_RGB,
102+
linear_function,
103+
linear_function,
104+
)
105+
106+
return s1, s2
107+
108+
def test_simple_eq(self):
109+
s1, s2 = self.get_two_rgb_spaces()
110+
111+
assert s1 is not s2
112+
assert s1 == s2
113+
114+
# Even if one space uses derived, if they return the same matrix
115+
# they are equivalent
116+
s2.use_derived_matrix_RGB_to_XYZ = True
117+
s1.matrix_RGB_to_XYZ = s2.matrix_RGB_to_XYZ
118+
s1.matrix_XYZ_to_RGB = s2.matrix_XYZ_to_RGB
119+
120+
assert s1 == s2
121+
122+
def test_partial_cctf(self):
123+
s1, s2 = self.get_two_rgb_spaces()
124+
125+
s1.cctf_decoding = partial(gamma_function, exponent=2)
126+
s1.cctf_encoding = partial(gamma_function, exponent=1 / 2)
127+
assert s1 != s2
128+
129+
s2.cctf_encoding = partial(gamma_function, exponent=1 / 2)
130+
assert s1 != s2
131+
132+
s2.cctf_decoding = partial(gamma_function, exponent=1.5)
133+
assert s1 != s2
134+
135+
s2.cctf_decoding = partial(gamma_function, 2)
136+
# Should be equal, but because one partial uses kwargs it is an error
137+
assert s1 != s2
138+
139+
s2.cctf_decoding = partial(gamma_function, exponent=2)
140+
assert s1 == s2
141+
69142
def test_required_attributes(self):
70143
"""Test the presence of required attributes."""
71144

@@ -92,6 +165,7 @@ def test_required_methods(self):
92165
"__init__",
93166
"__str__",
94167
"__repr__",
168+
"__eq__",
95169
"use_derived_transformation_matrices",
96170
"chromatically_adapt",
97171
"copy",

colour/models/rgb/transfer_functions/gamma.py

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,26 @@ def __call__(self, a: ArrayLike):
101101
negative_number_handling=self.negative_number_handling,
102102
)
103103

104+
def __eq__(self, other: object) -> bool:
105+
"""Return if two gamma functions have the same parameters and therefore
106+
produce the same results
107+
108+
Parameters
109+
----------
110+
other : object
111+
112+
Returns
113+
-------
114+
bool
115+
"""
116+
if not isinstance(other, GammaFunction):
117+
return False
118+
119+
return (
120+
self.exponent == other.exponent
121+
and self.negative_number_handling == other.negative_number_handling
122+
)
123+
104124

105125
def gamma_function(
106126
a: ArrayLike,

colour/models/rgb/transfer_functions/tests/test_gamma.py

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -204,6 +204,16 @@ def test_n_dimensional_gamma_function(self):
204204
GammaFunction(2.2, "Clamp")(a), a_p, atol=TOLERANCE_ABSOLUTE_TESTS
205205
)
206206

207+
def test__eq__(self):
208+
g1 = GammaFunction(exponent=3, negative_number_handling="Clip")
209+
g2 = GammaFunction(exponent=3, negative_number_handling="Clip")
210+
g3 = GammaFunction(exponent=4, negative_number_handling="Clip")
211+
g4 = GammaFunction(exponent=3, negative_number_handling="Mirror")
212+
213+
assert g1 == g2
214+
assert g1 != g3
215+
assert g1 != g4
216+
207217
@ignore_numpy_errors
208218
def test_nan_gamma_function(self):
209219
"""

0 commit comments

Comments
 (0)