Coverage for io/luts/tests/test_operator.py: 90%

1"""Define the unit tests for the :mod:`colour.io.luts.operator` module."""

2

3 from __future__ import annotations

4

5 import textwrap

6

7 import numpy as np

8

9 from colour.constants import TOLERANCE_ABSOLUTE_TESTS

10 from colour.io.luts import AbstractLUTSequenceOperator, LUTOperatorMatrix

11 from colour.utilities import tstack, zeros

12

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"

19

20 __all__ = [

21 "AbstractTestLUTSequenceOperator",

22 "TestLUTOperatorMatrix",

23]

24

25

26 class AbstractTestLUTSequenceOperator:

27 """

28 Define :class:`colour.io.luts.operator.AbstractLUTSequenceOperator` class

29 unit tests methods.

30 """

31

32 def test_required_attributes(self) -> None:

33 """Test the presence of required attributes."""

34

35 required_attributes = ("name", "comments")

36

37 for method in required_attributes:

38 assert method in dir(AbstractLUTSequenceOperator)

39

40 def test_required_methods(self) -> None:

41 """Test the presence of required methods."""

42

43 required_methods = ("apply",)

44

45 for method in required_methods:

46 assert method in dir(AbstractLUTSequenceOperator)

47

48

49 class TestLUTOperatorMatrix:

50 """

51 Define :class:`colour.io.luts.operator.LUTOperatorMatrix` class unit tests

52 methods.

53 """

54

55 def setup_method(self) -> None:

56 """Initialise the common tests attributes."""

57

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 )

64

65 def test_required_attributes(self) -> None:

66 """Test the presence of required attributes."""

67

68 required_attributes = ("matrix", "offset")

69

70 for method in required_attributes:

71 assert method in dir(LUTOperatorMatrix)

72

73 def test_required_methods(self) -> None:

74 """Test the presence of required methods."""

75

76 required_methods = ("__str__", "__repr__", "__eq__", "__ne__", "apply")

77

78 for method in required_methods:

79 assert method in dir(LUTOperatorMatrix)

80

81 def test_matrix(self) -> None:

82 """

83 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.matrix`

84 property.

85 """

86

87 M = np.identity(3)

88

89 lut_operator_matrix = LUTOperatorMatrix(M)

90 np.testing.assert_array_equal(lut_operator_matrix.matrix, np.identity(4))

91

92 def test_offset(self) -> None:

93 """

94 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.offset`

95 property.

96 """

97

98 offset = zeros(3)

99

100 lut_operator_matrix = LUTOperatorMatrix(np.identity(3), offset)

101 np.testing.assert_array_equal(lut_operator_matrix.offset, zeros(4))

102

103 def test__str__(self) -> None:

104 """

105 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__str__`

106 method.

107 """

108

109 assert (

110 str(self._lut_operator_matrix)

111 == (

112 textwrap.dedent(

113 """

114 LUTOperatorMatrix - Nemo Matrix

115 -------------------------------

116

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. ]

122

123 A first comment.

124 A second comment."""

125 )[1:]

126 )

127 )

128

129 def test__repr__(self) -> None:

130 """

131 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__repr__`

132 method.

133 """

134

135 assert repr(self._lut_operator_matrix) == (

136 textwrap.dedent(

137 """

138 LUTOperatorMatrix([[ 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 )

147

148 def test__eq__(self) -> None:

149 """Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__eq__` method."""

150

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 )

155

156 assert self._lut_operator_matrix == matrix

157

158 def test__neq__(self) -> None:

159 """

160 Test :class:`colour.io.luts.operator.LUTOperatorMatrix.__neq__`

161 method.

162 """

163

164 matrix = LUTOperatorMatrix(np.reshape(np.linspace(0, 1, 16), (4, 4)) * 0.75)

165

166 assert self._lut_operator_matrix != matrix

167

168 def test_apply(self) -> None:

169 """Test :class:`colour.io.luts.operator.LUTOperatorMatrix.apply` method."""

170

171 samples = np.linspace(0, 1, 5)

172 RGB = tstack([samples, samples, samples])

173

174 np.testing.assert_array_equal(LUTOperatorMatrix().apply(RGB), RGB)

175

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 )

189

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 )

203

204 RGBA = tstack([samples, samples, samples, samples])

205

206 np.testing.assert_array_equal(LUTOperatorMatrix().apply(RGBA), RGBA)

207

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 )

221

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 )