Coverage for colour/io/luts/tests/test_operator.py: 90%
61 statements
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 23:01 +1300
« prev ^ index » next coverage.py v7.11.0, created at 2025-11-16 23:01 +1300
1"""Define the unit tests for the :mod:`colour.io.luts.operator` module."""
3from __future__ import annotations
5import textwrap
7import numpy as np
9from colour.constants import TOLERANCE_ABSOLUTE_TESTS
10from colour.io.luts import AbstractLUTSequenceOperator, LUTOperatorMatrix
11from colour.utilities import tstack, zeros
13__author__ = "Colour Developers"
14__copyright__ = "Copyright 2013 Colour Developers"
15__license__ = "BSD-3-Clause - https://opensource.org/licenses/BSD-3-Clause"
16__maintainer__ = "Colour Developers"
17__email__ = "colour-developers@colour-science.org"
18__status__ = "Production"
20__all__ = [
21 "AbstractTestLUTSequenceOperator",
22 "TestLUTOperatorMatrix",
23]
26class AbstractTestLUTSequenceOperator:
27 """
28 Define :class:`colour.io.luts.operator.AbstractLUTSequenceOperator` class
29 unit tests methods.
30 """
32 def test_required_attributes(self) -> None:
33 """Test the presence of required attributes."""
35 required_attributes = ("name", "comments")
37 for method in required_attributes:
38 assert method in dir(AbstractLUTSequenceOperator)
40 def test_required_methods(self) -> None:
41 """Test the presence of required methods."""
43 required_methods = ("apply",)
45 for method in required_methods:
46 assert method in dir(AbstractLUTSequenceOperator)
49class TestLUTOperatorMatrix:
50 """
51 Define :class:`colour.io.luts.operator.LUTOperatorMatrix` class unit tests
52 methods.
53 """
55 def setup_method(self) -> None:
56 """Initialise the common tests attributes."""
58 self._lut_operator_matrix = LUTOperatorMatrix(
59 np.reshape(np.linspace(0, 1, 16), (4, 4)),
60 offset=np.array([0.25, 0.5, 0.75, 1.0]),
61 name="Nemo Matrix",
62 comments=["A first comment.", "A second comment."],
63 )
65 def test_required_attributes(self) -> None:
66 """Test the presence of required attributes."""
68 required_attributes = ("matrix", "offset")
70 for method in required_attributes:
71 assert method in dir(LUTOperatorMatrix)
73 def test_required_methods(self) -> None:
74 """Test the presence of required methods."""
76 required_methods = ("__str__", "__repr__", "__eq__", "__ne__", "apply")
78 for method in required_methods:
79 assert method in dir(LUTOperatorMatrix)
81 def test_matrix(self) -> None:
82 """
83 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.matrix`
84 property.
85 """
87 M = np.identity(3)
89 lut_operator_matrix = LUTOperatorMatrix(M)
90 np.testing.assert_array_equal(lut_operator_matrix.matrix, np.identity(4))
92 def test_offset(self) -> None:
93 """
94 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.offset`
95 property.
96 """
98 offset = zeros(3)
100 lut_operator_matrix = LUTOperatorMatrix(np.identity(3), offset)
101 np.testing.assert_array_equal(lut_operator_matrix.offset, zeros(4))
103 def test__str__(self) -> None:
104 """
105 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__str__`
106 method.
107 """
109 assert (
110 str(self._lut_operator_matrix)
111 == (
112 textwrap.dedent(
113 """
114 LUTOperatorMatrix - Nemo Matrix
115 -------------------------------
117 Matrix : [[ 0. 0.06666667 0.13333333 0.2 ]
118 [ 0.26666667 0.33333333 0.4 0.46666667]
119 [ 0.53333333 0.6 0.66666667 0.73333333]
120 [ 0.8 0.86666667 0.93333333 1. ]]
121 Offset : [ 0.25 0.5 0.75 1. ]
123 A first comment.
124 A second comment."""
125 )[1:]
126 )
127 )
129 def test__repr__(self) -> None:
130 """
131 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__repr__`
132 method.
133 """
135 assert repr(self._lut_operator_matrix) == (
136 textwrap.dedent(
137 """
138LUTOperatorMatrix([[ 0. , 0.06666667, 0.13333333, 0.2 ],
139 [ 0.26666667, 0.33333333, 0.4 , 0.46666667],
140 [ 0.53333333, 0.6 , 0.66666667, 0.73333333],
141 [ 0.8 , 0.86666667, 0.93333333, 1. ]],
142 [ 0.25, 0.5 , 0.75, 1. ],
143 name='Nemo Matrix',
144 comments=['A first comment.', 'A second comment.'])"""[1:]
145 )
146 )
148 def test__eq__(self) -> None:
149 """Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__eq__` method."""
151 matrix = LUTOperatorMatrix(
152 np.reshape(np.linspace(0, 1, 16), (4, 4)),
153 np.array([0.25, 0.5, 0.75, 1.0]),
154 )
156 assert self._lut_operator_matrix == matrix
158 def test__neq__(self) -> None:
159 """
160 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__neq__`
161 method.
162 """
164 matrix = LUTOperatorMatrix(np.reshape(np.linspace(0, 1, 16), (4, 4)) * 0.75)
166 assert self._lut_operator_matrix != matrix
168 def test_apply(self) -> None:
169 """Test :class:`colour.io.luts.operator.LUTOperatorMatrix.apply` method."""
171 samples = np.linspace(0, 1, 5)
172 RGB = tstack([samples, samples, samples])
174 np.testing.assert_array_equal(LUTOperatorMatrix().apply(RGB), RGB)
176 np.testing.assert_allclose(
177 self._lut_operator_matrix.apply(RGB),
178 np.array(
179 [
180 [0.25000000, 0.50000000, 0.75000000],
181 [0.30000000, 0.75000000, 1.20000000],
182 [0.35000000, 1.00000000, 1.65000000],
183 [0.40000000, 1.25000000, 2.10000000],
184 [0.45000000, 1.50000000, 2.55000000],
185 ]
186 ),
187 atol=TOLERANCE_ABSOLUTE_TESTS,
188 )
190 np.testing.assert_allclose(
191 self._lut_operator_matrix.apply(RGB, apply_offset_first=True),
192 np.array(
193 [
194 [0.13333333, 0.53333333, 0.93333333],
195 [0.18333333, 0.78333333, 1.38333333],
196 [0.23333333, 1.03333333, 1.83333333],
197 [0.28333333, 1.28333333, 2.28333333],
198 [0.33333333, 1.53333333, 2.73333333],
199 ]
200 ),
201 atol=TOLERANCE_ABSOLUTE_TESTS,
202 )
204 RGBA = tstack([samples, samples, samples, samples])
206 np.testing.assert_array_equal(LUTOperatorMatrix().apply(RGBA), RGBA)
208 np.testing.assert_allclose(
209 self._lut_operator_matrix.apply(RGBA),
210 np.array(
211 [
212 [0.25000000, 0.50000000, 0.75000000, 1.00000000],
213 [0.35000000, 0.86666667, 1.38333333, 1.90000000],
214 [0.45000000, 1.23333333, 2.01666667, 2.80000000],
215 [0.55000000, 1.60000000, 2.65000000, 3.70000000],
216 [0.65000000, 1.96666667, 3.28333333, 4.60000000],
217 ]
218 ),
219 atol=TOLERANCE_ABSOLUTE_TESTS,
220 )
222 np.testing.assert_allclose(
223 self._lut_operator_matrix.apply(RGBA, apply_offset_first=True),
224 np.array(
225 [
226 [0.33333333, 1.00000000, 1.66666667, 2.33333333],
227 [0.43333333, 1.36666667, 2.30000000, 3.23333333],
228 [0.53333333, 1.73333333, 2.93333333, 4.13333333],
229 [0.63333333, 2.10000000, 3.56666667, 5.03333333],
230 [0.73333333, 2.46666667, 4.20000000, 5.93333333],
231 ],
232 ),
233 atol=TOLERANCE_ABSOLUTE_TESTS,
234 )